一、JWT(单点登录)
JSON Web Token(JWT),全称是Json Web Token, 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权;它是分布式服务权限控制的标准解决方案!
二、为什么使用jwt
目前企业开发基于前后端分离,session已不能满足需求,需要使用JWT。
来看下面这张图,更加方便你理解。
三、JWT使用过程
此处对于用户密码做了SHA-256+盐加密,用于与shiro权限管理结合做铺垫。
1)前端通过表单将用户名和密码发送到后端接口。
2)后端核对用户名和密码后,将用户的id及其他非敏感信息作为JWT Payload,将其与头部分别进行base64编码后签名,生成JWT
public static String createJWT(User user) {
logger.debug("-------------------生成token-----------------------");
//加密算法
SignatureAlgorithm hs256 = SignatureAlgorithm.HS256;
//当前日期
long currentTimeMillis = System.currentTimeMillis();
Date date = new Date(currentTimeMillis);
//获取私钥
SecretKey secretKey=getKey();
//秘密,用于储存用户信息
HashMap<String, Object> claims = new HashMap<>();
claims.put(user.getUserName(), user.getUserName());
claims.put(user.getPassword(), user.getPassword());
//创建JET的构造器,指定加密算法,生成token
JwtBuilder builder = Jwts.builder()
//唯一标识
.setId(user.getUuid())
//签发者
.setIssuer(user.getUserName())
.setSubject(user.getUserName())
//生效时间
.setIssuedAt(date)
//设定私钥和算法
.signWith(hs256, secretKey)
//Claim储存用户账户密码
.addClaims(claims)
//唯一标识
.setAudience(user.getUuid());
//设置有效时间
if (currentTimeMillis >= 0) {
long expMillis=currentTimeMillis + 60*1000*15;
Date newDate = new Date(expMillis);
builder.setExpiration(newDate);
}
return builder.compact();
}
3)后端将JWT字符串作为登录成功的结果返回给前端,前端可以将JWT存到localStorage或者sessionStorage中,退出登录时,前端删除保存的JWT信息即可。
4)前端每次在请求时,将JWT放到header中的Authorization,但我边通过session+redis完成token储存
request.getSession().setAttribute("uuid", newUsers.getUuid());
//session声明周期
request.getSession().setMaxInactiveInterval(24*60*60);
//存入redis
redisUtil.save(newUsers.getUuid(), token);
redisUtil.setSaveTime(newUsers.getUuid(), 15*60);
5)每次请求接口,后端验证JWT的有效性,时效性,同时刷新token
//用户存在验证token(核实)
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(JWTUtil.JWT_SECERT)).build();
try {
//使用生成token配置选项对给定令牌执行验证。
DecodedJWT verify = jwtVerifier.verify(token);
if (!verify.getToken().equals(token)) {
throw new MyException(ErrorCode.USER_EXIST, "token验证失败,请重新登录");
}
//刷新token
String newToken = JWTUtil.createJWT(newUser);
if (!ObjectUtils.isEmpty(newToken)) {
redisUtil.save(uuid, newToken);
redisUtil.setSaveTime(uuid, 15*60);
}
} catch (Exception e) {
throw new MyException(ErrorCode.USER_EXIST, "token验证失败,请重新登录");
}
6)验证通过后,进行其他逻辑操作。
四、测试数据结果分析
JWT的token包含三部分数据:
Header:头部,通常头部有两部分信息:
声明类型type,这里是JWT(type=jwt)
加密算法,这里采用SHA-256+加盐加密
我们会对头部进行base64加密(可解密),得到第一部分数据
Payload:载荷,就是有效数据,一般包含下面信息:
用户身份信息-userid,username(注意,这里因为采用base64加密,可解密,因此不要存放敏感信息)
注册声明:如token的签发时间,过期时间,签发人等
这部分也会采用base64加密,得到第二部分数据
Signature:base64加密,签名,是整个数据的认证信息。一般根据前两步的数据,再加上服务的的密钥(secret,盐)(不要泄漏,最好周期性更换),通过加密算法生成。用于验证整个数据完整和安全可靠性
参考文献:JWT认证原理及使用