0

在 Spring Boot 2.0.3 应用程序中,我想根据请求路径应用多种身份验证方法。

预期行为

对于请求匹配;

  • /静止的/**
    • 不要应用任何身份验证过滤器,允许所有
  • /安全的/**
    • 期望并验证客户端证书
  • /api/**
    • 通过 HTTP Basic 或 HTTP Digest 进行身份验证

观察到的行为

无论我请求哪个 URL,所有身份验证过滤器始终按以下顺序应用;

  1. X509AuthenticationFilter
  2. 基本身份验证过滤器
  3. CustomDigestAuthenticationFilter

过滤器按预期工作,我使用任何方法进行身份验证都没有问题。但在某些边缘情况下,应用整个 FilterChain 会导致问题,例如,如果 Web 浏览器缓存了 Authorization 标头,则 Web 浏览器不会要求客户端证书。

所以主要问题是;如何将不同的过滤器隔离到其特定的请求域?

更新/编辑

从Spring Security 的多个 url 规则集不一起工作 Spring Security Reference跟随输入。不幸的是,这种行为也适用于这种方法。

WebSecurityConfig 类

@EnableWebSecurity
public class WebSecurityConfig {

    private final CertificateAuthenticationProvider certificateAuthenticationProvider;
    private final CustomBasicAuthenticationProvider customBasicAuthenticationProvider;

    @Autowired
    public WebSecurityConfig(CertificateAuthenticationProvider certificateAuthenticationProvider, CustomBasicAuthenticationProvider customBasicAuthenticationProvider) {
        this.certificateAuthenticationProvider = certificateAuthenticationProvider;
        this.customBasicAuthenticationProvider = customBasicAuthenticationProvider;
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(certificateAuthenticationProvider);
        auth.authenticationProvider(customBasicAuthenticationProvider);
    }

    @Configuration
    @Order(1)
    public static class SecureTestbedWebConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http    .antMatcher("/secure/**").authorizeRequests().anyRequest().authenticated()
                    .and().x509().x509AuthenticationFilter(x509AuthenticationFilter())
                    .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
        }

        @Bean
        public CustomX509AuthenticationFilter x509AuthenticationFilter() {
            CustomX509AuthenticationFilter customX509AuthenticationFilter = new CustomX509AuthenticationFilter();
            customX509AuthenticationFilter.setAuthenticationManager(authenticationManager());
            return customX509AuthenticationFilter;
        }

        @Bean
        @Override
        protected AuthenticationManager authenticationManager() {
            try {
                return super.authenticationManager();
            } catch (Exception ex) {
                throw new IllegalStateException("Failed to extract AuthenticationManager.", ex);
            }
        }
    }

    @Configuration
    @Order(2)
    public static class ApiAuthenticationConfigurationAdapter extends WebSecurityConfigurerAdapter {

        private final CustomBasicAuthenticationEntryPoint customBasicAuthenticationEntryPoint;
        private final AccessDao accessDao;

        @Autowired
        public ApiAuthenticationConfigurationAdapter(CustomBasicAuthenticationEntryPoint customBasicAuthenticationEntryPoint, AccessDao accessDao) {
            this.customBasicAuthenticationEntryPoint = customBasicAuthenticationEntryPoint;
            this.accessDao = accessDao;
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http    .antMatcher("/api/**")
                    .requestMatcher(new BasicRequestMatcher())
                    .authorizeRequests().anyRequest().authenticated()
                    .and().httpBasic().authenticationEntryPoint(customBasicAuthenticationEntryPoint)
                    .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
                    .and().addFilterAfter(customDigestAuthenticationFilter(), BasicAuthenticationFilter.class);
        }

        @Bean
        public CustomDigestAuthenticationFilter customDigestAuthenticationFilter() {
            return new CustomDigestAuthenticationFilter(accessDao);
        }
    }

    @Configuration
    @Order(3)
    public static class NoAuthenticationNeededConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http    .antMatcher("/static/**").authorizeRequests()
                    .antMatchers(HttpMethod.GET).permitAll();
        }
    }

    private static class BasicRequestMatcher implements RequestMatcher {
        @Override
        public boolean matches(HttpServletRequest request) {
            String auth = request.getHeader("Authorization");
            boolean isMatching = auth != null && (auth.startsWith("Basic") || auth.startsWith("Digest"));
            log.debug("HTTP {} {}, isMatching; {}", request.getMethod(), request.getRequestURI(), isMatching);
            return isMatching;
        }
    }
}
4

0 回答 0