【问题标题】:Spring Custom Filter is always invoked始终调用 Spring 自定义过滤器
【发布时间】:2018-03-17 16:19:14
【问题描述】:

我有一个在 BasicAuthenticationFilter 之前调用的自定义过滤器,该 Bean 在 SecurityConfig 文件中自动装配。

.addFilterBefore(preAuthTenantContextInitializerFilter, BasicAuthenticationFilter.class)

这是过滤器的外观。

@Component
public class PreAuthTenantContextInitializerFilter extends OncePerRequestFilter {
    @Autowired
    private TenantService tenantService;
.....
.....

我希望这个过滤器不会像 Spring Security 过滤器链的其余部分一样触发 WebSecurityConfigurerAdapter#configure(WebSecurity web) web.ignoring() 中包含的路径。

这是它的样子

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources", 
                                    "/configuration/security", "/swagger-ui.html", 
                                    "/webjars/**","/swagger-resources/configuration/ui",
                                    "/swagge‌​r-ui.html", "/docs/**");
    }
}

我已经尝试过了。

从过滤器类中移除@Component注解,它只会阻止过滤器在任何情况下被调用,因为过滤器不再被选为bean并且永远不会进入过滤器链。

我在寻找什么

我希望在调用 Spring Security 链的其余部分时调用此过滤器,并像其余 Spring Security 过滤器一样忽略 web.ignoring() 中的路径。谢谢。

【问题讨论】:

  • 因为它是 Spring Boot 检测到的 bean 并将其添加到常规过滤器链中。由于OncePerRequestFilter 的扩展,它只会执行一次,基本上你的安全过滤器链中配置的条目什么都不做。要修复它,不要让它成为一个 bean 并自己连接依赖项。这样 Spring Boot 就不会检测到它,它只是 Spring Security 过滤器链的一部分,而不是常规的过滤器链。或者为过滤器添加一个FilterRegistrationBean,并将enabled设置为false,以防止它被自动注册。

标签: spring spring-mvc spring-boot spring-security


【解决方案1】:

作为 Spring bean 的任何 ServletFilterServlet *Listener 实例都将在嵌入式容器中注册。如果您想在配置期间引用 application.properties 中的值,这会特别方便。

这个 sn-p 来自 Spring Boot reference guide。基本上,在应用程序上下文中检测到的任何 Filter 都将注册到默认过滤器链并映射到 DispatcherServlet/

在您的情况下,由于过滤器被标记为@Component,它将是一个 bean,Spring Boot 检测到它并将其注册到嵌入式容器。但是,您不希望它成为 Spring Security 过滤器链的一部分。

为此,您有 2 个选项。

  1. 删除@Component@Autowired 并构建您自己的实例,不要使其成为bean。
  2. 添加一个额外的 [FilterRegistrationBean] 并将enabled 属性设置为false,这将阻止 Spring Boot 将其注册到嵌入式容器。

这里是选项 2 的解决方案:

@Bean
public FilterRegistrationBean preAuthTenantContextInitializerFilterRegistration(PreAuthTenantContextInitializerFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(filter);
    registration.setEnabled(false);
    return registration;
}

使用这个添加的 bean,Spring Boot 不会向嵌入式容器注册过滤器,因此它只会作为 Spring Security 过滤器链的一部分被调用。

【讨论】:

  • 谢谢。这是我错过的关键部分。因此,通过将过滤器注释为@Component,它会自动注册到底层容器过滤器链中,并且还会添加到 Spring 安全过滤器链中(如果您使用 addFilterBefore 或 addFilterAfter 手动添加它)所以现在该过滤器被调用了两次。
【解决方案2】:
  • 我认为您试图忽略加载 Swagger UI 页面的安全性。如果是这种情况,您需要将另一个路径 /swagger-resources/configuration/security 添加到您的忽略路径列表中。添加此路径后,当您调用任何被忽略的路径时,将不会调用您的 PreAuthTenantContextInitializerFilter
  • 另外,手动管理 PreAuthTenantContextInitializerFilter 的创建,而不是让 Spring 管理。这将涉及从您的过滤器中删除@Component。你可以找到一个工作示例here

    @Configuration
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
       private TenantService service;
    
       @Autowired
       public SecurityConfiguration(TenantService service) {
           this.service = service;
       }
    
       @Override
       protected void configure(HttpSecurity http) throws Exception {
           http.addFilterBefore(
               new PreAuthTenantContextInitializerFilter(service),
               BasicAuthenticationFilter.class);
           ...
       }
    
       @Override
       public void configure(WebSecurity web) throws Exception {
           web.ignoring().antMatchers("/v2/api-docs", 
                "/configuration/ui",
                "/swagger-resources",
                "/configuration/security", "/swagger-ui.html",
                "/webjars/**", "/swagger-resources/configuration/ui",
                "/swagge‌r-ui.html", "/docs/**",
                "/swagger-resources/configuration/security");
       }
    }
    

【讨论】:

    猜你喜欢
    • 2015-05-30
    • 1970-01-01
    • 2011-08-23
    • 2014-07-28
    • 1970-01-01
    • 2013-07-22
    • 2023-03-04
    • 2019-12-04
    • 2018-09-13
    相关资源
    最近更新 更多