一.作用
1.授权: 这是使用JWT的最常见方案。一旦用户登录,每个后续请求将包括JWT,从而允许用户访问该令牌允许的路由,服务和资源。单一登录是当今广泛使用JWT的一项功能,因为它的开销很小并且可以在不同的域中轻松使用
2.支持跨域访问:Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.
3.去耦:不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可
二.组成
一个JWT实际上就是一个字符串,它由三部分组成:头部、载荷与签名。格式为: XXXX.XXXX.XXXX
2.1头部(header)用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等,头部可以被表示成一个JSON对象
{"typ":"JWT","alg":"HS256"}
使用Base64编码把JSON对象转化成由符号组成的字符串
Base64编码是一种基于64个字符(52个大小字母+10个位数数字+加号+除号)表示二进制数据的表示方法。
由于2的6次方等于64,所以用6比特表示一个单元,三个字节有24个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。空余的高位用0填充
2.2载荷(payload):存放有效信息的地方
标准中注册的声明(建议但不强制使用)
iss: jwt签发者 sub: jwt所面向的用户 aud: 接收jwt的一方 exp: jwt的过期时间,这个过期时间必须要大于签发时间 nbf: 定义在什么时间之前,该jwt都是不可用的. iat: jwt的签发时间 jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息。但不建议添加敏感信息,因为该部分在客户端可解密
2.3 签证(signature)
该部分由header+payload+密钥(自定义)通过header中声明的加密方式进行加密后生成的签名组成
三.JJWT
它是为了更友好在JVM上使用JWT,是基于JWT, JWS, JWE, JWK框架的java实现。
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
//私钥 / 生成签名的时候使用的秘钥secret,一般可以从本地配置文件中读取,切记这个秘钥不能外露,只在服务端使用,在任何场景都不应该流露出去
private static String tokenSignKey = "123456";
public static String createToken(Long userId, String userName) {
String token = Jwts.builder()
//设置签名(由自定义的密钥加密生成,前一个参数为加密密钥的算法)
.signWith(SignatureAlgorithm.HS512, tokenSignKey)
.compressWith(CompressionCodecs.GZIP) //设置jwt的类型
.setSubject("YYGH-USER") //设置面向的用户
//设置过期时间,参数为一个Date对象
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.claim("userId", userId) //用户相关信息的声明
.claim("userName", userName)
.compact(); //开始压缩为xxxxx.yyyyy.zzzzz 格式的jwt token
return token;
}
// 根据token 获取userId
public static Long getUserId(String token) {
if(StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Integer userId = (Integer)claims.get("userId");
return userId.longValue();
}