============= 后端_令牌过滤 ============= 1 添加依赖 /pom.xml: ... org.crazycake shiro-redis-spring-boot-starter 3.3.1 javax.xml.bind jaxb-api 2.3.1 cn.hutool hutool-all 5.3.3 io.jsonwebtoken jjwt 0.9.1 ... 2 添加属性 /src/main/resources/META-INF/spring-devtools.properties: restart.include.shiro-redis=/shiro-[\\w-\\.]+jar 3 添加配置 /src/main/resources/application.yml: ... shiro-redis: enabled: true redis-manager: host: 127.0.0.1:6379 weihome: jwt: # 加密秘钥 secret: f4e2e52034348f86b67cde581c0f9eb5 # 有效秒数(7天) expire: 604800 header: Authorization ... 4 添加JWT工具类 /src/main/java/com/weihome/barblog/shiro/JwtUtils.java: /** * JWT工具类 */ @Slf4j @Data @Component @ConfigurationProperties(prefix = "weihome.jwt") public class JwtUtils { private String secret; private long expire; private String header; /** * 生成令牌 */ public String generateToken(long userId) { Date nowDate = new Date(); //过期时间 Date expireDate = new Date(nowDate.getTime() + expire * 1000); return Jwts.builder() .setHeaderParam("typ", "JWT") .setSubject(userId+"") .setIssuedAt(nowDate) .setExpiration(expireDate) .signWith(SignatureAlgorithm.HS512, secret) .compact(); } public Claims getClaimByToken(String token) { try { return Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) .getBody(); }catch (Exception e){ log.debug("validate is token error ", e); return null; } } /** * 令牌是否过期 * @return true:过期 */ public boolean isTokenExpired(Date expiration) { return expiration.before(new Date()); } } 5 添加JWT令牌类 /src/main/java/com/weihome/barblog/shiro/JwtToken.java: /** * JWT令牌类 */ public class JwtToken implements AuthenticationToken { private String token; // 令牌字符串 public JwtToken(String token) { this.token = token; } @Override public Object getPrincipal() { return token; } @Override public Object getCredentials() { return token; } } 6 添加JWT过滤器类 /src/main/java/com/weihome/barblog/shiro/JwtFilter.java: /** * JWT过滤器类 */ @Component public class JwtFilter extends AuthenticatingFilter { @Autowired JwtUtils jwtUtils; /** * 接受或拒绝请求 * 无令牌:接受请求 * 令牌无效:抛出异常 * 令牌有效:根据身份认证结果决定接受或拒绝请求 */ @Override protected boolean onAccessDenied( ServletRequest servletRequest, ServletResponse servletResponse) throws Exception { HttpServletRequest request = (HttpServletRequest) servletRequest; // 从请求头中获取令牌字符串 String token = request.getHeader("Authorization"); if (StringUtils.isEmpty(token)) // 无令牌 return true; // 接受请求 Claims claim = jwtUtils.getClaimByToken(token); if (claim == null || jwtUtils.isTokenExpired( claim.getExpiration())) // 令牌无效 throw new ExpiredCredentialsException("令牌无效,重新登录"); return executeLogin(servletRequest, servletResponse); // 身份认证 } /** * 身份认证过程中调用此方法 */ @Override protected AuthenticationToken createToken( ServletRequest servletRequest, ServletResponse servletResponse) throws Exception { HttpServletRequest request = (HttpServletRequest) servletRequest; // 从请求头中获取令牌字符串 String token = request.getHeader("Authorization"); if (StringUtils.isEmpty(token)) // 无令牌 return null; // 无需身份认证 return new JwtToken(token); // 返回JWT令牌用于身份认证 } /** * 身份认证失败时调用此方法 */ @Override protected boolean onLoginFailure( AuthenticationToken authcToken, AuthenticationException authcException, ServletRequest servletRequest, ServletResponse servletResponse) { HttpServletResponse response = (HttpServletResponse) servletResponse; Throwable throwable = authcException.getCause() == null ? authcException : authcException.getCause(); Result result = Result.error(throwable.getMessage()); String json = JSONUtil.toJsonStr(result); try { // 将包含异常信息的Json字符串写入响应 response.getWriter().print(json); } catch (IOException ioException) { } return false; } }