1

当向 HttpSecurity 配置方法添加多个过滤器时,它们似乎是重叠的,因为当时只有一个有效。

这是配置方法:

@Override
public void configure(HttpSecurity http) throws Exception {
    http
            .logout().and().antMatcher("/**")
            .addFilterBefore(ssoFilter(), RequestHeaderAuthenticationFilter.class)
            .authenticationProvider(preauthAuthProvider())
            .authorizeRequests()
            .antMatchers("/index.html", "/home.html", "/", "/login").permitAll()
            .anyRequest().authenticated().and().csrf()
            .csrfTokenRepository(csrfTokenRepository()).and()
            .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
}

我试图指定顺序,但问题仍然存在:

@Bean
public FilterRegistrationBean securityFilterChain(@Qualifier(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) Filter securityFilter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(securityFilter);
    registration.setOrder(Integer.MAX_VALUE - 2);
    registration.setName(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
    return registration;
}

@Bean
public FilterRegistrationBean ssoFilterRegistrationBean() throws Exception {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    registrationBean.setFilter(ssoFilter());
    registrationBean.setOrder(Integer.MAX_VALUE-1);
    return registrationBean;
}

@Bean
public FilterRegistrationBean csrfFilterRegistrationBean() throws Exception {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    registrationBean.setFilter(csrfHeaderFilter());
    registrationBean.setOrder(Integer.MAX_VALUE);
    return registrationBean;
}

我按照以下线程没有成功。

spring-boot中的过滤顺序

https://github.com/spring-projects/spring-boot/issues/1640

https://github.com/spring-projects/spring-boot/issues/677

任何帮助将不胜感激!

更新:

CSRF 过滤器定义

private Filter csrfHeaderFilter() {
    return new OncePerRequestFilter() {
        @Override
        protected void doFilterInternal(HttpServletRequest request,
                                        HttpServletResponse response, FilterChain filterChain)
                throws ServletException, IOException {
            CsrfToken csrf = (CsrfToken) request
                    .getAttribute(CsrfToken.class.getName());
            if (csrf != null) {
                Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
                String token = csrf.getToken();
                if (cookie == null
                        || token != null && !token.equals(cookie.getValue())) {
                    cookie = new Cookie("XSRF-TOKEN", token);
                    cookie.setPath("/");
                    response.addCookie(cookie);
                }
            }
            filterChain.doFilter(request, response);
        }
    };
}

SSO 过滤器定义:

public class SSORequestHeaderAuthenticationFilter extends RequestHeaderAuthenticationFilter {

private boolean allowPreAuthenticatedPrincipals = true;

public SSORequestHeaderAuthenticationFilter() {
    super();
    //TODO Pull this value from a properties file (application.properties, or localstrings.properties)
    //NOTE SM_USER is the default, but you can change it like this (your company may use some other header)
    //this.setPrincipalRequestHeader("SM_USER");
}


@Override
public void doFilter(ServletRequest request, ServletResponse response,
                     FilterChain chain) throws IOException, ServletException {
    chain.doFilter(request, response);
}

/**
 * This is called when a request is made, the returned object identifies the
 * user and will either be {@literal null} or a String. This method will throw an exception if
 * exceptionIfHeaderMissing is set to true (default) and the required header is missing.
 *
 * @param request {@link javax.servlet.http.HttpServletRequest}
 */
@Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
    String userName = (String) (super.getPreAuthenticatedPrincipal(request));
    if (userName == null || userName.trim().equals("")) {
        return userName;
    }

    return userName;
}

public boolean isAllowPreAuthenticatedPrincipals() {
    return allowPreAuthenticatedPrincipals;
}
}
4

3 回答 3

0

执行您想要执行的操作的过滤器已经存在。它的OAuth2AuthenticationProcessingFilter. 如果您使用@EnableResourceServer. 如果您这样做,这将导致现在只有基于令牌的身份验证才能工作。您还必须设置此过滤器的无状态标志false以允许其他身份验证方式。

我所做的是创建一个ApiTokenAccessFilter扩展类OAuth2AuthenticationProcessingFilter。此过滤器采用ResourceServerTokenServices构造函数参数并将无状态标志设置为 false。

public class ApiTokenAccessFilter extends OAuth2AuthenticationProcessingFilter {

  public ApiTokenAccessFilter(ResourceServerTokenServices resourceServerTokenServices) {

    super();
    setStateless(false);
    setAuthenticationManager(oauthAuthenticationManager(resourceServerTokenServices));
  }

  private AuthenticationManager oauthAuthenticationManager(ResourceServerTokenServices tokenServices) {

    OAuth2AuthenticationManager oauthAuthenticationManager = new OAuth2AuthenticationManager();

    oauthAuthenticationManager.setResourceId("oauth2-resource");
    oauthAuthenticationManager.setTokenServices(tokenServices);
    oauthAuthenticationManager.setClientDetailsService(null);

    return oauthAuthenticationManager;
  }
}

在我的安全配置中,我使用了这个过滤器,如下所示:

@Configuration
@EnableOAuth2Sso
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

  @Autowired
  private ResourceServerTokenServices tokenServices;

  @Override
  public void configure(HttpSecurity http) throws Exception {

    http.authorizeRequests()
        .anyRequest()
        .authenticated()
        .and()
        .addFilterBefore(new ApiTokenAccessFilter(tokenServices), AbstractPreAuthenticatedProcessingFilter.class);
  }
}

我认为这可能更容易,所以我在spring-security-oauth Github repo上打开了一个问题。我不确定这个解决方案是否可行,但我没有找到另一种选择。

于 2016-02-03T17:29:55.713 回答
0

我的猜测是您并不总是在两个过滤器中执行FilterChain.doFilter方法。然后过滤器链停止,只执行您的一个自定义过滤器。在这个简单的例子中,两个过滤器都执行了:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .addFilterBefore(new Filter1(), RequestHeaderAuthenticationFilter.class)
                .addFilterAfter(new Filter2(), CsrfFilter.class)
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .httpBasic()
                .and()
                .logout()
                .permitAll();
    }

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

    static class Filter1 extends OncePerRequestFilter {
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            System.out.println("executed filter 1");
            filterChain.doFilter(request, response);
        }
    }

    static class Filter2 extends OncePerRequestFilter {
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            System.out.println("executed filter 2");
            filterChain.doFilter(request, response);
        }
    }

}
于 2016-01-30T11:18:32.367 回答
0

您混淆了容器注册(带有FilterRegistrationBean)和安全过滤器链中的注册(带有HttpSecurity),还可能与 Spring Security 中过滤器链的顺序混淆。如果 Spring Security 选择了给定的过滤器链,则其中的所有过滤器都不一定会被触发(过滤器总是可以关闭其他下游过滤器)。

我建议您停止担心您的订单FilterRegistrationBeans并使用它们来禁用容器注册(通过将其启用标志设置为 false)。然后考虑过滤器链的顺序,由@Order. WebSecurityConfigurers最后,您可以决定给定链中过滤器的顺序是否重要,以及它是否使用这些addFilter{Before,After}方法。

于 2016-01-30T18:22:31.537 回答