【问题标题】:AbstractAuthenticationProcessingFilter triggered no matter what SecurityFilterChain it is a part ofAbstractAuthenticationProcessingFilter 触发,无论它属于哪个 SecurityFilterChain
【发布时间】:2020-12-08 22:23:48
【问题描述】:

我正在尝试使用 spring security 并遇到了一个奇怪的行为。 我的想法是创建一个基于 JWT(或 JWS)令牌对请求进行身份验证的安全过滤器:

public class JWTokenFilter extends AbstractAuthenticationProcessingFilter {

    public JWTokenFilter(AuthenticationManager authenticationManager) {
        super("/**"); //doesn't have any effect, every request still gets considered by this filter
        setAuthenticationManager(authenticationManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        String token = request.getHeader("Authorization");
        if (!StringUtils.hasText(token)) {
            throw new TokenException("Token is empty");
        }
        var authentication = determineAuthentication(token.replace("Bearer","").trim());
        //the AbstractAuthenticationProcessingFilter fills the Security context
        return this.getAuthenticationManager().authenticate(authentication);
    }

    @Override
    protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("Asked for "+request.getRequestURI());
        return request.getHeader("Authorization") != null;
    }


    private TokenAuthentication<UserInfo> determineAuthentication(String token) {
        var split = token.split("\\.");
        if (split.length < 2 || split.length > 3) {
            throw new TokenException("Token malformed");
        }
        if (split.length == 2){
            return new JWTAuthentication<>(token);
        }else {
            return new JWSAuthentication<>(token);
        }
    }

}

我有 3 个 @RestController 类,它们的路径已映射:

  1. @RequestMapping("/admin")
  2. @RequestMapping("/all")
  3. @RequestMapping("/anon")

除此之外,我还有以下安全配置:

@Configuration
@Order(98)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.requestMatchers()
                .antMatchers("/all/**","/anon/**")
                .and()
                .authorizeRequests().antMatchers("/all/**").permitAll()
                .and()
                .authorizeRequests().antMatchers("/anon/**").anonymous();
    }

    @Override
    public void configure(WebSecurity web) {
        web.ignoring().mvcMatchers("/webjars/**", "/css/**");
    }



    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Configuration
    @Order(99)
    public static class TokenSecurityConfig extends WebSecurityConfigurerAdapter{

        @Lazy
        @Autowired
        private JWTokenFilter tokenFilter;

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests() //having /admin/** or /** makes no difference
                    .anyRequest().authenticated()
                    .and().addFilterBefore(tokenFilter,ExceptionTranslationFilter.class);//put this filter near the end of the chain
        }

        @Bean
        public JWTokenFilter tokenFilter(JWTokenAuthenticationProvider jwTokenAuthenticationProvider,JWSTokenAuthenticationProvider jwsTokenAuthenticationProvider){
            var list = new ArrayList<AuthenticationProvider>();
            list.add(jwsTokenAuthenticationProvider);
            list.add(jwTokenAuthenticationProvider);
            ProviderManager manager = new ProviderManager(list);
            return new JWTokenFilter(manager);
        }
    }
}

从这里的配置我们可以看到有2个SecurityFilterChans(不包括/webjars/css):

  1. 匹配"/all/**""/anon/**" REST 路由的所有请求
  2. 匹配任何请求

由于 1. 链的 @Order(98) 低于 2. @Order(99),这意味着 1.将首先考虑,如下所示调试器,

如果传入请求如下所示匹配:

curl --request GET \
  --url http://localhost:8080/all/hello \

现在我遇到的是 JWTokenFilter 方法 boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) 无论请求路径如何,都会被调用! 在控制台输出中,我可以找到Asked for /all/hello

编辑: 我的spring boot版本是2.3.6.RELEASE


我的问题是:

为什么JWTokenFIlter 甚至被问到它是否应该对路径与SecurityFilterChain 不匹配的请求进行身份验证?

【问题讨论】:

    标签: spring-boot spring-mvc spring-security


    【解决方案1】:

    我相信我有更好的答案,但我也想回答你原来的问题。我把它分成两部分。

    改进的答案

    我意识到这并不能回答最初的问题,但我认为您最好使用对基于 JWT 的身份验证的内置支持。我会查看参考文档的OAuth 2.0 Resource Server 部分。

    原始问题的答案

    Spring Boot will automatically register 任何 Filter 暴露为 @Bean,用于直接使用 Servlet 容器的每个请求。

    我看到你有两个选择。首先是避免将JwtTokenFilter 暴露为@Bean

    @Configuration
    @Order(99)
    public static class TokenSecurityConfig extends WebSecurityConfigurerAdapter{
        @Autowired
        JWTokenAuthenticationProvider jwTokenAuthenticationProvider;
    
        @Autowired
        JWSTokenAuthenticationProvider jwsTokenAuthenticationProvider;
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests() //having /admin/** or /** makes no difference
                    .anyRequest().authenticated()
                    .and().addFilterBefore(tokenFilter(),ExceptionTranslationFilter.class);//put this filter near the end of the chain
        }
    
        
        public JWTokenFilter tokenFilter(){
            var list = new ArrayList<AuthenticationProvider>();
            list.add(jwsTokenAuthenticationProvider);
            list.add(jwTokenAuthenticationProvider);
            ProviderManager manager = new ProviderManager(list);
            return new JWTokenFilter(manager);
        }
    }
    

    或者,您可以继续将JwtTokenFilter 公开为@Bean 并创建FilterRegistrationBean that disables registration

    @Bean
    public FilterRegistrationBean registration(JWTokenFilter filter) {
        FilterRegistrationBean registration = new FilterRegistrationBean(filter);
        registration.setEnabled(false);
        return registration;
    }
    

    【讨论】:

      猜你喜欢
      • 2015-06-20
      • 2017-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-08
      • 2011-09-06
      • 1970-01-01
      相关资源
      最近更新 更多