04 | 在OAuth 2.0中,如何使用JWT结构化令牌?
JWT 结构化令牌
JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息
JWT 这种结构化体可以分为 HEADER(头部)、PAYLOAD(数据体)和 SIGNATURE(签名)三部分。是被句点符号分割的三段内容
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
eyJzdWIiOiJVU0VSVEVTVCIsImV4cCI6MTU4NDEwNTc5MDcwMywiaWF0IjoxNTg0MTA1OTQ4MzcyfQ.
1HbleXbvJ_2SW8ry30cXOBGR9FW4oSWBd3PWaWKsEXE
注意:JWT 内部没有换行,这里只是为了展示方便,才将其用三行来表示。
也可以在这个网站解析。jwt.io/
令牌内检
受保护资源来调用授权服务提供的检验令牌的服务,我们把这种校验令牌的方式称为令牌内检。
JWT 是如何被使用的?
授权服务“扔出”一个令牌,受保护资源服务“接住”这个令牌,然后自己开始解析令牌本身所包含的信息就可以了,而不需要再去查询数据库或者请求 RPC 服务。
JJWT 是目前 Java 开源的、比较方便的 JWT 工具,封装了 Base64URL 编码和对称 HMAC、非对称 RSA 的一系列签名算法。
demo
String sharedTokenSecret="hellooauthhellooauthhellooauthhellooauth";//密钥
Key key = new SecretKeySpec(sharedTokenSecret.getBytes(),
SignatureAlgorithm.HS256.getJcaName());
//生成JWT令牌
String jwts=
Jwts.builder().setHeaderParams(headerMap).setClaims(payloadMap).signWith(key,SignatureAlgorithm.HS256).compact()
//解析JWT令牌
Jws<Claims> claimsJws =Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(jwts);
JwsHeader header = claimsJws.getHeader();
Claims body = claimsJws.getBody();
为什么要使用 JWT 令牌?
- JWT 的核心思想,就是用计算代替存储,有些 “时间换空间” 的 “味道”,减少了查询”数据库“这样的远程操作
- 是加密。因为 JWT 令牌内部已经包含了重要的信息,所以在整个传输过程中都必须被要求是密文传输的,这样被强制要求了加密也就保障了传输过程中的安全性。
- 使用 JWT 格式的令牌,有助于增强系统的可用性和可伸缩性。
JWT的缺点:
给小兔软件授权了,但是用户就修改密码了,或者突然取消给小兔的授权,但是服务的不会存储JWT,所以在令牌的有效期内,是可以横行无止的。也不能违法JWT的初衷,把JWT 令牌存储到远程的分布式内存数据库中。
做法:
- 将每次生成 JWT 令牌时的秘钥粒度缩小到用户级别,也就是一个用户一个秘钥。这样,当用户取消授权或者修改密码后,就可以让这个密钥一起修改。
- 在不提供用户主动取消授权的环境里面,如果只考虑到修改密码的情况,那么我们就可以把用户密码作为 JWT 的密钥。
令牌的生命周期
令牌失效情况:
- 令牌的自然过期过程,这也是最常见的情况
- 访问令牌失效之后可以使用刷新令牌请求新的访问令牌来代替失效的访问令牌,以提升用户使用第三方软件的体验。
- 就是让第三方软件比如小兔,主动发起令牌失效的请求,然后授权服务收到请求之后让令牌立即失效。
总结
- 结构化可以组织用户的授权信息,信息化就是令牌本身包含了授权信息。
- 令牌在 OAuth 2.0 系统中对于第三方软件都是不透明的。需要关心令牌的,是授权服务和受保护资源服务。
- 需要注意 JWT 令牌的失效问题。方法一种是建立一个秘钥管理系统,将生成秘钥的粒度缩小到用户级别,另外一种是直接将用户密码当作密钥。