You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security 6未调用自定义CustomAuthenticationProvider问题求助

问题分析与解决:Spring Security自定义AuthenticationProvider未被调用

问题背景

我的Spring Security配置定义如下:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

    private final CustomAuthenticationProvider customAuthenticationProvider;

    @Autowired
    public SecurityConfiguration(CustomAuthenticationProvider customAuthenticationProvider) {
        this.customAuthenticationProvider = customAuthenticationProvider;
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .cors(CorsConfigurer::disable) // Disable CORS
            .csrf().disable()
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
            .authenticationProvider(customAuthenticationProvider)
            .authorizeHttpRequests(authorizeRequests -> authorizeRequests
                .requestMatchers(HttpMethod.GET, "/health", "/public/**").permitAll()
                .requestMatchers("/api/**", "/events/**", "/competition/**").authenticated()
            )
            .httpBasic();

        return http.build();
    }
   
}

/static和/public路径的请求能正常被允许访问,但/events、/api、/competition下的请求都会触发AnonymousAuthenticationFilter。请求/events/1时的日志如下:

20:05:06.483 [http-nio-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - Securing GET /events/1
20:05:06.483 [http-nio-8080-exec-8] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
20:05:06.484 [http-nio-8080-exec-8] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to com.pr.golf.golfapp.controller.EventsController#getEvent(Long)
20:05:06.486 [http-nio-8080-exec-8] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to com.pr.golf.golfapp.controller.EventsController#getEvent(Long)
20:05:06.487 [http-nio-8080-exec-8] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to com.pr.golf.golfapp.controller.EventsController#getEvent(Long)
20:05:06.488 [http-nio-8080-exec-8] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to com.pr.golf.golfapp.controller.EventsController#getEvent(Long)
20:05:06.490 [http-nio-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - Securing GET /error
20:05:06.491 [http-nio-8080-exec-8] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml(HttpServletRequest, HttpServletResponse)
20:05:06.492 [http-nio-8080-exec-8] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml(HttpServletRequest, HttpServletResponse)
20:05:06.493 [http-nio-8080-exec-8] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml(HttpServletRequest, HttpServletResponse)
20:05:06.495 [http-nio-8080-exec-8] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml(HttpServletRequest, HttpServletResponse)
20:05:06.498 [http-nio-8080-exec-8] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml(HttpServletRequest, HttpServletResponse)
20:05:06.498 [http-nio-8080-exec-8] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext

原因分析

你的CustomAuthenticationProvider未被调用,核心原因是认证流程没有被触发:

  • 你配置了.httpBasic(),意味着Spring Security会通过HttpBasicAuthenticationFilter处理认证,但这个过滤器只会在请求携带Authorization: Basic <Base64编码的用户名:密码>头时才会启动认证流程,调用配置的AuthenticationProvider。
  • 如果请求没有携带这个认证头,Spring Security会认为当前是匿名请求,直接触发AnonymousAuthenticationFilter,不会调用自定义的AuthenticationProvider,最终因为请求需要认证但没有有效身份,跳转到错误页面。

解决方案

根据你的认证需求,有两种处理方式:

方式一:使用Http Basic认证(符合当前配置)

确保请求携带正确的Http Basic认证头:

  1. 将用户名和密码用冒号拼接(比如user:password)
  2. 对拼接后的字符串进行Base64编码
  3. 在请求头中添加Authorization: Basic <编码后的字符串>

例如,用curl发送请求:

curl -H "Authorization: Basic dXNlcjpwYXNzd29yZA==" http://localhost:8080/events/1

(其中dXNlcjpwYXNzd29yZA==是user:password的Base64编码)

方式二:自定义认证过滤器(如果不用Http Basic)

如果你的认证方式不是Http Basic(比如Token认证),需要添加自定义过滤器来触发认证流程:

  1. 编写一个自定义过滤器,从请求中提取认证凭证(比如Token)
  2. 创建Authentication对象(比如UsernamePasswordAuthenticationToken或自定义实现)
  3. 调用AuthenticationManager.authenticate(authentication)方法,这会自动触发你的CustomAuthenticationProvider
  4. 将认证成功后的Authentication对象存入SecurityContextHolder

示例代码:

public class CustomAuthFilter extends OncePerRequestFilter {
    private final AuthenticationManager authenticationManager;

    public CustomAuthFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 从请求头提取Token
        String token = request.getHeader("X-Auth-Token");
        if (token != null) {
            // 创建Authentication对象
            Authentication authRequest = new UsernamePasswordAuthenticationToken(null, token);
            // 触发认证,会调用CustomAuthenticationProvider
            Authentication authResult = authenticationManager.authenticate(authRequest);
            // 存入SecurityContext
            SecurityContextHolder.getContext().setAuthentication(authResult);
        }
        filterChain.doFilter(request, response);
    }
}

然后在Security配置中添加这个过滤器:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .cors(CorsConfigurer::disable)
        .csrf().disable()
        .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
        .authenticationProvider(customAuthenticationProvider)
        .addFilterBefore(new CustomAuthFilter(authenticationManager(http)), UsernamePasswordAuthenticationFilter.class)
        .authorizeHttpRequests(authorizeRequests -> authorizeRequests
            .requestMatchers(HttpMethod.GET, "/health", "/public/**").permitAll()
            .requestMatchers("/api/**", "/events/**", "/competition/**").authenticated()
        );

    return http.build();
}

// 暴露AuthenticationManager
@Bean
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
    return http.getSharedObject(AuthenticationManagerBuilder.class)
        .authenticationProvider(customAuthenticationProvider)
        .build();
}

内容的提问来源于stack exchange,提问作者mvarta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 16:14:56