在多个位置配置Spring Security

时间:2019-02-07 10:20:39

标签: java spring spring-boot spring-security

通过实现单个WebSecurityConfigurerAdapter并以其HttpSecurity方法访问configure,我显然可以充分利用Spring Security的全部功能。但这导致整体实现,并且如果不为此实现自定义措施,就无法在应用程序模块之间分散。

因此,可以尝试实现多个WebSecurityConfigurerAdapter子类。但这会导致重复的HttpSecurity对象,从而尝试重新配置一些基本方面(例如csrf),并且无法正确修改第一个适配器中已经配置的内容。即使禁用默认设置在这里也无济于事。

因此,我的问题是:在独立的Configuration / Component类中是否有Spring或Spring-Boot方式指定http安全性? (所以Java不是xml配置) 一个示例可能是在链的中间添加一个安全过滤器。另一个更改csrf(例如,将会话更改为cookie),而仅另一个类将保留默认值。

1 个答案:

答案 0 :(得分:0)

我不认为有这样做的直接方法。但是我们仍然可以在项目架构中强制这样做。

通常,我们通常会从WebSecurityConfigurerAdapter的配置中覆盖3种方法。 1.配置(AuthenticationManagerBuilder auth) 2.配置(WebSecurity Web) 3.配置(HttpSecurity http)

根据Spring安全性架构,只能使用一个WebSecurityConfigurer实例。

我们可以设计这样的东西: 1.使用此规则,我们可以让我们的父项目拥有此WebsecurityConfigurer实例。 2.我们可以让IBaseSecurityConfig具有上述3种方法签名。 3.我们将忽略任何其他WebsecurityConfigurer实例,仅允许父级WebsecurityConfigurer实例。 4.我们可以将IBaseSecurityConfig的抽象实现作为BaseSecurityConfig。

就像Spring在我们身上强制使用WebsecurityConfigurer一样,您可以在项目模块上强制BaseSecurityConfig覆盖任何与Security相关的配置。

我将尝试举例说明。

public interface IBaseSecurityConfig {

    void configure(AuthenticationManagerBuilder auth) throws Exception;
    void configure(WebSecurity web) throws Exception;
    void configure(HttpSecurity http) throws Exception;

}


@Configuration
public abstract class BaseSecurityConfig implements IBaseSecurityConfig {

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        // TODO Any defaults

    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // TODO Any defaults

    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // TODO Any defaults

    }
}

现在,我们将通过扩展BaseSecurityConfig来声明我们的安全配置。可以说我们声明了WebSecurityConfiguration1如下。

@Configuration
public class WebSecurityConfiguration1 extends BaseSecurityConfig {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/css/**", "/js/**", "/admin/**").permitAll().anyRequest().authenticated()
                .and()
                .addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class)
                .formLogin().loginPage("/login").permitAll().and().logout().logoutSuccessUrl("/");
    }
}

现在,我们将在其他任何地方声明一个单独的安全配置。让我们称之为WebSecurtiyConfiguration2。

@Configuration
public class WebSecurtiyConfiguration2 extends BaseSecurityConfig {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        IsSecureFilter i1 = new IsSecureFilter();
        http.addFilterBefore(i1, ChannelProcessingFilter.class);
    }
}

现在,我们必须自动配置以上声明的两个安全配置。我们将在父项目中执行此操作,或者您可以说,我们将在SecurityConfig的实际实例中将它们配置为如下所示。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    private List<IBaseSecurityConfig> securityConfigs;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        for(IBaseSecurityConfig secConfig : securityConfigs) {
            secConfig.configure(auth);          
        }
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        for(IBaseSecurityConfig secConfig : securityConfigs) {
            secConfig.configure(web);
        }

    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        System.out.println("CONFIGURING FROM BASE");
        for(IBaseSecurityConfig secConfig : securityConfigs) {
            secConfig.configure(http);
        }
    }
}

现在这是我们的应用程序加载类。 我们将必须确保没有其他WebSecurityConfigurerAdapter加载并且仅加载我们的父实例。我们通过@ Component->排除过滤器来实现。在@Import的帮助下,将确保仅加载我们的实例。

@SpringBootApplication
@EnableCaching
@ComponentScan(excludeFilters = @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,classes=WebSecurityConfigurerAdapter.class))
@Import(SecurityConfig.class)
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

现在,您已经通过仅扩展BaseSecurityConfig来强制体系结构声明任何安全配置,并且可以在其他位置进行此操作。

但是请注意,如果发生冲突,这可能会覆盖彼此的配置。