目录
参照:jwt三个组成部分_jwt加密算法 - 腾讯云开发者社区-腾讯云 (tencent.com)
1.JWT
在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用Json Web Token认证机制。
1.1什么是JWT
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
1.2JWT的构成
第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证。
jwt的头部
- 声明类型,这里是JWT
- 声明加密的算法 通常直接使用 HMAC SHA256 HS256
payload
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分
公共的声明 : 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.
私有的声明 : 私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
signature
JWT的第三部分是一个签证信息,这个签证信息由三部分组成:
header (base64后的)
payload (base64后的)
secret
- 标准中注册的声明
- 公共的声明
- 私有的声明
- 标准中注册的声明 (建议但不强制使用) :
- iss: jwt签发者
- sub: jwt所面向的用户
- aud: 接收jwt的一方
- exp: jwt的过期时间,这个过期时间必须要大于签发时间
- nbf: 定义在什么时间之前,该jwt都是不可用的.
- iat: jwt的签发时间
- jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
1.3JWT快速入门案例
所需依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
代码
package com.hzw.jwt;
import io.jsonwebtoken.*;
import org.junit.Test;
import java.util.Date;
import java.util.UUID;
public class JwtTest {
private long time=1000*60*60*2;
private String signature="admin"; //签名
//加密
@Test
public void jwt(){
JwtBuilder jwtBuilder = Jwts.builder();
//jwt 由header playload sign 组成
String jwtToken=jwtBuilder
//header
.setHeaderParam("typ","JWT")
.setHeaderParam("alg","HS256")
//payload 载荷
.claim("username","hzw")
.claim("role","admin")
.setSubject("admin-test")
.setExpiration(new Date(System.currentTimeMillis()+time))
.setId(UUID.randomUUID().toString())
//signature 签名
.signWith(SignatureAlgorithm.HS256,signature)
//将三部分连接起来
.compact();
System.out.println(jwtToken);
}
//解密
@Test
public void parse(){
String token ="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imh6dyIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2NzExMjAxOTEsImp0aSI6ImQxMGYwNjIwLThjM2ItNGIyMC1iYzUwLTE4YzE5OTIxNjM0MyJ9.wFQzUPi4t-5DJBxbuZksEHy2rm60ZWjl5FtMMUAEEzI";
JwtParser parser = Jwts.parser();
//
Jws<Claims> claimsJws = parser.setSigningKey(signature).parseClaimsJws(token);
//get
Claims claims = claimsJws.getBody();
Object username = claims.get("username");
System.out.println(username);
System.out.println(claims.get("role"));
System.out.println(claims.getId());
System.out.println(claims.getSubject());
System.out.println(claims.getExpiration());
}
}
2Jwt认证(微服务)
JWT是一个经过加密的,包含用户信息的且具有时效性的固定格式字符串
2.1微服务下统一权限认证
2.2应用认证
验签注解实现
@GetMapping("/xxx")
自定义注解,利用AOP做验签
@CheckJwt
public void xxx(){
/Controller代码
两个方案对比
方案一:JWT校验无感知,验签过程无侵入,
执行效率低,适用于低并发企业级应用
方案二:控制更加灵活,有一定代码侵入,代
码可以灵活控制,适用于追求性能互联网应用
3.无状态的JWT令牌如何实现续签功能?
那JWT不设置过期时间行不行?
不行,会留下”太空垃圾”,后患无穷JWT不建议设置长时有效期
续签JWT必须有退出机制(设置过期时间)
3.1不允许改变Token令牌实现续签
加入redis。超过过期时间,自动删除K。注销删除K.
为什么加入Redis后JWT中过期时间可以去掉?
因为过期时间的被放到后端Redis存储,可以灵活控制
同时在生成MD5时加入环境特征,尽量避免人为盗取
但这也意味着JWT是有状态的,但也是我思考后唯一不改变前
端JWT的续签方案了
3.2允许改变Token令牌实现续签
情况1access_token、refresh_token未过期
情况2access_token过期,refresh_token未过期
生成全新token替换原有token,实现续签
问:为什么必须要两个jwt?为什么不直接设置token一个小时过期,判断还
有10分钟过期的时候,生成新的token进行替换?
答:这两个token的职责不一样:
access token用于业务系统交互,是最核心的数据。
refresh token只用于向认证中心获取新的access token与refresh_token.
refresh token的出现本质解决了在用户超过30分钟后,access token已经失效,
此时access token被送给认证中心是无法解析的,而refresh token因为生存时
间更长,且主体内容与access_token一致,因此被送达认证中心后可以被正确解
析,进而重新生成新的access._token与refresh_token。
情况三:access_token过期,refresh_token过期
清除两个JWT,重新登录
多线程:造成重复生成JWT问题
·认证中心设计一个计时Map数据结构
·只记录过去n秒内的原始jwt刷新所生成新jwt数据
·几秒内如果发现同样的jwt在再次请求刷新,就返回相同的新jwt数据。