同一路径回退到 SAML2 的 JWT 身份验证

JWT authentication with fallback to SAML2 for the same path

我在我的 spring 启动应用程序之一中使用 spring-security-saml2-service-provider 进行身份验证,并且我使用自定义 JwtAuthorizationFilter(通过 http 身份验证 header)在不同的 spring 启动应用程序中。

它们都可以完美地独立工作。

现在我需要编写一个 spring 启动应用程序来使用它们。如果 JWT 令牌可用(身份验证 header),则使用 JwtAuthorizationFilter,否则使用 saml2Login.

SAML2 配置如下所示:(无过滤器,只有 saml2Login

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
            .antMatcher("/**").authorizeRequests()
            .antMatchers("/saml2/service-provider-metadata/**").permitAll()
            .antMatchers("/**").authenticated().and()

            // use SAML2
            .saml2Login()
            .addObjectPostProcessor(new ObjectPostProcessor<OpenSamlAuthenticationProvider>() {
                public <O extends OpenSamlAuthenticationProvider> O postProcess(O samlAuthProvider) {
                    samlAuthProvider.setAuthoritiesExtractor(authoritiesExtractor());
                    samlAuthProvider.setAuthoritiesMapper(authoritiesMapper());
                    return samlAuthProvider;
                }
            })
        ;
    }

JWT 配置如下所示:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
            .antMatcher("/**").authorizeRequests()
            .antMatchers("/**").authenticated().and()

            // use JWT
            .addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtUtil))
        ;
    }

我想我需要类似 JwtOrSaml2AuthenticationFilter 的东西,但不知道该怎么做。

解决方法是

  1. 使用@Order 和
  2. 复制配置
  3. 在addFilter

    之前设置一个基于header的requestMatcher
    @EnableWebSecurity
    public class SecurityConfiguration {
        @Order(100) // lower number = higher priority
        @Configuration
        @RequiredArgsConstructor
        public static class AppSecurityJWT extends WebSecurityConfigurerAdapter {
            final JWTUtil jwtUtil;
    
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
                    .antMatcher("/**").authorizeRequests()
                    .antMatchers("/saml2/service-provider-metadata/**", "/idm-app/**").permitAll()
                    .antMatchers("/**").authenticated().and()
    
                    // This configuration will only be active if the Authorization header is present in the request
                    .requestMatcher(new RequestHeaderRequestMatcher("Authorization")).addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtUtil))
                ;
            }
        }
    
        @Order(101)
        @Configuration
        @RequiredArgsConstructor
        public static class AppSecuritySAML2 extends WebSecurityConfigurerAdapter {
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                    .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
                    .antMatcher("/**").authorizeRequests()
                    .antMatchers("/saml2/service-provider-metadata/**", "/idm-app/**").permitAll()
                    .antMatchers("/**").authenticated().and()
    
                    // This whole configuration will only be active, if the previous (100) didn't match
                    .saml2Login()
                    //...
            ;
        }
    }