SpringBoot3.3+SpringSecurity6自定义过滤器与认证提供者适配问题
Spring Security 6 自定义过滤器与认证提供者配置解决方案
问题根源
- 认证提供者未正确关联:旧版
configureGlobal方法依赖WebSecurityConfigurerAdapter,在Spring Security 6中该配置方式已失效,导致自定义AuthenticationProvider未被纳入当前安全过滤器链。 - 过滤器逻辑跳过认证流程:原自定义过滤器直接将认证对象存入
SecurityContext,Spring Security会判定请求已完成认证,不会触发AuthenticationProvider的校验逻辑。
修正步骤
1. 调整自定义过滤器逻辑
改用OncePerRequestFilter(确保单次请求仅执行一次),逻辑改为提取认证凭证→创建未认证对象→交由AuthenticationManager触发认证→认证通过后存入SecurityContext:
@Component public class CustomFilter extends OncePerRequestFilter { private final AuthenticationManager authenticationManager; // 构造注入AuthenticationManager public CustomFilter(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 从请求中提取认证信息(示例从请求头提取,可根据实际场景调整) String username = request.getHeader("X-Username"); String password = request.getHeader("X-Password"); if (username != null && password != null) { // 创建未认证的Authentication对象 Authentication unauthenticatedAuth = new UsernamePasswordAuthenticationToken(username, password); // 交由AuthenticationManager认证,自动触发自定义AuthenticationProvider的authenticate方法 Authentication authenticatedAuth = authenticationManager.authenticate(unauthenticatedAuth); // 认证通过后存入SecurityContext SecurityContextHolder.getContext().setAuthentication(authenticatedAuth); } filterChain.doFilter(request, response); } }
2. 修正SecurityConfiguration配置
在SecurityFilterChain中直接关联AuthenticationProvider,并通过Spring注入自定义过滤器(避免手动new导致依赖缺失):
@Slf4j @Configuration @EnableWebSecurity // 启用方法级安全(替代旧版@EnableGlobalMethodSecurity) @EnableMethodSecurity(securedEnabled = true) public class SecurityConfiguration { private final CustomAuthenticationProvider customAuthenticationProvider; private final CustomFilter customFilter; // 构造注入依赖 public SecurityConfiguration(CustomAuthenticationProvider customAuthenticationProvider, CustomFilter customFilter) { this.customAuthenticationProvider = customAuthenticationProvider; this.customFilter = customFilter; } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .requestMatchers("/secure/**", "/api/**").authenticated() // 配置需要认证的端点 .anyRequest().permitAll() ) // 注册自定义认证提供者 .authenticationProvider(customAuthenticationProvider) // 添加自定义过滤器,放在BasicAuthenticationFilter之前 .addFilterBefore(customFilter, BasicAuthenticationFilter.class) .build(); } // 注册AuthenticationManager Bean,自动关联已配置的AuthenticationProvider @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception { return authConfig.getAuthenticationManager(); } }
3. 确保AuthenticationProvider逻辑正确
完善authenticate方法的返回逻辑,并指定支持的Authentication类型:
@Component public class CustomAuthenticationProvider implements AuthenticationProvider { private final UserRepository userRepository; public CustomAuthenticationProvider(UserRepository userRepository) { this.userRepository = userRepository; } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getName(); String password = authentication.getCredentials().toString(); // 查询用户信息 User user = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("用户不存在"); } // 校验密码 if (!isAuthenticated(user, password)) { throw new BadCredentialsException("密码错误"); } // 返回已认证的Authentication对象,需包含用户权限信息 return new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities()); } // 指定该提供者支持的Authentication类型 @Override public boolean supports(Class<?> authentication) { return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); } private boolean isAuthenticated(User user, String password) { BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); return encoder.matches(password, user.getPassword()); } }
关键注意事项
- 避免手动new自定义过滤器实例,必须通过Spring注入,确保依赖(如
AuthenticationManager)正确初始化。 - 过滤器仅负责提取凭证并触发认证,具体校验逻辑交由
AuthenticationProvider处理,遵循单一职责原则。 - 若无需方法级安全,可移除
@EnableMethodSecurity注解。
内容的提问来源于stack exchange,提问作者Nanditha Suresh
相关产品推荐
相关产品推荐

