JWT
1、Session 存放服务器端— Session ID
2、Token + Redis
Session 缺点集群无法共享 — redis 中
Token 类似于 Session ID
Token 依赖于 Redis 真实 token 存放 value 值
使用 Token 缺点:每次都需要根据 token查询真实的内容,对服务器端压力就非常大。
jwt 先学习 json、token (加密算法 对称非对称加密算法)
Jwt 底层组成部分:
1、Header(头) 作用:记录令牌类型。签名算法等
2、Payload(有效载荷) 作用:携带一些用户信息
3、Signature(签名) 作用:防止 Token 被篡改。确保安全性
1、头部
header
- 声明类型,这里是jwt
- 声明加密的算法 通常直接使用 HMAC SHA256
{
'typ': 'JWT',
'alg': 'HS256'
}
然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分.
在header 描述 jwt 的 Payload 加密方式
2、Payload 装载的数据
- 标准中注册的声明
- 公共的声明
- 私有的声明
标准中注册的声明 (建议但不强制使用) :
- iss:jwt签发者
- sub:jwt所面向的用户
- aud:接收jwt的一方
- exp:jwt的过期时间,这个过期时间必须要大于签发时间
- nbf:定义在什么时间之前,该jwt都是不可用的.
- iat:jwt的签发时间
- jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
公共的声明 :
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.
私有的声明 :
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
Payload 就是 jwt 存放的数据内容
{
"userId":"1234"
"userName":"liujianyu"
"过期时间。。。。"
}
注意在 Pyload 中不能够存放敏感数据-(手机号、密码。。。。)
然后将其进行base64加密,得到Jwt的第二部分。
Token 对应存放在 Redis 或者数据库中的数据
3、验证签名
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
- header (base64后的)
- payload (base64后的)
- secret
这个部分需要 base64 加密后的 header 和 base64 加密后的 payload 使用.
连接组成的字符串,然后通过header中声明的加密方式进行加盐secret
组合加密,然后就构成了jwt的第三部分。
Jwt与token最大的区别:
- token依赖于Redis 查询数据信息,token存放value数据比较安全的。
- Jwt 不需要依赖于服务器端,将数据信息内容直接存放在客户端(浏览器)
Jwt payload 的数据是无法被篡改的
JWT优缺点
优点:
1、无需在服务器存放用户的数据,减轻服务器端压力
2、轻量级、json风格比较简单
3、跨语言
缺点:
jwt 一旦生成后期无法修改
1、无法更新 jwt 有效期
2、无法销毁一个 jwt
导入依赖
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- 这三个依赖是解决jdk版本过高问题 -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>3.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-core -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>3.0.0</version>
</dependency>
创建 Token
private static String signature = "admin";
private static long time = 1000*60*60*24; //单位毫秒,一天
JwtBuilder jwtBuilder = Jwts.builder();
String jwtToken = jwtBuilder
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
//Payload
.claim("role", "admin")
.claim("userName", "liujian")
.setSubject("admin-test")//设置主题
.setExpiration(new Date(System.currentTimeMillis() + time))
.setId(UUID.randomUUID().toString())
//signature
.signWith(SignatureAlgorithm.HS256, signature)
.compact();//拼接
解析 token
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiYWRtaW4iLCJ1c2VyTmFtZSI6ImxpdWppYW4iLCJzdWIiOiJhZG1pbi10ZXN0IiwiZXhwIjoxNjI0MTYzMDIxLCJqdGkiOiJlNWNiZjAwNy01MDYzLTQ3YzktOTk1OC03NTA0YTAzYTE3NmQifQ.lzi0a5vMRUKFT4AbBrZuBV44qFVQdye3WacqKXo6CW8";
JwtParser parser = Jwts.parser();
Jws<Claims> claimsJws = parser.setSigningKey(signature).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
System.out.println(claims.get("userName"));
System.out.println(claims.get("role"));
System.out.println(claims.getId());
System.out.println(claims.getSubject());
System.out.println(claims.getExpiration());
System.out.println(claims);
输出结果
liujian
admin
e5cbf007-5063-47c9-9958-7504a03a176d
admin-test
Sun Jun 20 12:23:41 CST 2021
{
role=admin, userName=liujian, sub=admin-test, exp=1624163021, jti=e5cbf007-5063-47c9-9958-7504a03a176d}