多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
步骤如下: **1. 封装jwt工具** ```java public class JwtUtils { /** * token有效期,单位ms。 * 60 * 60 *1000 一个小时 */ public static final Long JWT_TTL = 3600000L; /** * 秘钥明文 */ public static final String JWT_KEY = "itcast"; /** * 存储token,这里用Map代替Redis */ private static final Map<String, Object> tokenMap = new HashMap<>(16); /** * 创建token */ public static String createToken(String id, String subject, Map<String, Object> claims, 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)); if (!CollectionUtils.isEmpty(claims)) { //如果想存储更多的信息(例如角色)可以增加自定义claims builder.claim("roles", claims.get("roles")); } 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(); } /** * 登录成功时存储token */ public static void putToken(String username, String token) { tokenMap.put(username, token); } /** * 获取token */ public static String getToken(String username) { return (String) tokenMap.get(username); } /** * 退出时删除token */ public static void delToken(String username) { tokenMap.remove(username); } } ``` **2. 封装登录登出的controller** ```java @RestController @RequestMapping("/admin") @RequiredArgsConstructor public class AdminController { final AdminService adminService; @PostMapping("/login") public Json login(@RequestBody Admin admin) { boolean login = adminService.login(admin); //验证失败 if (!login) { return JsonBuilder.error(); } //创建token String token = JwtUtils.createToken(UUID.randomUUID().toString(), admin.getUsername(), null, null); String auth = JwtUtils.hashpw(admin.getUsername()); //存储token JwtUtils.putToken(auth, token); Map<String, String> info = new HashMap<>(16); info.put("username", admin.getUsername()); info.put("token", token); info.put("auth", auth); return JsonBuilder.ok(info); } @PostMapping("/logout") public Json logout(@RequestBody Admin admin) { //删除token JwtUtils.delToken(admin.getAuth()); return JsonBuilder.ok(); } @PostMapping("/uuid") public Json getUUID() { return JsonBuilder.ok(UUID.randomUUID().toString()); } } ``` **3. 在过滤器中进行认证** ```java @Component public class AuthorizeFilter implements Filter { private static final String AUTHORIZE_TOKEN = "token"; private static final String AUTHORIZE_auth = "auth"; @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"); //1. 如果是登录、退出请求则放行 boolean release = request.getRequestURI().contains("/admin/login") || request.getRequestURI().contains("/admin/logout"); if (release) { //放行 chain.doFilter(request, response); return; } //2. token不存在说明已经退出或未登录 String auth = request.getHeader(AUTHORIZE_auth); if (JwtUtils.getToken(auth) == null) { String resJson = JSON.toJSONString(JsonBuilder.error("未登录")); response.getWriter().write(resJson); return; } //3. 请求头中获取令牌 String token = request.getHeader(AUTHORIZE_TOKEN); //判断请求头中是否有令牌 if (!StringUtils.hasLength(token)) { String resJson = JSON.toJSONString(JsonBuilder.error("无权限访问")); response.getWriter().write(resJson); return; } //4. 如果请求头中有令牌则解析令牌 try { JwtUtils.parseToken(token); //放行 chain.doFilter(request, response); } catch (Exception e) { e.printStackTrace(); //5. 解析jwt令牌出错, 说明令牌过期或者伪造等不合法情况出现 String resJson = JSON.toJSONString(JsonBuilder.error("无权限访问")); response.getWriter().write(resJson); } } } ``` **3. 测试** (1)未登录访问 http://localhost:8080/admin/uuid 。 ``` { "code": 1000, "msg": "未登录", "success": false } ``` (2)登录 http://localhost:8080/admin/login 。 ``` //入参 { "username": "zhangsan", "password": "123456" } //出参 { "success": true, "code": 200, "msg": "操作成功", "data": { "auth": "$2a$10$jth464hRdX5IrxIbUwsczOQlbcarlr9hL8klZfQf7wBtLQ89BggLm", "username": "zhangsan", "token": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI0YWJhYzIxYi0zMDNhLTRlZmYtYTk2My04NDFhOWFlN2I3ZmQiLCJzdWIiOiJ6aGFuZ3NhbiIsImlzcyI6ImFkbWluIiwiaWF0IjoxNjc2NTYyMDk3LCJleHAiOjE2NzY1NjU2OTd9.tid7QncjDhdjAGjcDBPwO53I-5JSOz7aH6g5jt04c64" } } ``` (3)完成登录后访问 http://localhost:8080/admin/uuid 。 ![](https://img.kancloud.cn/c9/d2/c9d2ec6c04234f3253a4ef486891b014_1763x385.png) ``` { "success": true, "code": 200, "msg": "操作成功", "data": "abc10c73-111d-4f35-b819-759698676076" } ``` (4)注销后再访问 http://localhost:8080/admin/uuid 。 ``` { "code": 1000, "msg": "未登录", "success": false } ```