|
@@ -5,6 +5,8 @@ import jakarta.servlet.FilterChain;
|
|
|
import jakarta.servlet.ServletException;
|
|
import jakarta.servlet.ServletException;
|
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
|
|
|
+import org.slf4j.Logger;
|
|
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
|
import org.springframework.security.core.context.SecurityContextHolder;
|
|
import org.springframework.security.core.context.SecurityContextHolder;
|
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.stereotype.Component;
|
|
@@ -17,6 +19,8 @@ import java.util.Set;
|
|
|
@Component
|
|
@Component
|
|
|
public class JwtAuthFilter extends OncePerRequestFilter {
|
|
public class JwtAuthFilter extends OncePerRequestFilter {
|
|
|
|
|
|
|
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(JwtAuthFilter.class);
|
|
|
|
|
+
|
|
|
/** 始终公开的路径(不需要 token) */
|
|
/** 始终公开的路径(不需要 token) */
|
|
|
private static final Set<String> PUBLIC_PREFIXES = Set.of(
|
|
private static final Set<String> PUBLIC_PREFIXES = Set.of(
|
|
|
"/health",
|
|
"/health",
|
|
@@ -38,6 +42,7 @@ public class JwtAuthFilter extends OncePerRequestFilter {
|
|
|
HttpServletResponse response,
|
|
HttpServletResponse response,
|
|
|
FilterChain filterChain) throws ServletException, IOException {
|
|
FilterChain filterChain) throws ServletException, IOException {
|
|
|
String uri = request.getRequestURI();
|
|
String uri = request.getRequestURI();
|
|
|
|
|
+ String method = request.getMethod();
|
|
|
|
|
|
|
|
// 公开路径始终放行
|
|
// 公开路径始终放行
|
|
|
if (isPublicPath(uri)) {
|
|
if (isPublicPath(uri)) {
|
|
@@ -49,27 +54,32 @@ public class JwtAuthFilter extends OncePerRequestFilter {
|
|
|
|
|
|
|
|
if (header != null && header.startsWith("Bearer ")) {
|
|
if (header != null && header.startsWith("Bearer ")) {
|
|
|
String token = header.substring(7);
|
|
String token = header.substring(7);
|
|
|
|
|
+ log.info("JWT 认证请求: {} {} | token={}...", method, uri, token.substring(0, Math.min(20, token.length())));
|
|
|
if (jwtUtil.validateToken(token)) {
|
|
if (jwtUtil.validateToken(token)) {
|
|
|
String subject = jwtUtil.getSubject(token);
|
|
String subject = jwtUtil.getSubject(token);
|
|
|
var auth = new UsernamePasswordAuthenticationToken(subject, null, Collections.emptyList());
|
|
var auth = new UsernamePasswordAuthenticationToken(subject, null, Collections.emptyList());
|
|
|
SecurityContextHolder.getContext().setAuthentication(auth);
|
|
SecurityContextHolder.getContext().setAuthentication(auth);
|
|
|
|
|
+ log.info("JWT 认证通过: subject={}, uri={} {}", subject, method, uri);
|
|
|
filterChain.doFilter(request, response);
|
|
filterChain.doFilter(request, response);
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
// token 无效
|
|
// token 无效
|
|
|
|
|
+ log.warn("JWT 认证拒绝(token无效): {} {}", method, uri);
|
|
|
if (authProperties.isEnabled()) {
|
|
if (authProperties.isEnabled()) {
|
|
|
send401(response, "token 无效或已过期");
|
|
send401(response, "token 无效或已过期");
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 无 token
|
|
|
|
|
- if (authProperties.isEnabled()) {
|
|
|
|
|
- send401(response, "未提供认证 token");
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 无 token
|
|
|
|
|
+ log.warn("JWT 认证拒绝(无token): {} {}", method, uri);
|
|
|
|
|
+ if (authProperties.isEnabled()) {
|
|
|
|
|
+ send401(response, "未提供认证 token");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 鉴权未启用,放行
|
|
// 鉴权未启用,放行
|
|
|
|
|
+ log.debug("鉴权未启用,放行: {} {}", method, uri);
|
|
|
filterChain.doFilter(request, response);
|
|
filterChain.doFilter(request, response);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -77,7 +87,6 @@ public class JwtAuthFilter extends OncePerRequestFilter {
|
|
|
for (String prefix : PUBLIC_PREFIXES) {
|
|
for (String prefix : PUBLIC_PREFIXES) {
|
|
|
if (uri.startsWith(prefix)) return true;
|
|
if (uri.startsWith(prefix)) return true;
|
|
|
}
|
|
}
|
|
|
- // 根路径 "/" 也公开
|
|
|
|
|
return "/".equals(uri) || uri.endsWith(".html") || uri.endsWith(".js") || uri.endsWith(".css");
|
|
return "/".equals(uri) || uri.endsWith(".html") || uri.endsWith(".js") || uri.endsWith(".css");
|
|
|
}
|
|
}
|
|
|
|
|
|