最近我一个朋友换到了新的公司,接手了一个不算太旧的项目,大概三四年吧。
然后他跟我说,他们的token是自生成的,是一串毫无意义的uuid。
然后业务用户的信息就需要通过这串毫无意义的uuid去数据库查询对应的user_id,再通过user_id查到该用户的信息
真是一串冗长的废话操作不说,还浪费了性能,真是把博主给看笑了。
同时博主也很疑惑,都 2024 年了,就算是三四年的项目,也才 2020 年。竟然还有人不知道 jwt 的存在吗
jwtjwt全称是json web token,它是一个开放标准
(RFC 7519)
,它定义了一种紧凑且自包含的方式,使用JSON对象在各方之间安全地传输信息。此信息可以被验证和信任,因为它是数字签名的。jwt 可以使用密钥(通过HMAC算法)进行签名,或者使用公钥/私钥对,采用RSA或ECDSA算法进行签名。
尽管jwt可以被加密以在各方之间提供保密性,我们将重点关注签名令牌。签名令牌可以验证其中包含的声明的完整性,而加密令牌则将这些声明隐藏起来,不让其他方看到。当使用公钥/私钥对对令牌进行签名时,签名还证实了只有持有私钥的一方才是签名者。
jwt 的使用场景授权 jwt 最常见的使用场景是用户身份验证。一旦用户登录成功,服务器会生成一个包含用户信息的jwt,并将其返回给客户端。在后续的请求中,客户端只需携带这个jwt,服务器就可以通过验证jwt的有效性来确认用户的身份,并授权其访问相应的资源。这种方式避免了频繁查询数据库,提高了应用的性能。
SSO sso即是单点登录,jwt在单点登录场景中也非常有用。单点登录允许用户在一个应用系统中登录后,无需再次登录即可访问其他相关应用。通过使用jwt,可以将用户的登录状态信息编码在token中,并在多个应用之间共享。这样,用户只需在一次登录后,就可以无缝地切换到其他应用,提高了用户体验。
无状态认证 对于RESTful API来说,jwt是实现无状态认证的一种理想方式。无状态认证意味着服务器不保存任何会话信息,每次请求都需要携带足够的认证信息。通过使用jwt,客户端可以在每个请求中附带token,服务器通过验证token的有效性来确认客户端的身份,从而实现了无状态认证。
jwt由三部分组成,并用.相连接,三部分分别为
Header -- (头部)Payload -- (载荷)Signature -- (签名)所以基本上常见的jwt都是 xxxxxxx.yyyyyyy.zzzzzzz
Header标头通常由两部分组成:令牌的类型和使用的签名算法
这个json是使用Base64 Url编码的。
Payload令牌的第二部分是有效载荷,包含声明。声明是关于实体(通常是用户信息)和附加数据的声明。有三种类型:注册,公共和私有声明。
Registered claims 这是一组预定义的声明,不是强制性的,推荐使用。提供一组有用的、可互操作的声明。比如:iss/exp/sub/aud等。Public claims 这些可以由使用jwt的人随意定义。但是为了避免冲突,它们应该在IANA JSON Web令牌注册表中定义。Private claims 这些自定义声明是为了在各方之间共享信息而创建的,既不是注册的也不是公开的声明。jwt的有效载荷或头部元素中,除非它被加密。签名部分就是通过代码来实现了,但是首先要获取正确的算法也就是header中声明的
签名用于验证消息在发送过程中没有被沿着更改。并且,在使用私钥签名的令牌的情况下,它还可以验证jwt的发送者是否是它所说的那个人。
输出的是由点分隔Base64-URL字符串,可以在HTML和HTTP环境中轻松传递。同时,与基于XML的标准(如SAML)相比更加紧凑。
下面显示了一个jwt,它具有头部和有效负载编码,并且使用加密签名。
可以尝试用
在线jwt编译器
来解码、验证和生成jwt
在身份验证中,当用户成功登录后,将返回JSON Web Token。由于令牌是凭证,因此必须非常小心,防止出现安全问题。
由于缺乏浏览器安全性,您还不应将敏感会话数据存储在浏览器中。
每当用户想要访问受保护的路由或资源时,用户发送JWT,通常在使用Bearer模式的Authorization头中设置。标题的内容应该如下所示:
在某些情况下,可以是一种无状态的授权机制。服务器的protected routes将检查Authorization头中是否存在有效的jwt。如果存在,则允许用户访问受保护的资源。
请注意,如果您通过HTTP协议的标头发送jwt令牌,则应尝试防止它们太大。有些服务器不接受超过8K的头文件。如果您试图在jwt令牌中嵌入太多信息,例如包含所有用户的权限,则可能需要替代解决方案,例如:
Auth 0 Fine-Grained Authorization
如果令牌在Authorization报头中发送,跨域资源共享将不会成为问题,因为它不使用Cookie。
下图显示了如何获取jwt并将其用于访问api或资源:
请注意,使用签名令牌时,令牌中包含的所有信息都会暴露给用户或其他方。这意味着您不应该将机密信息放入令牌中。
json没有XML那么冗长。所以,在编码时,它的大小也更小。这使得jwt比SAML更紧凑。
安全方面,SWT只能通过使用HMAC算法进行对称签名。但是,jwt和SAML令牌可以使用X.509证书形式的公钥/私钥对进行签名。与json签名的简单性相比,使用XML数字签名而不引入模糊的安全漏洞是非常困难的。
json解析器在大多数编程语言中很常见,因为它们直接映射到对象。相反,XML没有自然的文档到对象的映射。
{
"alg": "HS256",
"typ": "JWT"
}
{
"sub": "admin",
"name": "ctexthuang",
"admin": true
}
public static function encode(
array $payload,
$key,
string $alg,
string $keyId = null,
array $head = null
): string {
$header = ['typ' => 'JWT'];
if (isset($head) && \is_array($head)) {
$header = \array_merge($header, $head);
}
$header['alg'] = $alg;
if ($keyId !== null) {
$header['kid'] = $keyId;
}
$segments = [];
$segments[] = static::urlsafeB64Encode((string) static::jsonEncode($header));
$segments[] = static::urlsafeB64Encode((string) static::jsonEncode($payload));
$signing_input = \implode('.', $segments);
$signature = static::sign($signing_input, $key, $alg);
$segments[] = static::urlsafeB64Encode($signature);
return \implode('.', $segments);
}
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE3MzA4NjkzNjIsIm5iZiI6MTczMDg2OTM2MiwiZXhwIjoxNzMwODcyOTYyLCJkYXRhIjp7ImlkIjoxLCJyb2xlIjoxfX0.yG7VzTj-6N86h8f0VFIO2MESCmJ3LA9DWcV51XRA0Kc
Authorization: Bearer <jwt>