SpringBoot 整合 JWT——Token 认证与自动刷新
📅 2026/7/19 1:09:27
👁️ 阅读次数
📝 编程学习
Session 方式在分布式环境下不好用,JWT(JSON Web Token)是目前主流的无状态认证方案。服务端不需要存 Session,Token 中包含了用户信息。
一、JWT 结构
header.payload.signature header: 加密算法 payload: 用户数据(不要放密码) signature: 签名,防止篡改二、JWT 工具类
@ComponentpublicclassJwtUtil{@Value("${jwt.secret:mySecretKey}")privateStringsecret;@Value("${jwt.expire:86400000}")privatelongexpire;// 默认24小时publicStringgenerateToken(LonguserId,Stringusername){Datenow=newDate();returnJwts.builder().setSubject(userId.toString()).claim("username",username).setIssuedAt(now).setExpiration(newDate(now.getTime()+expire)).signWith(SignatureAlgorithm.HS256,secret).compact();}publicClaimsparseToken(Stringtoken){returnJwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();}publicbooleanvalidateToken(Stringtoken){try{parseToken(token);returntrue;}catch(Exceptione){returnfalse;}}}三、登录接口
@RestController@RequestMapping("/auth")publicclassAuthController{@AutowiredprivateJwtUtiljwtUtil;@PostMapping("/login")publicResultVO<Map<String,Object>>login(@RequestParamStringusername,@RequestParamStringpassword){// 校验用户名密码if(!"admin".equals(username)||!"123456".equals(password)){returnResultVO.error(401,"用户名或密码错误");}// 生成 TokenStringaccessToken=jwtUtil.generateToken(1001L,username);StringrefreshToken=jwtUtil.generateRefreshToken(1001L);Map<String,Object>result=newHashMap<>();result.put("accessToken",accessToken);result.put("refreshToken",refreshToken);result.put("expiresIn",86400);returnResultVO.success(result);}}四、Token 刷新
@PostMapping("/refresh")publicResultVO<Map<String,Object>>refresh(@RequestParamStringrefreshToken){if(!jwtUtil.validateToken(refreshToken)){returnResultVO.error(401,"RefreshToken 无效");}Claimsclaims=jwtUtil.parseToken(refreshToken);LonguserId=Long.parseLong(claims.getSubject());Stringusername=claims.get("username",String.class);StringnewAccessToken=jwtUtil.generateToken(userId,username);StringnewRefreshToken=jwtUtil.generateRefreshToken(userId);returnResultVO.success(Map.of("accessToken",newAccessToken,"refreshToken",newRefreshToken));}五、拦截器校验
@ComponentpublicclassJwtInterceptorimplementsHandlerInterceptor{@AutowiredprivateJwtUtiljwtUtil;@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{Stringtoken=request.getHeader("Authorization");if(token==null||!token.startsWith("Bearer ")){thrownewBusinessException(401,"未登录");}token=token.substring(7);if(!jwtUtil.validateToken(token)){thrownewBusinessException(401,"Token 已过期");}// 将用户信息存入请求上下文Claimsclaims=jwtUtil.parseToken(token);request.setAttribute("userId",claims.getSubject());request.setAttribute("username",claims.get("username"));returntrue;}}六、前端调用
// 登录constresp=awaitfetch('/auth/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:'admin',password:'123456'})});const{accessToken,refreshToken}=awaitresp.json();// 后续请求携带 Tokenfetch('/api/user',{headers:{'Authorization':'Bearer '+accessToken}});// Token 过期时用 refreshToken 刷新asyncfunctionrefreshAccessToken(){constresp=awaitfetch('/auth/refresh',{method:'POST',body:newURLSearchParams({refreshToken})});constdata=awaitresp.json();accessToken=data.accessToken;}七、安全注意事项
// 1. JWT 中不要放敏感信息Claimsclaims=Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();Stringpassword=claims.get("password");// ❌ 错误!// 2. 密钥不要写死,用配置中心或环境变量@Value("${jwt.secret}")privateStringsecret;// 3. accessToken 有效期短(15-30分钟)// refreshToken 有效期长(7天),专门用来刷新 accessToken总结
Session 认证:服务端存 Session,分布式下需要共享 Session JWT 认证: 无状态,Token 携带用户信息,适合分布式 JWT 缺点:签发后无法主动失效(只能等过期) 解决方案:accessToken 短时效 + refreshToken 刷新机制💡 觉得有用的话,点赞 + 关注【张老师技术栈】吧!每周更新 Java/Python/爬虫 实战干货,不让你白来。
编程学习
技术分享
实战经验