Spring Security Spring安全性-使用2个身份验证提供程序时不支持请求方法“POST”

ujv3wf0j  于 2023-08-05  发布在  Spring
关注(0)|答案(1)|浏览(147)

Spring Security不允许我使用2个身份验证提供程序之一登录。
我的应用程序应该能够通过检查数据库中存储的信息来验证两种类型的用户-UserOrganization。为此,我创建了两个单独的WebSecurityConfiguration类,使用不同的SecurityFilterChain,定义不同的表单登录,并使用2个不同的身份验证提供程序-它们使用两个不同的UserDetailsService实现(指向不同的存储库)。
我的Organization端点工作-注册和登录,会话成功创建,但对于User,登录端点(/auth/login/user)上的POST方法被阻止-在IntelliJ上返回Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' is not supported]作为警告,但后端在Postman上返回状态200。应用程序没有崩溃,但POST方法没有完成-在调试时,它作为405完成并将请求重定向到/auth/login/org
以下是OrgWebSecurityConfigurationSecurityFilterChain

@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();
    }

字符串
UserWebSecurityConfigurationSecurityFilterChain

@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;
    }


orgAuthenticationManageruserAuthenticationManager都是通过定义DaoAuthenticationProvider类型的身份验证提供程序并为每个提供程序设置适当的UserDetailsService来创建的,并在AuthenticationManagerBuilder上实现所创建的身份验证提供程序。在本例中,User的身份验证管理器被设置为主身份验证管理器,使用@Primary注解。
我尝试按照this questionUserWebSecurityConfiguration上使用@Order(0)注解,但问题仍然存在。我还禁用了csrf。

v6ylcynt

v6ylcynt1#

我通过将两个SecurityFilterChains合并为一个来解决这个问题,并将AuthenticationProvider s添加到userAuthenticationManager中,如下所示:

@Bean
    @Primary
    public AuthenticationManager userAuthenticationManager(HttpSecurity http) throws Exception {
        return http.getSharedObject(AuthenticationManagerBuilder.class)
                .authenticationProvider(userAuthProvider())
                .authenticationProvider(orgAuthProvider())
                .build();
    }

字符串
然后通常将userAuthenticationManager添加到securityFilterChain(之前的userSecurityFilterChain):

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


现在,我只使用一个表单登录来验证UserOrganization-/auth/login
解释:
通过在application.properties上添加trace=true,我能够确定对/auth/login/userPOST请求返回状态405,并被重定向为对/auth/login/orgGET请求。这意味着orgSecurityFilterChain被认为是应用程序上的“默认”过滤器,即使userSecurityFilterChain被标记为Order(0)。它允许访问/auth/*/user,但发生的情况是,即使我访问了用户端点(应该使用userSecurityFilterChain),仍然使用了orgSecurityFilterChain,因为它是默认的过滤器,它将/auth/login/orgMap为表单登录名。这意味着,即使该请求应该由userSecurityFilterChain处理(它将登录端点Map为/auth/login/user),它也由orgSecurityFilterChain处理,而orgSecurityFilterChain不支持POST/auth/login/user的请求。

相关问题