使用具有不同 AuthenticationProviders 的多个 WebSecurityConfigurerAdapter(API 的基本身份验证和 Web 应用的 LDAP)

Posted

技术标签:

【中文标题】使用具有不同 AuthenticationProviders 的多个 WebSecurityConfigurerAdapter(API 的基本身份验证和 Web 应用的 LDAP)【英文标题】:Using multiple WebSecurityConfigurerAdapter with different AuthenticationProviders (basic auth for API and LDAP for web app) 【发布时间】:2017-03-08 14:26:21 【问题描述】:

根据Spring Security Reference section 5.7,应该可以定义多个安全适配器。

我尝试做同样的事情,但没有成功。服务器重新启动后,API 的前 x 次使用基本身份验证正常工作,但几次后我被重定向到登录(表单)页面,这应该只发生在我们的 Web 应用程序,而不是 API 调用。

我的代码:

@EnableWebSecurity
public class MultiHttpSecurityConfig  

    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter 

        @Autowired
        private Environment env;

        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception 
            auth.inMemoryAuthentication().
                withUser("admin").password("pw_test").roles(API_ROLE);
        

        protected void configure(HttpSecurity http) throws Exception 
            http
              .antMatcher("/services/**")
              .authorizeRequests()
              .anyRequest().hasRole(API_ROLE)
              .and()
              .httpBasic()
              .and()
              .csrf()
              .disable();
        
    

    @Configuration
    @Order(2)
    public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter 

        @Autowired
        private Environment env;

        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception 
            auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
            auth.eraseCredentials(false);
        

        @Override
        protected void configure(HttpSecurity http) throws Exception 
            // LDAP FORM AUTHENTICATION
            http.authorizeRequests()
                .antMatchers("/login.html").permitAll()
                .antMatchers("/css/**").permitAll() 
                .antMatchers("/js/**").permitAll() 
                .antMatchers("/images/**").permitAll() 
                .anyRequest().authenticated()
            .and().formLogin()
                .failureUrl("/login.html?error=1")
                .loginPage("/login.html")
                .loginProcessingUrl("/j_spring_security_check")
                .defaultSuccessUrl("/success.html")
                .usernameParameter("j_username")
                .passwordParameter("j_password")
                .permitAll();

            http.csrf().disable();

            // iFRAMES SETTINGS
            http
                .headers()
                .frameOptions().sameOrigin()
                .httpStrictTransportSecurity().disable();

            // HTTPS
            http
                .requiresChannel()
                .anyRequest()
                .requiresSecure();

            //MAP 8080 to HTTPS PORT
            http.portMapper().http(8080).mapsTo(443);
        

        @Bean
        public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() 
            CustomLdapAuthenticationProvider provider = new CustomLdapAuthenticationProvider(env.getProperty("ldap.domain"), env.getProperty("ldap.url"), env.getProperty("ldap.base"));
            provider.setConvertSubErrorCodesToExceptions(true);
            provider.setUseAuthenticationRequestCredentials(true);
            return provider;
        
    

有什么想法吗?

我正在使用 Spring Boot 版本 1.4.1-RELEASE 和 Spring Security 版本 4.1.3-RELEASE。

【问题讨论】:

【参考方案1】:

您对两种配置使用相同的AuthenticationManager,因为您自动连接相同的AuthenticationManagerBuilder

见Spring Security Architecture:

@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter 

    ... // web stuff here

    @Autowired
    public void initialize(AuthenticationManagerBuilder builder, DataSource dataSource) 
        builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")
            .password("secret").roles("USER");
    


此示例与 Web 应用程序有关,但 AuthenticationManagerBuilder 的使用更广泛(有关如何实现 Web 应用程序安全性的更多详细信息,请参见下文)。请注意,AuthenticationManagerBuilder@Autowired 中的一个方法 @Bean - 这就是它构建全局(父)AuthenticationManager 的原因。相比之下,如果我们这样做:

@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter 

    @Autowired
    DataSource dataSource;

    ... // web stuff here

    @Override
    public void configure(AuthenticationManagerBuilder builder) 
        builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")
            .password("secret").roles("USER");
    


(在配置器中使用@Override 方法)然后AuthenticationManagerBuilder 仅用于构建“本地”AuthenticationManager,它是全局的子代。

【讨论】:

以上是关于使用具有不同 AuthenticationProviders 的多个 WebSecurityConfigurerAdapter(API 的基本身份验证和 Web 应用的 LDAP)的主要内容,如果未能解决你的问题,请参考以下文章

使用具有不同模型和 DataTemplates 的分组 ListView

如何使用sql从具有不同列的两个表中获取不同的记录

使用不同编码编码的两个不同字符串可以具有相同的字节序列吗?

使用 AJAX 获取具有不同按钮的不同 html

为啥使用 cv::line 函数绘制的不同线条具有不同的透明度 (alpha) 级别?

iOS PageViewController 使用故事板具有不同的页面布局