package com.trafficaudit.security.filter; import com.trafficaudit.security.utils.JwtUtils; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import javax.annotation.Resource; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; import java.util.List; /** * 接口登录校验过滤器:/api/** 除白名单外必须携带有效 Bearer 令牌,否则直接返回 401。 * 白名单只保留登录前必须调用的接口(登录、行为验证码)。 */ @Component @Order(1) public class JwtAuthFilter extends OncePerRequestFilter { /** 免登录接口(登录页在拿到令牌前必须能调用) */ private static final List WHITELIST = Arrays.asList( "/api/auth/login", "/api/auth/captcha", "/api/auth/captcha/verify", "/api/auth/captcha-config" ); @Resource private JwtUtils jwtUtils; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String uri = request.getRequestURI(); // 非接口请求(前端静态资源、首页)放行 if (uri == null || !uri.startsWith("/api")) { chain.doFilter(request, response); return; } // 预检请求放行,交由 CORS 处理 if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { chain.doFilter(request, response); return; } if (WHITELIST.contains(uri)) { chain.doFilter(request, response); return; } String username = jwtUtils.resolveUsername(request.getHeader("Authorization")); if (username == null) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("{\"code\":401,\"message\":\"未登录或登录已过期\",\"data\":null}"); return; } request.setAttribute("loginUser", username); chain.doFilter(request, response); } }