在 Spring Boot 中使用多个 WebSecurityConfigurerAdapter

Posted

技术标签:

【中文标题】在 Spring Boot 中使用多个 WebSecurityConfigurerAdapter【英文标题】:Using multiple WebSecurityConfigurerAdapter in spring boot 【发布时间】:2014-11-24 16:39:40 【问题描述】:

我有 2 个类扩展 WebSecurityConfigurerAdapter。并且不能让它们一起工作。

思路如下:

    有一个WebSecurityConfigurerAdapter,它只会将自定义过滤器添加到安全链中。过滤器执行一些自定义身份验证并将Authentication 保存到SecurityContext 中。这通常工作正常。配置如下(省略导入):
 @Order(1)
 @Configuration
 @EnableWebMvcSecurity
 public class BestSecurityConfig extends WebSecurityConfigurerAdapter 

     @Autowired
     private BestPreAuthenticationFilter ssoAuthenticationFilter;

     @Bean
     protected FilterRegistrationBean getSSOAuthenticationFilter() 
         FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(ssoAuthenticationFilter);

         // Avoid include to the default chain
         filterRegistrationBean.setEnabled(false);

         return filterRegistrationBean;
     

     @Override
     protected void configure(HttpSecurity http) throws Exception 
         http
            .addFilterAfter(ssoAuthenticationFilter, SecurityContextPersistenceFilter.class);

     

     @Configuration
     protected static class AuthenticationConfiguration extends
             GlobalAuthenticationConfigurerAdapter 

         @Autowired
         private BestAuthenticationProvider authenticationProvider;

         @Override
         public void configure(AuthenticationManagerBuilder auth) throws Exception 
             auth.authenticationProvider(authenticationProvider);
         
     
 
    我希望上面的库类是任何人都可以通过@ComponentScan 包含的库类,并对自定义身份验证进行排序。显然,他们希望提供自定义 HttpSecurity 来保护 edpoints。尝试类似:
 @Configuration
 @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
 @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
 public class SecurityConfig extends WebSecurityConfigurerAdapter 

     @Override
     protected void configure(HttpSecurity http) throws Exception 
         http
             .csrf().disable()
             .authorizeRequests()
             .antMatchers("/testUrl").hasRole("NON_EXISTING")
             .anyRequest().authenticated();
     
 

由于我的用户不是角色NON_EXISTING 的成员,因此测试 URL 显然不可访问。不幸的是,她是。

如果我将安全 authorizeRequests() 部分移动到配置类表单 1。在添加安全过滤器旁边,它会按预期阻止访问。但在我的情况下,第二个配置似乎被忽略了。

我还调试了configure() 方法并注意到HttpSecurity 不是同一个对象,它有点味道。

任何提示我如何使这项工作非常受欢迎。

目标总结:

有一个WebSecurityConfigurerAdapter,它添加了过滤器并且对库的用户隐藏 让用户定义自己的自定义端点安全

Spring boot 1.1.6-RELEASE

【问题讨论】:

在 XML 中拥有多个 WebSecurityConfigurerAdapter 与拥有多个 http 元素相同。所以它们没有合并为一个,而是分开使用。 是的,这不是我现在所理解的。任何提示如何解决这个问题?将尝试扩展BestSecurityConfig 覆盖configure() 并删除@Configuration ...让我们看看:) ... 它有效。我只是想知道它是否正确 @M. Deinum @ Jan Zyka 我有同样的问题。调试显示我的过滤器已注册。但它被忽略了。我想了解 xml 中的 http 元素是什么意思。我得到了 web.xml 参考,但是:/ 【参考方案1】:

定义一个特殊的接口

public interface ServiceWebSecurityConfigurer 
    void configure(HttpSecurity http) throws Exception;

那么就只有一个ConfigurerAdapter:

public class MyConfigurerAdapter extends WebSecurityConfigurerAdapter 

    @Autowired(required = false)
    ServiceWebSecurityConfigurer serviceSecConfig;

    public void configure(HttpSecurity http) throws Exception 
        http.authorizeRequests(). // whatever

        if (serviceSecConfig != null) serviceSecConfig.configure(http);

        http.authorizeRequests(). // whatever
    

然后在需要时在其他地方实现 ServiceWebSecurityConfigurer。也可以有多种实现,只需将它们自动装配为列表并迭代并在主配置中使用它们。

【讨论】:

是的,这很好,我也用过几次,它符合弹簧配置器的概念。 爱它。比AbstractHttpConfigurer 效果更好,因为它似乎忽略了某些设置。 经过多年的尝试/错误/忘记这一点并再次找到它,我相信这是最好的答案。 如何在游戏中加入 AuthenticationManager?我有两个 WebSecurityConfigurerAdapter,其中一个需要 AuthenticationManager。如果我按照建议添加 WebSecurityConfigurerAdapter 并在其实现中覆盖 authenticationManagerBean() ,则当我将 AuthenticationManager 注入实现 ServiceWebSecurityConfigurer 的 bean 时,我会得到循环依赖。 @homaxto well.. 例如,您可以更改接口以将 httpsecurity 和 authenticationmanager 作为参数。但是如果你有很多这样的东西,它很容易变得混乱【参考方案2】:

