Appearance
过滤器链与执行顺序
过滤器顺序本身就是机制的一部分。Spring Security 大量问题都不是“配置错”,而是过滤器插错位置。
常见执行顺序
Servlet 场景下常见主链路可以概括为:
SecurityContextHolderFilterHeaderWriterFilterCsrfFilterLogoutFilterUsernamePasswordAuthenticationFilterBasicAuthenticationFilterRequestCacheAwareFilterSecurityContextHolderAwareRequestFilterAnonymousAuthenticationFilterSessionManagementFilterExceptionTranslationFilterAuthorizationFilter
不同功能开启后还会插入例如:
OAuth2AuthorizationRequestRedirectFilterOAuth2LoginAuthenticationFilterBearerTokenAuthenticationFilter
为什么是这个顺序
- 上下文恢复必须最早,否则后续拿不到身份。
- 认证要早于授权,否则
AuthorizationFilter没法判断。 ExceptionTranslationFilter要包住后面的授权异常。- 匿名认证要晚于真实认证,否则会把未登录请求过早固化成匿名主体。
顺序示意
text
request
-> SecurityContextHolderFilter
-> ...身份恢复/基础保护...
-> Authentication Filter
-> AnonymousAuthenticationFilter
-> ExceptionTranslationFilter
-> AuthorizationFilter
-> controller自定义 JWT 过滤器
java
@Component
class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String authorization = request.getHeader("Authorization");
if (authorization != null && authorization.startsWith("Bearer ")) {
Authentication authentication = new UsernamePasswordAuthenticationToken(
"jwtUser", null, List.of(new SimpleGrantedAuthority("ROLE_USER")));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
}java
@Bean
SecurityFilterChain apiChain(HttpSecurity http, JwtAuthenticationFilter jwtAuthenticationFilter) throws Exception {
return http
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.build();
}插入位置判断
- JWT 解析通常放在
UsernamePasswordAuthenticationFilter前面。 - 审计日志过滤器常放在认证后、授权前。
- 异常包装过滤器不能压过
ExceptionTranslationFilter的职责。
