添加依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
生成JWT(Token)
public static String getToken() {
// 声明过期时间:当前时间24小时后
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.HOUR, 24);
Date expiredTime = calendar.getTime();
// 获取JWT
String token = JWT.create()
// 设置Header,不写也行,全部使用默认值
.withHeader(new HashMap<String, Object>())
// 设置Payload
.withClaim("id", 12345)
.withClaim("username", "John")
.withExpiresAt(expiredTime)
// 设置Signature
.sign(Algorithm.HMAC256("token12#@!KJH"));
return token;
}
验证JWT(Token)
public static void verifyToken(String token) {
// 签名的算法和密钥都必须和创建时一致
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("token12#@!KJH")).build();
// 验证拿到的Token,如果验证失败,verify方法会抛出异常
DecodedJWT decodedJWT = jwtVerifier.verify(token);
// 如果验证成功,则可以获取Payload中的信息
System.out.println(decodedJWT.getClaim("id").asLong());
System.out.println(decodedJWT.getClaim("username").asString());
}
注意:verify抛出的异常:
SignatureverificationException:签名不一致异常
TokenExpiredException:令牌过期异常
AlgorithmMismatchException:算法不匹配异常
InvalidClaimException:失效的payload异常
Springboot整合JWT
-
封装JWTUtils:
/** * JWT工具类 */ public class JWTUtils { /** * 私钥 */ private static final String SECRET = "1@3$.Ssd$%7^"; /** * 创建Token * @param map 前台传输的用户信息 * @return Token */ public static String getToken(Map<String, String> map) { JWTCreator.Builder builder = JWT.create(); // 声明过期时间:7天 Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DATE, 7); Date expireTime = calendar.getTime(); // Header默认加载,不写也行 builder.withHeader(new HashMap<String, Object>()); // Payload装载数据 for (Map.Entry<String, String> entry : map.entrySet()) { builder.withClaim(entry.getKey(), entry.getValue()); } builder.withExpiresAt(expireTime); // Signature配置,同时获取最终生成的Token String token = builder.sign(Algorithm.HMAC256(SECRET)); return token; } /** * 验证Token合法性,假如Token被修改,则抛出异常 * @param token 待验证的Token */ public static void verifyToken(String token) { // 验证Token必须使用和创建一样的算法和私钥 JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token); } /** * 通过载荷名字获取载荷的值 * @param token 已验证的Token * @param name payload中的key * @return payload中的value */ public static Claim getClaimByName(String token, String name){ return JWT.decode(token).getClaim(name); } }
-
在
config
包中创建拦截器配置类/** * 拦截器配置类 */ @Configuration public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new JWTInterceptor()) // 拦截路径 .addPathPatterns("/**") // 放行路径 .excludePathPatterns("/user/login") .excludePathPatterns("/user/verifyCode"); } }
-
在
interceptor
包中配置拦截器/** * JWT拦截器,对除了登录注册以外的接口进行保护。 * 用户登录后,Token被存储在前端,每一次请求都放在Header中带给后端,中间被拦截器拦下来做验证 */ public class JWTInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 获取请求中的token,官方建议将token携带在请求头中 String token = request.getHeader("token"); Result result; try { // 验证token JWTUtils.verifyToken(token); // 放行请求 return true; } catch (SignatureVerificationException e1) { result = Result.error(ResultCodeEnum.SIGNATURE_VERIFICATION_ERROR); } catch (TokenExpiredException e2) { result = Result.error(ResultCodeEnum.TOKEN_EXPIRED_ERROR); } catch (AlgorithmMismatchException e3) { result = Result.error(ResultCodeEnum.ALGORITHM_MISMATCH_ERROR); } catch (InvalidClaimException e4) { result = Result.error(ResultCodeEnum.INVALID_CLAIM_ERROR); } // 将result转成json传到前端 String resultJson = new ObjectMapper().writeValueAsString(result); response.setContentType("application/json;charset=UTF-8"); response.getWriter().println(resultJson); // 拦截请求 return false; } }
-
接口示例
// 不需要再接收token,专注于业务逻辑的处理 @GetMapping("test") public Result test() { // 业务处理 return Result.ok(); }