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

Spring Security双认证提供者问题:User登录POST请求不被支持

多用户类型Spring Security登录问题排查与解决

问题描述

应用需区分User和Organization两种用户类型做数据库验证,因此创建了两个独立的WebSecurityConfiguration类,分别配置对应SecurityFilterChain、表单登录逻辑及UserDetailsService实现的认证提供者。

目前Organization的注册、登录端点均正常,会话可成功创建;但User的登录端点/auth/login/user的POST请求出现异常:

  • IntelliJ日志提示 Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' is not supported]
  • Postman显示返回200,但实际调试发现请求先返回405,随后重定向至/auth/login/org,POST请求未完成认证流程。

相关代码

OrgWebSecurityConfiguration的SecurityFilterChain

@Bean
@CrossOrigin
public SecurityFilterChain orgSecurityFilterChain(HttpSecurity http) throws Exception {
    http.csrf()
            .disable()
            .securityMatchers((matcher) -> matcher
                    .requestMatchers("/auth/*/org").anyRequest())
            .authorizeHttpRequests()
            .requestMatchers("/auth/register/**")
            .permitAll()
            .requestMatchers("/auth/login/**")
            .permitAll()
            .anyRequest()
            .authenticated()
            .and()
            .formLogin()
            .loginPage("/auth/login/org")
            .loginProcessingUrl("/auth/login/org")
            .defaultSuccessUrl("/auth/org-login-success", true)
            .permitAll()
            .and()
            .authenticationManager(orgAuthenticationManager(http))
            .logout()
            .invalidateHttpSession(true)
            .clearAuthentication(true)
            .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
            .logoutSuccessUrl("/auth/login?logout")
            .permitAll();
    return http.build();
}

UserWebSecurityConfiguration的SecurityFilterChain

@Bean
@CrossOrigin
public SecurityFilterChain userSecurityFilterChain(HttpSecurity http) throws Exception {
    http.csrf()
            .disable()
            .securityMatchers((matcher) -> matcher
                    .requestMatchers("/auth/*/user").anyRequest())
            .authorizeHttpRequests()
            .requestMatchers("/auth/register/**")
            .permitAll()
            .requestMatchers("/auth/login/**")
            .permitAll()
            .anyRequest()
            .authenticated()
            .and()
            .formLogin()
            .loginPage("/auth/login/user")
            .loginProcessingUrl("/auth/login/user")
            .defaultSuccessUrl("/auth/login-success", true)
            .permitAll()
            .and()
            .authenticationManager(userAuthenticationManager(http))
            .logout()
            .invalidateHttpSession(true)
            .clearAuthentication(true)
            .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
            .logoutSuccessUrl("/auth/login?logout")
            .permitAll();
    return http.build();
}

userAuthProvider

@Bean
public DaoAuthenticationProvider userAuthProvider() {
    DaoAuthenticationProvider userAuthenticationProvider = new DaoAuthenticationProvider();
    userAuthenticationProvider.setUserDetailsService(userDetailsService);
    userAuthenticationProvider.setPasswordEncoder(passwordEncoder());
    return userAuthenticationProvider;
}

orgAuthProvider

@Bean
public DaoAuthenticationProvider orgAuthProvider() {
    DaoAuthenticationProvider orgAuthenticationProvider = new DaoAuthenticationProvider();
    orgAuthenticationProvider.setUserDetailsService(organizationDetailsService);
    orgAuthenticationProvider.setPasswordEncoder(passwordEncoder);
    return orgAuthenticationProvider;
}

注:orgAuthenticationManager和userAuthenticationManager均通过AuthenticationManagerBuilder配置对应DaoAuthenticationProvider实现,其中User的认证管理器通过@Primary注解设为优先。已尝试为UserWebSecurityConfiguration添加@Order(0)注解、关闭CSRF,但问题仍未解决。

问题根源与修复方案

1. 修正SecurityFilterChain的匹配范围(核心问题)

两个配置中的securityMatchers写法错误,.requestMatchers("/auth/*/org").anyRequest()会让该FilterChain匹配所有请求,而非仅/auth/*/org路径,导致两条链的请求范围重叠,User的登录请求被Org的链错误拦截。

修改两个配置类的securityMatchers,明确限定各自负责的路径:

  • OrgWebSecurityConfiguration:
.securityMatchers((matcher) -> matcher
        .requestMatchers("/auth/*/org", "/auth/register/org"))
  • UserWebSecurityConfiguration:
.securityMatchers((matcher) -> matcher
        .requestMatchers("/auth/*/user", "/auth/register/user"))

2. 明确FilterChain执行顺序

为两个配置类添加@Order注解,确保优先级明确:

  • 在UserWebSecurityConfiguration类上添加@Order(1)
  • 在OrgWebSecurityConfiguration类上添加@Order(2)
    注:@Order数值越小,执行优先级越高

3. 消除AuthenticationManager全局冲突

移除认证管理器的@Primary注解,每个FilterChain使用专属的认证管理器,将userAuthenticationManager和orgAuthenticationManager设为配置类的私有方法,避免全局Bean冲突:

// User配置类中的私有方法
private AuthenticationManager userAuthenticationManager(HttpSecurity http) throws Exception {
    return http.getSharedObject(AuthenticationManagerBuilder.class)
            .authenticationProvider(userAuthProvider())
            .build();
}

4. 验证登录路径匹配

确保loginProcessingUrl的路径在对应FilterChain的securityMatchers范围内,例如User的/auth/login/user已包含在.requestMatchers("/auth/*/user")中,无需额外调整。

验证

修复后重启应用,发送POST请求至/auth/login/user,可正常进入User的认证流程,无405错误及错误重定向。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 10:56:59