引言:最近看了一个开源项目,涉及了些比较陌生的东西,为了加深印象,做点小笔记;
JWT
json web token,简单来说,就是客户端与服务器进行验证的解决方案之一;另外一种就是使用session的方式;
使用原理:
当客户端第一次登陆后,服务端会返回JWT格式的令牌,包含一些用户的信息,客户端则会保存这个JWT信息至Cookie或者其他数据层框架,用于下次登陆时验证。
此时,服务端不需要去存储任何当前用户的信息。而下次请求时,客户端都需要携带次JWT信息,客户端则会去解析该信息,重新认证该用户,授权该用户;
使用方法:
项目权限认证使用的spring security框架,第一次登陆时,在相应的successHandle中添加成功处理逻辑:
- 登陆成功生成JWT:
// jwt
token = SecurityConstant.TOKEN_SPLIT + Jwts.builder()
//主题 放入用户名
.setSubject(username)
//自定义属性 放入用户拥有请求权限
.claim(SecurityConstant.AUTHORITIES, new Gson().toJson(list))
//失效时间
.setExpiration(new Date(System.currentTimeMillis() + tokenExpireTime * 60 * 1000))
//签名算法和密钥
.signWith(SignatureAlgorithm.HS512, SecurityConstant.JWT_SIGN_KEY)
.compact();
ResponseUtil.out(response, ResponseUtil.resultMap(true,200,"登录成功", token));
再次请求校验jwt:
只需要在Jwt认证的过滤器中添加该校验;
private UsernamePasswordAuthenticationToken getAuthentication(String header, HttpServletResponse response) {
// 用户名
String username = null;
// 权限
List<GrantedAuthority> authorities = new ArrayList<>();
try {
// 解析token
Claims claims = Jwts.parser()
.setSigningKey(SecurityConstant.JWT_SIGN_KEY)
.parseClaimsJws(header.replace(SecurityConstant.TOKEN_SPLIT, ""))
.getBody();
//获取用户名
username = claims.getSubject();
//获取权限
String authority = claims.get(SecurityConstant.AUTHORITIES).toString();
if(StrUtil.isNotBlank(authority)){
List<String> list = new Gson().fromJson(authority, new TypeToken<List<String>>(){}.getType());
for(String ga : list){
authorities.add(new SimpleGrantedAuthority(ga));
}
}
} catch (ExpiredJwtException e) {
ResponseUtil.out(response, ResponseUtil.resultMap(false,401,"登录已失效,请重新登录"));
} catch (Exception e){
log.error(e.toString());
ResponseUtil.out(response, ResponseUtil.resultMap(false,500,"解析token错误"));
}
比较Session
众所周知,Session方式的用户信息认证是将登陆信息存储在服务器端,redis缓存中,或者持久化;
而在分布式的系统中,就只能持久化;
另外,session方式返回给浏览器端的认证信息一般只需要一个id,而JWT是将复杂的用户信息,甚至加密加长后返给客户端,这可能让存储4k的Cookie比较难为情了;以致于前端可能需要拓展另外的方案解决认证问题;
总结:
JWT是将用户登录信息存储在客户端的一种方便拓展的认证方案,而Session则是将用户信息存储在服务器端的更安全的解决方案;