it-roy-ru.com

Как применять пружинный защитный фильтр только на защищенных конечных точках?

У меня есть следующая конфигурация Spring Security:

    httpSecurity
            .csrf()
            .disable()
            .exceptionHandling()
            .authenticationEntryPoint(unauthorizedHandler)
            .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeRequests()
            .antMatchers("/api/**").fullyAuthenticated()
            .and()
            .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);

authenticationTokenFilterBean() применяется даже к конечным точкам, которые не соответствуют выражению /api/**. Я также попытался добавить следующий код конфигурации

@Override
public void configure(WebSecurity webSecurity) {
    webSecurity.ignoring().antMatchers("/some_endpoint");
}

но это все еще не решило мою проблему. Как я могу сказать Spring Security, чтобы применять фильтры только к конечным точкам, которые соответствуют защищенному выражению URI? Спасибо

15
Bravo

У меня есть приложение с тем же требованием, и для его решения я в основном ограничил Spring Security указанным паттерном сопоставления муравьев (используя antMatcher) следующим образом:

http.antMatcher("/api/**").authorizeRequests() //
        .anyRequest().authenticated() //
        .and()
        .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);

Вы можете прочитать его следующим образом: для http вызывайте эти конфигурации только по запросам, соответствующим шаблону ant /api/**, разрешающему any request для authenticated пользователей andadd filterauthenticationTokenFilterBean()beforeUsernamePasswordAuthenticationFilter. Для всех остальных запросов эта конфигурация не имеет никакого эффекта.

18
Francisco Spaeth

Если вы используете .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

Вы можете определить в конструкторе конкретный путь, к которому он будет применяться:

public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        super("/api/**");
        this.setAuthenticationManager(authenticationManager);
    }

    @Override
    protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
        return super.requiresAuthentication(request, response);
    }

Метод requireAuthentication будет использоваться для определения необходимости аутентификации на этой конечной точке.

1
Qualaelay

Я думаю, что нашел способ решить это. У меня есть JwtTokenAuthenticationProcessingFilter, который является AbstractAuthenticationProcessingFilter. Я хочу, чтобы он аутентифицировал запрос, если в голове есть токен, но не блокировал запрос в случае неудачи. Все, что вам нужно, это переписатьdoFilterи вызватьchain.doFilterнезависимо от того, каков результат аутентификации (вызов unsuccessfulAuthentication не является обязательным). Вот часть моего кода.

public class JwtTokenAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {

    private final TokenExtractor tokenExtractor;

    @Autowired
    public JwtTokenAuthenticationProcessingFilter(TokenExtractor tokenExtractor, RequestMatcher matcher) {
        super(matcher);
        this.tokenExtractor = tokenExtractor;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
            ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        if (!this.requiresAuthentication(request, response)) {
            chain.doFilter(request, response);
        } else {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Request is to process authentication");
            }

            boolean success = true;

            Authentication authResult = null;
            try {
                authResult = this.attemptAuthentication(request, response);
            } catch (InternalAuthenticationServiceException var8) {
                this.logger.error("An internal error occurred while trying to authenticate the user.", var8);
                success = false;
            } catch (AuthenticationException var9) {
                success = false;
            }


            if (success && null != authResult) {
                this.successfulAuthentication(request, response, chain, authResult);
            }

            // Please ensure that chain.doFilter(request, response) is invoked upon successful authentication. You want
            // processing of the request to advance to the next filter, because very last one filter
            // FilterSecurityInterceptor#doFilter is responsible to actually invoke method in your controller that is
            // handling requested API resource.
            chain.doFilter(request, response);
        }
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        String tokenPayload = request.getHeader(WebSecurityConfig.AUTHENTICATION_HEADER_NAME);
        RawAccessJwtToken token = new RawAccessJwtToken(tokenExtractor.extract(tokenPayload));
        return getAuthenticationManager().authenticate(new JwtAuthenticationToken(token));
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {
        SecurityContext context = SecurityContextHolder.createEmptyContext();
        context.setAuthentication(authResult);
        SecurityContextHolder.setContext(context);
    }
}
0
Shengfeng Li