Ключ безопасности Spring 5 Api Key Filter - PullRequest
0 голосов
/ 17 февраля 2020

Я пытаюсь создать фильтр с пружинной защитой 5 и загрузкой 2, который защищает некоторые, но не все конечные точки с ключом API и без сеансов. Однако после того, как фильтр аутентифицируется, он устает перенаправлять на «/» вместо исходного URL-адреса, поскольку SavedRequestAwareAuthenticationSuccessHandler имеет кэш запроса empy и возвращается к значению по умолчанию "/".

Как я могу заставить его продолжить целевой ресурс вместо '/' и почему он работает так?

Я также был бы признателен, если бы кто-нибудь мог объяснить мне, почему AbstractPreAuthenticatedProcessingFilter предназначен для продолжения цепочки фильтров после успешной аутентификации, но AbstractAuthenticationProcessingFilter не.

Это класс конфигурации безопасности:

@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${secret.admin.api.key}")
    String validApiKey;

    @Override
    protected void configure(AuthenticationManagerBuilder builder) throws Exception {
        builder.authenticationProvider(new ApiKeyAuthenticationProvider(validApiKey));
    }

    @Override
    protected void configure(HttpSecurity security) throws Exception {
        security
            .csrf().disable()
            .sessionManagement()
                .sessionCreationPolicy(STATELESS)
                .and()
            .addFilterBefore(new ApiKeyAuthenticationFilter(authenticationManager()), AnonymousAuthenticationFilter.class)
            .requestMatchers()
                .antMatchers("/v1/admin/**")
                .antMatchers("/actuator/**")
                .and()
            .authorizeRequests().anyRequest().authenticated();
    }

}

Мой фильтр сопоставляет запросы с заголовком авторизации с пользовательским значением. Извлекает ключ api из заголовка и передает маркер с принципалом и учетными данными (ключ api) менеджеру аутентификации.

public class ApiKeyAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

//...

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
        throws AuthenticationException, IOException, ServletException {
        var apiKey = extractApiKey(request.getHeader(AUTHORIZATION));
        var token = new ApiKeyAuthenticationToken(apiKey);
        var authentication = getAuthenticationManager().authenticate(token);
        return authentication;
    }

//...
}

Следующий класс проверяет учетные данные и создает и аутентифицирует токен с принципалом и без учетные данные:

public class ApiKeyAuthenticationProvider implements AuthenticationProvider {

// ...

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        var apiKey = (String) authentication.getCredentials();
        if (validApiKey.equals(apiKey)) {
            var auth = new ApiKeyAuthenticationToken();
            auth.setAuthenticated(true);
            return auth;
        } else {
            throw new BadCredentialsException("Bad ApiKey credentials");
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return ApiKeyAuthenticationToken.class.isAssignableFrom(authentication);
    }

}

И журналы:

OrRequestMatcher: Trying to match using Ant [pattern='/v1/admin/**']
AntPathRequestMatcher: Checking match of request : '/v1/admin/namespace'; against '/v1/admin/**'
OrRequestMatcher: matched
FilterChainProxy$VirtualFilterChain: /v1/admin/namespace at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
FilterChainProxy$VirtualFilterChain: /v1/admin/namespace at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
FilterChainProxy$VirtualFilterChain: /v1/admin/namespace at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
FilterChainProxy$VirtualFilterChain: /v1/admin/namespace at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
[...]
FilterChainProxy$VirtualFilterChain: /v1/admin/namespace at position 5 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
FilterChainProxy$VirtualFilterChain: /v1/admin/namespace at position 6 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
FilterChainProxy$VirtualFilterChain: /v1/admin/namespace at position 7 of 11 in additional filter chain; firing Filter: 'ApiKeyAuthenticationFilter'
ProviderManager: Authentication attempt using ....security.ApiKeyAuthenticationProvider
AbstractAuthenticationTargetUrlRequestHandler: Using default Url: /
DefaultRedirectStrategy: Redirecting to '/'

Я пытался сделать эту работу на основе this .

1 Ответ

0 голосов
/ 18 февраля 2020

Мне пришлось переопределить метод successAuthentication в фильтре и продолжить цепочку, чтобы он заработал.

@Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
        FilterChain chain, Authentication authResult) throws IOException, ServletException {

        log.info("Successful authentication");
        SecurityContextHolder.getContext().setAuthentication(authResult);
        chain.doFilter(request,response);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...