JSON Web Token (JWT)
参考资料:Introduction to JSON Web Tokens
简介
JSON Web令牌(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且独立的方法,用于在各方之间安全地将信息作为JSON对象传输。由于此信息是经过数字签名的,因此可以被验证和信任。
组成部分
JSON Web Token由三个部分组成,使用(.)分割。
- Header
- Payload
- Signature
因此JWT的格式为:xxxx.yyyy.zzzz
第一部分Header
通常包括两部分:令牌的类型(即JWT),以及使用的哈希算法(如HMAC SHA256或RSA)。
{
"alg": "HS256",
"typ": "JWT"
}
然后,这个JSON是Base64Url编码形成JWT的第一部分。
第二部分Payload
通常包括claims, claims是关于实体(通常是用户)和附加元数据的声明。
这里有三个类型的声明:
- reserved
- public
- private
Reserved claims
这些是一组预定义的声明,不是强制性的,而是建议的,以提供一组有用的,可互操作的声明。其中有些是:
- iss (issuer)
- exp (expiration time)
- sub (subject)
- aud (audience)
- 其他
PS:请注意,声明名称只有三个字符,因为JWT意味着紧凑。
Public claims
这些可以由使用JWT的人随意定义。但为避免冲突,应在
IANA JSON Web Token注册表
中定义它们,或者将其定义为包含防冲突命名空间的URI。
Private claims
这些是为共享使用它们的各方之间共享信息而创建的自定义声明。
例如
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
该payload被Base64Url编码以形成JSON Web令牌的第二部分。
第三部分Signature
创建签名部分,必须使用以下3个数据根据header中指定的算法, 并签名用于验签。
- base64编码的header
- 编码的payload
- 一个secret
例如:如果要使用HMAC SHA256算法,将以以下方式创建签名:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
最后拼接起来
输出是三个由点(.)分隔的Base64-URL字符串,可以在HTML和HTTP环境中轻松传递这些字符串,与基于XML的标准(例如SAML)相比,它更紧凑。
下面这个就是编码签名后的JWT结果字符串:
.
.
可以使用JWT Debug 工具测试签名和验签名。
如何使用JWT
获取JWT并将其用于访问API或资源:
- 客户端从授权服务器登录
- 登录成功后授权服务器下发JWT令牌返回给客户端
- 客户端使用JWT令牌访问受保护的API资源服务器
请注意,使用签名的令牌,令牌中包含的所有信息都会暴露给用户或其他方(因使用的是Base64可以反编译获得原文),即使他们无法更改其中的数据,但不应将机密信息放入令牌中,由于缺乏安全性,不应该将敏感的会话数据存储在浏览器中。
在身份验证中,当用户使用其凭据成功登录时,将返回JSON Web Token。由于令牌是凭据,因此必须格外小心以防止安全问题。通常,令牌的保留时间不应超过要求的时间。
每当用户想要访问受保护的路由或资源时,用户代理应发送JWT,通常在使用Bearer模式的Authorization header中。
header的内容应如下所示: Authorization: Bearer <token>
在某些情况下,这可以是无状态授权机制。服务器的受保护路由将在header中检查有效的JWT,如果存在,则将允许用户访问受保护的资源。如果JWT包含必要的数据,则可以减少查询数据库中某些操作的需求,尽管并非总是如此。
如果令牌是在header中发送的,则跨域资源共享(CORS)不会成为问题,因为它不使用cookie。
总结
JSON Web Token(简称JWT)使用点(.)分隔三个Base64加密部分拼接在一起的字符串。
优点
- 轻量跨语言,使用字符串传输,不同开发语言系统都能使用
- 无状态,无需消耗缓存或其他数据存储保存状态
- 可跨域
- 可承载数据传输到不同系统,减少数据库的访问
- 可设置有效时间,在网关层/入口拦截器处理判断
- 签名和承载数据不可更改
缺点
- 承载数据完全暴露
- 无状态,不能有效管理token,需要等有效时间失效
- 有效时间续期问题
扩展
现在开发的系统是生成一个token(如UUID字符串),保存在缓存中,由服务器管理,校验和存储需要一些资源,当大量请求的时候后端会有一些压力。
因此参考了JWT的特性,把token字符串改为JWT的形式,token放在缓存,token状态因业务问题还是需要保留。这样的好处是保持业务不变,利用JWT的承载数据校验有效时间和身份等判断,减少与缓存的交互压力,可以很大程度有效过滤掉无用的token请求(虽然没了JWT的无状态等特性)。
网友评论