spring-security 如何正确地为特定URL添加Spring Security过滤器?[duplicate]

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

此问题在此处已有答案

Filter invoke twice when register as Spring bean(2个答案)
上个月关门了。
我尝试将自定义过滤器仅添加到特定的URL,但是过滤器会应用到每个请求,而不管URL和方法如何,有人知道使用Spring Security的最新版本修复此问题的正确方法吗,即不使用WebSecurityConfigurerAdapter,因为它将是deprecated
这里有很多类似的问题,但它们要么对我不起作用,要么使用“旧”方法(如thisthis以及许多其他方法),或者两者都有。
我暴露了许多端点,它们都遵循以下模式:/api/**但是,我需要为特定端点提供一些身份验证:/api/some/url和一个特定的方法(在本例中为GET),如何正确地执行此操作?
注意:端点URL都在/api/*下(它们应该称为嵌套吗?)
我的安全配置如下所示:

@EnableWebSecurity
public class SecurityConfig {

    private MyFilter myFilter;

    public SecurityConfig(MyFilter pif) {
        myFilter = pif;
    }

    /**
     * Handling AuthZ & AuthN for most APIs. No AuthZ & AuthN.
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SecurityFilterChain defaultSecurity(HttpSecurity http) throws Exception {
        http.requestMatchers((requests) ->
                        requests.antMatchers("/"))
                .authorizeHttpRequests((authorize) -> authorize.anyRequest()
                        .permitAll());
        return http.build();
    }

    /**
     * Handling AuthZ & AuthN for GET /api/some/url.
     */
    @Bean
    public SecurityFilterChain keyApiSecurity(HttpSecurity http) throws Exception {
        http.requestMatchers((requests) -> requests
                        .antMatchers(HttpMethod.GET, "/api/some/url").and())
                .addFilterBefore(myFilter,
                        BasicAuthenticationFilter.class)
                .authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll());
        return http.build();
    }
}
jei2mxaa

jei2mxaa1#

当您在spring-boot中将一些GenericFilter实现公开为bean时,它会自动将其放入任何请求的公共过滤器链中,因为它不知道它是否是安全过滤器- * 它可能是日志记录过滤器或其他任何过滤器 *。
因此,将执行此过滤器Bean而不考虑spring-security
您的defaultSecurity过滤器链没有这个自定义过滤器,所以MyFilter将在spring安全过滤器链之后执行。
同时,keyApiSecurity过滤器链在BasicAuthenticationFilter之前设置这个自定义过滤器,因此它将在那里执行,并且不会第二次执行,因为OncePerRequestFilter s方法的基本doFilter()实现检查请求是否已经被过滤器过滤。
因此,如果您希望筛选器仅作为安全筛选器工作,则不应将其公开为bean,而应在安全筛选器链中设置它,如下所示:

.addFilterBefore(new MyFilter(), BasicAuthenticationFilter.class)

你也应该考虑为一个“默认”的安全过滤器链设置最低的优先级,因为如果它是第一个被选中的-其他的安全过滤器链将被完全忽略。所以我认为一些特定的过滤器安全链应该有更高的优先级。

编辑:

如果因为依赖于Filter实现中的bean注入而无法使用new操作符设置安全过滤器,则可以覆盖OncePerRequestFiltershouldNotFilter(HttpServletRequest request)方法,例如:

@Component
public class MyFilter extends OncePerRequestFilter {

    private final RequestMatcher uriMatcher = 
                        new AntPathRequestMatcher("/api/some/url", HttpMethod.GET.name());
    // some bean injection...

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        // filter logic here...
    }

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        RequestMatcher matcher = new NegatedRequestMatcher(uriMatcher);
        return matcher.matches(request);
    }
}

然后,它将只过滤匹配的请求,并将其放入安全过滤器链将设置其顺序。

相关问题