两个匹配器都适合,如何避免应用过滤器?

问题描述

这是我当前的安全配置;如您所见,对于AntPathRequestMatcher我有一个/api/**,应该为基于令牌的安全性应用一个过滤器。我的身份验证网址位于/api/token下,显然不应受到保护。当前的.permitAll似乎被忽略了;我该如何解决

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {


    private static final RequestMatcher PROTECTED_URLS = new OrRequestMatcher(
            new AntPathRequestMatcher("/api/**")
    );

    private static final RequestMatcher FREE_URLS = new OrRequestMatcher(
            new AntPathRequestMatcher("/api/token")
    );

    @Autowired
    AuthenticationProvider provider;

    public SecurityConfiguration(final AuthenticationProvider authenticationProvider) {
        super();
        this.provider = authenticationProvider;
    }

    @Override
    protected void configure(final AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(provider);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
            .exceptionHandling()
                .and()
            .authorizeRequests()
                .requestMatchers(FREE_URLS).permitAll()
                .and()
            .authenticationProvider(provider)
                .addFilterBefore(authenticationFilter(),AnonymousAuthenticationFilter.class)
            .authorizeRequests()
                .requestMatchers(PROTECTED_URLS).authenticated()
                .and()
            .csrf().disable()
            .formLogin().disable()
            .httpBasic().disable()
            .logout().disable();
    }

    @Bean
    AuthenticationFilter authenticationFilter() throws Exception {
        final AuthenticationFilter filter = new AuthenticationFilter(PROTECTED_URLS);
        filter.setAuthenticationManager(authenticationManager());
        return filter;
    }

    @Bean
    AuthenticationEntryPoint forbiddenEntryPoint() {
        return new HttpStatusEntryPoint(HttpStatus.FORBIDDEN);
    }
}

编辑: 这是我的筛选器:可能确实是“抛出新的AuthenticationCredentialsNotFoundException”,但我不知道如何解决此问题。仅更改过滤器链配置是否不可能?过滤器仅适用于PROTECTED_URLS中列出的那些URL,但被FREE_URLS排除的URL除外。如果我要更改过滤器,那么是否不需要告诉过滤器免费URL?

public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    AuthenticationFilter(final RequestMatcher requiresAuth) {
        super(requiresAuth);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws AuthenticationException,IOException,servletexception {
        String token= httpServletRequest.getHeader(AUTHORIZATION);
        if(token==null) throw new AuthenticationCredentialsNotFoundException("Kein Token im Header angegeben");
        token = StringUtils.removeStart(token,"Bearer").trim();
        Authentication requestAuthentication = new UsernamePasswordAuthenticationToken(token,token);
        return getAuthenticationManager().authenticate(requestAuthentication);

    }

    @Override
    protected void successfulAuthentication(final HttpServletRequest request,final HttpServletResponse response,final FilterChain chain,final Authentication authResult) throws IOException,servletexception {
        SecurityContextHolder.getContext().setAuthentication(authResult);
        chain.doFilter(request,response);
    }
}

解决方法

这可以通过以下方式解决:首先放置更具体的配置,使其首先匹配。

按如下所示更改您的配置方法:

http
    .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
    .exceptionHandling()
        .and()
    .authorizeRequests()
        .requestMatchers(FREE_URLS).permitAll()
        .and()
    .authenticationProvider(provider)
        .addFilterBefore(authenticationFilter(),AnonymousAuthenticationFilter.class)
    .authorizeRequests()
        .requestMatchers(FREE_URLS).permitAll()
        .requestMatchers(PROTECTED_URLS).authenticated()
        .and()
    .csrf().disable()
    .formLogin().disable()
    .httpBasic().disable()
    .logout().disable();