【问题标题】:Spring Security multiple AuthenticationProvidersSpring Security 多个 AuthenticationProviders
【发布时间】:2020-05-18 12:56:26
【问题描述】:

我已经使用以下方式配置了 Spring Security:

@Configuration
@Import(SecurityProblemSupport.class)
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

   @Autowired
   private RestAuthenticationProvider authenticationProvider;

   @Autowired
   private CustomUserDetailService customUserDetailService;

   @Override
   protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.authenticationProvider(authenticationProvider);
        auth.userDetailsService(customUserDetailService);

        super.configure(auth);
    }

一切都按预期工作。 Rest 身份验证提供程序是一个实现 AuthenticationProvider 的组件:

@Component
public class RestAuthenticationProvider implements AuthenticationProvider  {

问题是,如果我在类路径中添加另一个扩展 AbstractUserDetailAuthenticationProvider 的 @Component,则不再使用 RestAuthenticationProvider; 相反,spring 使用一个默认提供程序,使用配置中指定的 UserDetailService。 此 CustomAuthenticationProvider 没有其他链接。它只是在同一个包中。 如果我在配置中使用 CustomProvider 会发生同样的事情,但其余的是用组件注释而不使用其他任何东西。

@Component // <- if I remove this, everything works fine. 
public class CustomUserAuthenticationProvider extends
   AbstractUserDetailsAuthenticationProvider {

我想根据一些配置在 AuthenticationProvider(S) 之间切换。 任何帮助表示赞赏。

【问题讨论】:

  • 为什么要切换?
  • 它并不是要在运行时切换;对于不同的安装,我想使用一种或另一种身份验证。
  • 我明白了,但你还没回答为什么?

标签: spring spring-boot authentication spring-security dependency-injection


【解决方案1】:

你可以给bean添加ConditionalOnProperty注解。

仅当条件启用或具有特定值时,Spring 才会将该 bean 包含在上下文中。

对于您的代码,它将如下所示:

@ConditionalOnProperty(name = "authprovider", havingValue = "custom")
public class CustomUserAuthenticationProvider extends
    AbstractUserDetailsAuthenticationProvider {

并在属性文件(或相关的PropertySource)中添加authprovider 属性:

authprovider=custom

另一种选择是将@Profile注解添加到bean。它映射特定应用程序配置文件的 bean 映射。我使用此选项为特定的开发环境加载某些配置。我建议在您的情况下使用第一个选项。

【讨论】:

  • 我明天会尝试这个选项,然后如果它有效,我会将您的答案设置为已接受。不管怎样,你知道为什么会这样吗?似乎 springs 搜索任何实现 authenticationprovider 的类。但是,在这种情况下,为什么还要麻烦配置 auth builder?
【解决方案2】:

我建议在您的 WebSecurityConfigurerAdapter 中使用单个 AuthenticationProvider 并使用委托方法,即仅实现一个身份验证提供程序:

@Component
public class DelegatingAuthenticationProvider implements AuthenticationProvider  {

    private final AuthenticationProvider authenticationProviderFirstDelegate;

    private final AuthenticationProvider authenticationProvideSecondDelegate; // This uses your UserDetailsService, e.g.

    private final SomeProperty someProperty;

    public Authentication authenticate(Authentication authentication) {
        // Here based on someProperty, return authenticationProviderFirstDelegate.authenticate(authentication) or authenticationProviderSecondDelegate.authenticate(authentication)
    }
}

然后输掉auth.userDetailsService(customUserDetailService);

【讨论】:

    【解决方案3】:

    经过几次尝试,我已经解决了这个问题。 我不得不使用

    @Component
    @ConditionalOnProperty(name = "authprovider", havingValue = "custom")
    public class CustomUserAuthenticationProvider extends
        AbstractUserDetailsAuthenticationProvider {
    

    和

    @Component
    @ConditionalOnProperty(name = "authentication.type", havingValue = "restCall")
    public class RestAuthenticationProvider implements AuthenticationProvider  {
    

    关于两个组件。

    在 WebSecurityConfigurerAdapter 的“configure”方法中直接使用这两者之一会造成麻烦,因为默认的“provider”是由 spring 自动使用的。

    所以我不得不阅读环境并使用手动注入 bean:

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
    @Autowired
    private Environment env;
    
    // .....
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    
        if (env.getProperty("authentication.type").equals("standard")) {
    
        auth.authenticationProvider(applicationContext.getBean( 
          CustomUserAuthenticationProvider.class));
         } 
    
        else {
    
        auth.authenticationProvider(applicationContext.getBean(
          RestAuthenticationProvider.class));
        }
    
        auth.userDetailsService(customUserDetailService);
    
        super.configure(auth);
    }
    

    【讨论】:

      猜你喜欢
      • 2017-05-28
      • 2015-10-12
      • 2019-04-13
      • 1970-01-01
      • 2021-12-30
      • 2012-06-04
      • 2021-04-21
      • 2016-08-31
      • 2018-11-15
      相关资源
      最近更新 更多