添加要在Servlet 3+环境中的spring-security过滤器之后调用的自定义过滤器

时间:2014-06-23 11:11:44

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

我正在使用Spring-Security 3.2.4和Spring Boot 1.1.0(以及相关的依赖版本4.X)。 我正在编写一个将在嵌入式tomcat中运行的Web应用程序。

我正在尝试添加两个额外的过滤器(与Spring安全无关),其中一个将在Spring-Security-FilterChainProxy之前调用,另一个将在Spring-Security-FilterChainProxy之后调用。

我的Spring-Security配置文件:

@Configuration
@EnableWebMvcSecurity
public class SecurityCtxConfig extends WebSecurityConfigurerAdapter {

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth
    .inMemoryAuthentication()
        .withUser("user").password("pass").roles("USER");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf()
            .disable()
            .authorizeRequests()
            .anyRequest()
            .authenticated()
            .and()
            .formLogin()
            .usernameParameter("user").passwordParameter("password");
}
}

Main类(Application.class):

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

    @Bean
RequestFilter beforeSpringSecurityFilter(){
    return new RequestFilter();
}

@Bean
RequestFilter afterSpringSecurityFilter(){
    return new RequestFilter();
}

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

Filter实现:

public class RequestFilter extends OncePerRequestFilter {

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
        FilterChain filterChain) throws ServletException, IOException {
        filterChain.doFilter(request, response);
}

}

在考虑FilterChainProxy(由WebSecurityConfigurerAdapter创建?)时,有没有办法控制调用顺序? 为了做到这一点,所需的订单是:

  1. 请求滤波器-1
  2. Spring-Security FilterChain
  3. 请求滤波器-2
  4. 由于

4 个答案:

答案 0 :(得分:8)

同意Dave Syer所述的所有内容;)但希望添加使用FilterRegistrationBean的Java Config示例。

在我的情况下,我发现我的自定义安全过滤器(使用Spring Security)每次请求都被触发两次。添加FilterRegistrationBean配置修复此问题。

    @Bean(name = "myFilter")
    public MyAuthenticationFilter myAuthenticationFilter(final MyAuthenticationEntryPoint entryPoint) {
        final MyAuthenticationFilter filter = new MyAuthenticationFilter();
        filter.setEntryPoint(entryPoint);
        return filter;
    }

    /**
     *  We do this to ensure our Filter is only loaded once into Application Context
     *
     */
    @Bean(name = "authenticationFilterRegistration")
    public FilterRegistrationBean myAuthenticationFilterRegistration(final MyAuthenticationFilter filter) {
        final FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(filter);
        filterRegistrationBean.setEnabled(false);
        return filterRegistrationBean;
    }

(关于我在应用程序上下文中两次注册过滤器的具体问题 - 我还发现重新实现FilterRegistrationBean继承自MyAuthenticationFilter而不是OncePerRequestFilter {1}}也有效。但是,GenericFilterBean支持来自Servlet 3.x以上,因为我正在编写公共库,可能需要来自Servlet 2.x的支持。)

答案 1 :(得分:5)

Spring Security使用的FilterChainProxy不是Ordered(如果您可以订购所有过滤器)。但是您应该能够在<{1>} FilterRegistrationBean中注册它,并以相同的方式注册其他过滤器。对于安全过滤器,您可以按名称将其注入注册bean。您可以通过调用Ordered方法注入其他人。

答案 2 :(得分:0)

如果您使用的是web.xml方法,则可以遵循以下步骤: https://stackoverflow.com/a/11929129/1542363

如果您使用Java配置方法,则可以在WebSecurityConfigurerAdapter

中执行此操作
@Override
protected void configure(HttpSecurity http) throws Exception {

    http.addFilterBefore(your-request-filter-1, ChannelProcessingFilter.class);
    http.addFilterAfter(your-request-filter-2, SwitchUserFilter.class);

}

始终检查您使用的库版本,并参考特定文档以获取正确的过滤器链顺序:

https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#ns-custom-filters

或者,如果您使用AbstractSecurityWebApplicationInitializer,则可以使用insertFiltersappendFilters

public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
        insertFilters(servletContext, new MultipartFilter());
    }
}

更多信息您可以参考以下内容: https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#csrf-multipart

答案 3 :(得分:0)

在某些时候,spring boot 将安全过滤器作为一个属性公开。现在这很容易做到。

在你的 application.yml 中:

  spring:
    security:
      filter:
        order: 20

还有一些你想在 Spring Security 完成它之后调用的过滤器:

@Bean
public FilterRegistrationBean<Filter> afterAuthFilterRegistrationBean() {
    FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
    //a filter that extends OncePerRequestFilter
    AfterAuthFilter afterAuthFilter = new AfterAuthFilter();
    registrationBean.setFilter(afterAuthFilter);
    //this needs to be a number greater than than spring.security.filter.order
    registrationBean.setOrder(30);
    return registrationBean;
}

对于在 Spring security 之前执行的过滤器,将 order 设置为小于 20 的数字。