1.0 Session
有状态:用户请求接口 -> 从Session中读取用户信息 -> 根据当前的用户来处理业务 -> 返回
缺点:不支持分布式
2.0 Token
无状态:用户携带Token请求接口 -> 从请求中获取用户信息 -> 根据当前的用户来处理业务 -> 返回
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>4.3.0</version> </dependency>
|
public class JwtUtils { private static final String key = "abcdefghijklmn";
public static String createJwt(UserDetails user){ Algorithm algorithm = Algorithm.HMAC256(key); Calendar calendar = Calendar.getInstance(); Date now = calendar.getTime(); calendar.add(Calendar.SECOND, 3600 * 24 * 7); return JWT.create() .withClaim("name", user.getUsername()) .withClaim("authorities", user.getAuthorities().stream().map(GrantedAuthority::getAuthority).toList()) .withExpiresAt(calendar.getTime()) .withIssuedAt(now) .sign(algorithm); }
public static UserDetails resolveJwt(String token){ Algorithm algorithm = Algorithm.HMAC256(key); JWTVerifier jwtVerifier = JWT.require(algorithm).build(); try { DecodedJWT verify = jwtVerifier.verify(token); Map<String, Claim> claims = verify.getClaims(); if(new Date().after(claims.get("exp").asDate())) return null; else return User .withUsername(claims.get("name").asString()) .password("") .authorities(claims.get("authorities").asArray(String.class)) .build(); } catch (JWTVerificationException e) { return null; } } }
|
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String authorization = request.getHeader("Authorization"); if (authorization != null && authorization.startsWith("Bearer ")) { String token = authorization.substring(7); UserDetails user = JwtUtils.resolveJwt(token); if(user != null) { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } filterChain.doFilter(request, response); } }
|
.sessionManagement(conf -> { conf.sessionCreationPolicy(SessionCreationPolicy.STATELESS); })
.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
|
JWT退出登录
采用黑名单方案。一台服务器存储JWT黑名单,共享给所有微服务。
JWT.create() .withJWTId(UUID.randomUUID().toString())
|
public class JwtUtils { private static final HashSet<String> blackList = new HashSet<>(); public static boolean invalidate(String token){ Algorithm algorithm = Algorithm.HMAC256(key); JWTVerifier jwtVerifier = JWT.require(algorithm).build(); try { DecodedJWT verify = jwtVerifier.verify(token); Map<String, Claim> claims = verify.getClaims(); return blackList.add(verify.getId()); } catch (JWTVerificationException e) { return false; } }
public static UserDetails resolveJwt(String token){ Algorithm algorithm = Algorithm.HMAC256(key); JWTVerifier jwtVerifier = JWT.require(algorithm).build(); try { DecodedJWT verify = jwtVerifier.verify(token); if(blackList.contains(verify.getId())) return null; Map<String, Claim> claims = verify.getClaims(); if(new Date().after(claims.get("exp").asDate())) return null; return User .withUsername(claims.get("name").asString()) .password("") .authorities(claims.get("authorities").asArray(String.class)) .build(); } catch (JWTVerificationException e) { return null; } } }
|