当前位置: 首页 > 知识库问答 >
问题:

Spring Security 5 api密钥过滤器

韩征
2023-03-14

我正试图用spring security 5和boot 2创建一个过滤器,用一个API键保护一些但不是所有的endpoint,并且没有会话。然而,在过滤器对其进行身份验证之后,由于SavedRequestAwareAuthenticationSuccessHandler有一个空的请求缓存,因此它倾向于重定向到“/”,而不是原始url。

我如何才能让它继续使用目标资源而不是“/”,以及为什么它像这样工作?

如果有人能向我解释为什么抽象身份验证处理过滤器被设计为在成功身份验证后继续使用过滤器链,而抽象身份验证处理过滤器不是,我将不胜感激。

这是安全配置类:

@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();
    }

}

我的筛选器匹配具有自定义值的Authorization头的请求。从标头提取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 '/'

我试图在这个基础上让这个工作。

共有1个答案

郗俊能
2023-03-14

我不得不覆盖过滤器中的successfulAuthentication方法,并继续这个链以使它工作。

@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);
    }
 类似资料:
  • 在这个expire方法中,我们需要提供而不是。但是我需要过期而不是。 那么,请帮助我如何处理过期?

  • 我无法访问托管密钥库中的存储帐户密钥。下面是我的代码: 似乎$secret.secretValueText为空/null。如何正确检索存储帐户密钥?这就是出现的错误。

  • 我用过这个命令 生成密钥库。它工作正常,但从我读到的内容来看,这个命令还应该提示您输入密钥密码(而不是存储密码)?我从来没有收到过这样的提示。我能跑 查看密钥库的内容。钥匙似乎就在那里。。。正确的别名在那里。在哪里获取/设置特定别名的密码? 我有一个key.properties在Android目录 在build.gradle我有: 当我试图生成一个发布版本时,我得到了 我想它可能与keyPassw

  • 密钥用于绑定虚拟机和裸金属,提高服务器登录安全性。 密钥是根据RSA或DSA加密算法生成的一组密钥对,由公钥和私钥组成。其中公钥文件用于新建密钥,私钥文件需要由用户妥善保管,用于登录绑定密钥的虚拟机或裸金属。 密钥文件使用方法 当用户需要使用密钥登录虚拟机时,需要先在密钥列表使用公钥内容创建密钥。 将密钥绑定到虚拟机或裸金属上。 用户通过私钥文件远程登录虚拟机或裸金属。或在云管平台上通过私钥内容获

  • 问题内容: 当生存时间达到0时,我的Redis服务器不会删除密钥。 这是一个示例代码: 如果我通过redis检查信息返回,它说0个密钥已过期。 任何想法? 谢谢。 问题答案: 由于您正在执行“ …”,因此很难确定,但是我要说的是您在该部分设置了mykey,这将有效地消除过期。 从EXPIRE手册 仅当使用DEL命令删除密钥或使用SET或GETSET命令覆盖密钥时,才清除超时 另外,关于TTL的-1

  • 问题内容: 当我的密钥在Redis数据存储区中过期时,我正在尝试使用Redis实施过期密钥通知。redis网站提供了一些有关http://redis.io/topics/notifications的描述,但是我无法找到任何示例,例如使用Jedis的redis java客户端如何做到这一点? 任何可能的带有插图的代码都将非常有用,因为它们是redis的新功能。 问题答案: 您只能使用 pub-sub