所以我刚刚找到的一个选项是:

    从第一个 bean 中删除 @Configuration 注释

并将 2. 更改为:

 @Configuration
 @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
 @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
 public class SecurityConfig extends BestSecurityConfig  //Note the changed extend !

     @Override
     protected void configure(HttpSecurity http) throws Exception 

         super.configure(http); // Merge of the 2 HTTP configurations

         http
             .csrf().disable()
             .authorizeRequests()
             .antMatchers("/testUrl").hasRole("NON_EXISTING")
             .anyRequest().authenticated();
     
 

非常感谢任何关于这种方法是对还是错的方法

编辑:几年后我仍然没有找到其他方式,但我越来越喜欢这种方式。即使在默认情况下,您扩展抽象 WebSecurityConfigurerAdapter 也没有理由为什么其他抽象层不能提供另一个提供有意义的默认值的抽象扩展。

【讨论】:

你现在有一个WebSecurityConfigurerAdapter,所以它可以工作,但需要扩展而不是自动检测。 是的,这就是我应该如何完成这样的任务吗?或者我应该以不同的方式使用它以及如何使用它? 我认为您使用扩展提出的解决方案非常好。【参考方案3】:

我(在我看来)创建了一种更简洁的方式来构建一些默认配置,并使用 Custom DSLs 简化了新项目的集成。

我正在使用它来配置 JWT 身份验证过滤器,但我认为 CORS 过滤器更简单且具有指导意义:

public class CustomCorsFilterDsl extends AbstractHttpConfigurer<CustomCorsFilterDsl, HttpSecurity> 

    @Override
    public void init(HttpSecurity http) throws Exception 
        //your init code here, no needed in this case
    

    @Override
    public void configure(HttpSecurity http) throws Exception 
        CorsFilter corsFilter = corsFilter(corsProperties);
        http.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class);
    

    private CorsFilter corsFilter(CorsProperties corsProperties) 
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://localhost:9000");
        config.addAllowedHeader("*");
        config.addAllowedMethod("GET, POST, PUT, PATCH, DELETE");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    

    public static CustomCorsFilterDsl dsl() 
        return new CustomCorsFilterDsl();
    

在您的 WebSecurityConfig 中,您可以像这样使用它:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http
                .csrf().disable()
                .exceptionHandling()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/foo/**").permitAll()
                //... your configurations
                .antMatchers("/**").authenticated()
                .and()
                .apply(CustomCorsFilterDsl.dsl());
    

并且您以更清晰的方式实现了使库具有独立于项目代码的默认配置的目标,因为您可以在项目的 WebSecurityConfig 中可视化自定义 CORS 条目。

【讨论】:

酷,所以你基本上是说AbstractHttpConfigurer 将通过组件扫描被发现并应用,对吗?干得好! 在示例中您不需要将CustomCorsFilterDsl 声明为组件,因为您正在使用静态方法创建实例:CustomCorsFilterDsl.dsl()。但我想你可以通过在 Dsl 上使用 @Component 和通过 @ComponentScan 来完成相同的行为 我喜欢这种方法,但是您如何将其合并到使用 @Enable... 的外部库中?我们有一个内部库,它使用@EnableJWTAuthentication 设置 JWT 过滤器。它需要在HttpSecurity 中注入这些过滤器。不知何故,我觉得这种方法可以完全控制HttpSecurity 给用户,但另一方面我觉得如果有人使用注释,他们可能知道它的作用(好吧实际上通常情况并非如此......但理论上应该是)。 我设法编写了类似的代码并使用了另一个从 AbstractHttpConfigurer 扩展的类,并像这样使用它:CustomJwtAuthFilter .apply(CustomJwtAuthFilter.dsl().skipPaths("/public/**").skipPaths("/anotherPublic/**");。在评论中详细解释有点困难,但如果您需要更多信息,我可以提供。 您的解决方案对我来说很好,但您似乎只能添加过滤器,因为我尝试设置其他内容,如会话或 authenticationEntrypoint,而这些设置被忽略。看来我不是唯一一个遇到这个问题的人:***.com/questions/44818399/…

以上是关于在 Spring Boot 中使用多个 WebSecurityConfigurerAdapter的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring Boot 中使用多个 WebSecurityConfigurerAdapter

使用spring boot在mongodb中进行多个搜索查询

使用spring-boot在多个数据库之间进行数据迁移

在命令行 Spring Boot 中传递多个参数

如何在 Spring Boot JPA 中使用多个 json 数组?

如何在spring boot的多个类中使用@Autowired MongoTemplate