spring-security 从Web安全配置器适配器迁移到安全筛选器链

oprakyz7  于 2022-11-11  发布在  Spring
关注(0)|答案(1)|浏览(156)

以下是我在迁移前的工作安全配置:

@Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers("/auth/**")
                .antMatchers("/swagger-ui/**")
                .antMatchers("/swagger-ui.html")
                .antMatchers("/swagger-resources/**")
                .antMatchers("/v2/api-docs/**")
                .antMatchers("/v3/api-docs/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedPortalRoleConverter);

        http
                .csrf().disable()
                .cors()
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(new AuthenticationFallbackEntryPoint())
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests(authorize -> authorize.anyRequest().authenticated())
                .oauth2ResourceServer()
                .jwt().jwtAuthenticationConverter(jwtAuthenticationConverter);
    }

以下是我在迁移后的安全链配置:

@Bean
    @Order(1)
    public SecurityFilterChain ignorePathsSecurityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(authorize -> authorize
                        .antMatchers(
                                "/auth/**",
                                "/swagger-ui/**",
                                "/swagger-ui.html",
                                "/swagger-resources/**",
                                "/v3/api-docs/**")
                            .permitAll());

        return http.build();
    }

    @Bean
    @Order(2)   
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http, GrantedPortalRoleConverter grantedPortalRoleConverter) throws Exception {
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedPortalRoleConverter);

        http
                .csrf().disable()
                .cors(Customizer.withDefaults())
                .exceptionHandling(configurer -> configurer.authenticationEntryPoint(new AuthenticationFallbackEntryPoint()))
                .sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
                .oauth2ResourceServer(configurer -> configurer.jwt().jwtAuthenticationConverter(jwtAuthenticationConverter));

        return http.build();
    }

对于原始conf,当我调用一个随机的不存在路径时:

@Test
    void should_not_authenticate_or_return_not_found() throws Exception {
        logger.info("should_not_authenticate_or_return_not_found");

        mvc.perform(get("/toto/tata"))
                .andExpect(status().isUnauthorized());      
    }

我得到:

15:44:00.230 [main] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Failed to authorize filter invocation [GET /toto/tata] with attributes [authenticated]

有了新的配置文件,我只得到HTTP 404,请问我在这里错过了什么?我看不到任何区别,调试日志也没有显示太多。
下面是使用非工作配置时日志丢失的第一行:

16:24:58.651 [main] DEBUG o.s.s.w.a.e.ExpressionBasedFilterInvocationSecurityMetadataSource - Adding web access control expression [authenticated] for any request

但在两个日志中,我可以看到(新配置有两行,因为有两个安全链):

o.s.s.web.DefaultSecurityFilterChain - Will secure any request with (...)
c9x0cxw0

c9x0cxw01#

说明

当您有多个SecurityFilterChain时,您必须指定一个请求匹配器,否则所有请求将由第一个SecurityFilterChain(用@Order(1)注解)处理,并且永远不会到达第二个SecurityFilterChain(用@Order(2)注解)。
在上面共享的代码中,这意味着在ignorePathsSecurityFilterChain中配置.requestMatchers()

@Bean
@Order(1)
public SecurityFilterChain ignorePathsSecurityFilterChain(HttpSecurity http) throws Exception {
    http
        .requestMatchers(requests -> requests // add this block
            .antMatchers(
                "/auth/**",
                "/swagger-ui/**",
                "/swagger-ui.html",
                "/swagger-resources/**",
                "/v3/api-docs/**")
        )
        .authorizeHttpRequests(authorize -> authorize
            .antMatchers(
                "/auth/**",
                "/swagger-ui/**",
                "/swagger-ui.html",
                "/swagger-resources/**",
                "/v3/api-docs/**")
            .permitAll());

    return http.build();
}

这意味着只有与/auth/**/swagger-ui/**等匹配的请求将由ignorePathsSecurityFilterChain处理,而其余请求将移动到defaultSecurityFilterChain
要了解requestMatchersauthorizeHttpRequests之间的区别,您可以查看此StackOverflow问题。

解决方案

一个更好的选择是将SecurityFilterChain组合成一个单独的。我看不出在这种情况下有什么理由要将它们分开。
生成的配置为:

@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http, GrantedPortalRoleConverter grantedPortalRoleConverter) throws Exception {
    JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
    jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedPortalRoleConverter);

    http
            .authorizeHttpRequests(authorize -> authorize
                    .antMatchers(
                            "/auth/**",
                            "/swagger-ui/**",
                            "/swagger-ui.html",
                            "/swagger-resources/**",
                            "/v3/api-docs/**")
                    .permitAll()
                    .anyRequest().authenticated()
            )
            .csrf().disable()
            .cors(Customizer.withDefaults())
            .exceptionHandling(configurer -> configurer.authenticationEntryPoint(new AuthenticationFallbackEntryPoint()))
            .sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .oauth2ResourceServer(configurer -> configurer.jwt().jwtAuthenticationConverter(jwtAuthenticationConverter));

    return http.build();
}

替代

或者,您可以使用WebSecurityCustomizer来忽略某些端点:

@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
    return (web) -> web.ignoring().antMatchers(
                "/auth/**",
                "/swagger-ui/**",
                "/swagger-ui.html",
                "/swagger-resources/**",
                "/v3/api-docs/**");
}

然后,您将使用defaultSecurityFilterChain作为唯一的SecurityFilterChain

相关问题