多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
**1. 封装 token 工具** ```java public class JwtUtils { /** * token有效期,单位ms。 * 60 * 60 *1000 一个小时 */ public static final Long JWT_TTL = 3600000L; /** * 秘钥明文 */ public static final String JWT_KEY = "itcast"; /** * 创建token * * @param id: token唯一ID * @param subject: token主题,任意字符串 * @param ttlMs: token过期时间 * @return */ public static String createJWT(String id, String subject, Long ttlMs) { long nowMs = System.currentTimeMillis(); if (ttlMs == null) { ttlMs = JWT_TTL; } JwtBuilder builder = Jwts.builder() //唯一的ID .setId(id) //主题,可以是JSON数据 .setSubject(subject) //签发者 .setIssuer("admin") //签发时间 .setIssuedAt(new Date(nowMs)) //使用HS256对称加密算法签名, 第二个参数为秘钥 .signWith(SignatureAlgorithm.HS256, generalKey()) //设置过期时间 .setExpiration(new Date(nowMs + ttlMs)); return builder.compact(); } /** * 生成加密后的秘钥 */ public static SecretKey generalKey() { byte[] encodedKey = Base64.getDecoder().decode(JWT_KEY); SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES"); return key; } /** * 密码加密 */ public static String hashpw(String password) { String gensalt = BCrypt.gensalt(); return BCrypt.hashpw(password, gensalt); } /** * 密码验证 */ public static boolean checkpw(String password, String hashpw) { boolean checkpw = BCrypt.checkpw(password, hashpw); return checkpw; } /** * 解析token */ public static Claims parseToken(String token) { return Jwts.parser() .setSigningKey(generalKey()) .parseClaimsJws(token) .getBody(); } } ``` **2. 登录成功后签发 token** ```java @RestController @RequiredArgsConstructor @RequestMapping("/admin") public class AdminController { final AdminService adminService; @PostMapping("/login") public Map<String, Object> login(@RequestBody Admin admin) { //验证账号/密码是否正常 boolean login = adminService.login(admin); //验证失败 if (!login) { return Map.of("success", false, "message", "账号或密码错误"); } //创建token String token = JwtUtils.createJWT(UUID.randomUUID().toString(), admin.getUsername(), null); return Map.of("username", admin.getUsername(), "token", token); } @PostMapping("/getUUid") public Map<String, Object> getUUID() { return Map.of("success", true, "data", UUID.randomUUID().toString()); } } ``` **3. 在过滤器中验证 token** ```java @Slf4j @Component public class AuthorizeFilter implements Filter { private static final String AUTHORIZE_TOKEN = "token"; @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; response.setContentType("text/json;charset=utf-8"); //如果是登录则放行 boolean isLogin = request.getRequestURI().contains("/admin/login"); if (isLogin) { //放行 chain.doFilter(request, response); return; } Map<String, Object> resMap = Map.of("success", false, "message", "无权访问"); String resJson = JSON.toJSONString(resMap); //从请求头中获取token String token = request.getHeader(AUTHORIZE_TOKEN); //请求头不携带token不放行 if (!StringUtils.hasLength(token)) { response.getWriter().write(resJson); return; } try { //验证token JwtUtils.parseToken(token); } catch (Exception ex) { log.error("[doFilter|token验证失败]: {}", ex.getMessage(), ex); //验证token失败, 说明令牌过期或者伪造等不合法情况出现 response.getWriter().write(resJson); return; } //token验证通过放行 chain.doFilter(request, response); } } ``` **4. 测试** 1. 登录成功后签发 token。 ![](https://img.kancloud.cn/3d/cb/3dcb081c4a44a57087706d06cf5f9206_1802x602.png) <br/> 2. 每次请求在请求头携带 token,验证成功后方可访问。 ![](https://img.kancloud.cn/1d/51/1d51f8824a1771685bdad3c590ae7ff9_1777x597.png) **** 案例代码:https://gitee.com/flymini/codes03/tree/master/learn-jwtauth