Spring Security资源服务器(Servlet栈)JWT无效令牌日志记录咨询
基于Servlet栈的Spring Security资源服务器无效JWT日志与监控方案
核心结论
完全支持记录WARN/ERROR级别的无效JWT日志,无需依赖DEBUG/TRACE级别日志,同时可以通过自定义逻辑实现符合OWASP API10要求的监控能力。
方案1:自定义JWT认证失败处理器
通过实现AuthenticationFailureHandler,精准捕获JWT相关认证失败场景,记录指定级别的日志,并区分失败原因:
import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.oauth2.jwt.InvalidJwtException; import java.io.IOException; public class CustomJwtFailureHandler implements AuthenticationFailureHandler { private static final Logger logger = LoggerFactory.getLogger(CustomJwtFailureHandler.class); @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { // 区分不同的JWT无效场景 if (exception instanceof InvalidJwtException) { InvalidJwtException jwtException = (InvalidJwtException) exception; // 针对签名无效、过期、格式错误等细分场景记录日志 logger.warn("Invalid JWT token received for request {}: {}", request.getRequestURI(), jwtException.getLocalizedMessage()); } else if (exception instanceof BadCredentialsException) { logger.warn("Invalid credentials for request: {}", request.getRequestURI()); } else { logger.error("Unexpected authentication failure for request: {}", request.getRequestURI(), exception); } // 返回标准401响应 response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid or unauthorized token"); } }
在SecurityFilterChain配置中绑定该处理器:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationFailureHandler; @Configuration public class ResourceServerConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter())) .authenticationFailureHandler(customJwtFailureHandler()) ); return http.build(); } @Bean public AuthenticationFailureHandler customJwtFailureHandler() { return new CustomJwtFailureHandler(); } // 配置JWT转换器等其他必要组件 // ... }
方案2:监听Spring Security认证事件
通过Spring事件监听机制,无侵入式捕获AuthenticationFailureEvent,实现日志记录:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.event.EventListener; import org.springframework.security.authentication.event.AuthenticationFailureEvent; import org.springframework.security.oauth2.jwt.InvalidJwtException; import org.springframework.stereotype.Component; @Component public class AuthFailureEventListener { private static final Logger logger = LoggerFactory.getLogger(AuthFailureEventListener.class); @EventListener public void handleAuthFailure(AuthenticationFailureEvent event) { Exception exception = event.getException(); if (exception instanceof InvalidJwtException) { InvalidJwtException jwtException = (InvalidJwtException) exception; logger.warn("JWT validation failed: {}", jwtException.getMessage()); // 可在此处扩展监控逻辑 } } }
方案3:结合监控工具满足OWASP API10要求
为监控无效JWT拒绝数量的上升趋势,可结合Micrometer添加自定义指标:
import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; import jakarta.annotation.PostConstruct; import org.springframework.stereotype.Component; @Component public class JwtMetrics { private final MeterRegistry meterRegistry; private Counter invalidJwtCounter; public JwtMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; } @PostConstruct public void init() { invalidJwtCounter = Counter.builder("invalid.jwt.tokens") .description("Number of invalid JWT tokens rejected") .tag("failure_reason", "unknown") .register(meterRegistry); } public void incrementInvalidJwt(String failureReason) { invalidJwtCounter.tag("failure_reason", failureReason).increment(); } }
在自定义失败处理器中调用指标统计:
// 注入JwtMetrics private final JwtMetrics jwtMetrics; public CustomJwtFailureHandler(JwtMetrics jwtMetrics) { this.jwtMetrics = jwtMetrics; } // 在onAuthenticationFailure方法中 if (exception instanceof InvalidJwtException) { // ...日志记录 String reason = extractFailureReason((InvalidJwtException) exception); jwtMetrics.incrementInvalidJwt(reason); } // 自定义方法提取细分失败原因 private String extractFailureReason(InvalidJwtException exception) { if (exception.getMessage().contains("signature")) { return "signature_invalid"; } else if (exception.getMessage().contains("expired")) { return "token_expired"; } return "invalid_format"; }
通过Prometheus采集指标后,可在Grafana中创建仪表盘监控无效JWT数量变化,并设置阈值告警,满足OWASP API10的日志与监控要求。
为什么不推荐DEBUG/TRACE级别日志
生产环境开启DEBUG/TRACE会产生大量无关日志,占用存储资源且增加分析复杂度。上述方案仅针对无效JWT场景记录必要的WARN/ERROR级别日志,同时保留细分失败原因的能力,更适合生产环境。
内容的提问来源于stack exchange,提问作者ciis0
相关产品推荐
相关产品推荐

