有没有办法在 Spring Boot 中对某些端点使用 api 密钥并为其他端点使用 oauth2?

问题描述 投票:0回答:1

我需要使用 google oauth2 保护一些端点并使用 api 密钥保护一些端点。

在我将 ApiKeyFilter 添加到 AuthConfig 之前,它按预期工作。但是,当我添加过滤器时,我发现

"/secured-with-api-key/**"
"/non-secured/**"
按预期工作,但是即使没有jwt令牌也可以访问
"/secured/**"

这是 ApiKeyAuthFilter:

public class ApiKeyAuthFilter extends AbstractPreAuthenticatedProcessingFilter {
private static final Logger LOG = LoggerFactory.getLogger(ApiKeyAuthFilter.class);

    private final String apiKeyHeaderName;
    private final String timestampHeaderName;
    private final String signatureHeaderName;
    
    public ApiKeyAuthFilter(String apiKeyHeaderName, String timestampHeaderName, String signatureHeaderName) {
        this.apiKeyHeaderName = apiKeyHeaderName;
        this.timestampHeaderName = timestampHeaderName;
        this.signatureHeaderName = signatureHeaderName;
    }
    
    @Override
    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
        String apiKey = request.getHeader(apiKeyHeaderName);
        String timestamp = request.getHeader(timestampHeaderName);
        String signature = request.getHeader(signatureHeaderName);
        return new AuthPrincipal(apiKey, timestamp, signature);
    }
    
    @Override
    protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
        // No creds when using API key
        return null;
    }

这是 SimpleAuthenticationManager:

@Component
public class SimpleAuthenticationManager implements AuthenticationManager {

    private static final Logger LOG = LoggerFactory.getLogger(SimpleAuthenticationManager.class);

    @Autowired
    private ApiKeysDatabase apiKeysDatabase;

    @Autowired
    private TokenVerifier tokenVerifier;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        AuthPrincipal principal = (AuthPrincipal) authentication.getPrincipal();
        if (principal.getApikey() == null || principal.getTimestamp() == null || principal.getSignature() == null) {
            throw new BadCredentialsException("The API_KEY/timestamp/signature Header is missing.");
        }
        if (!apiKeysDatabase.isValidKey(principal.getApikey())) {
            throw new BadCredentialsException("The API key was not found or not the expected value.");
        }
        if (!tokenVerifier.isTokenAuthorized(principal)) {
            throw new BadCredentialsException("The signature is invalid");
        }
        authentication.setAuthenticated(true);
        return authentication;
    }
}

这是 AuthConfig:

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

    private static final String API_KEY_HEADER_NAME = "API_KEY";
    private static final String TIMESTAMP_HEADER_NAME = "timestamp";
    private static final String SIGNATURE_HEADER_NAME = "signature";

    @Autowired
    private SimpleAuthenticationManager simpleAuthenticationManager;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ApiKeyAuthFilter filter = new ApiKeyAuthFilter(API_KEY_HEADER_NAME, TIMESTAMP_HEADER_NAME, SIGNATURE_HEADER_NAME);
        filter.setAuthenticationManager(simpleAuthenticationManager);

        http.antMatcher("/secured/**")
                .authorizeRequests()
                .antMatchers("/secured/**")
                .fullyAuthenticated();

        http.antMatcher("/non-secured/**")
                .authorizeRequests()
                .antMatchers("/non-secured/**")
                .permitAll();

        http.antMatcher("/secured-with-api-key/**")
                .addFilter(filter)
                .authorizeRequests()
                .antMatchers("/secured-with-api-key/**")
                .authenticated();

        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        http.cors().and().csrf().disable();

        http.oauth2ResourceServer().jwt();
    }
}

提前致谢。

我预计

"/secured/**"
需要jwt才能访问,
"/secured-with-api-key/**"
需要一个api密钥才能访问并且
"/non-secured/**"
可以为任何人访问。

java spring-boot spring-security oauth-2.0 api-key
1个回答
0
投票

使用两个

SecurityFilterChain
@Beans:一个具有资源服务器配置(OAuth2,使用 Bearer 访问令牌保护),另一个用于 API 密钥。不要忘记订购两个并用
securityMatcher
限制第一个加载的。

例如,使用专用于 API 密钥的过滤器链(所有以

/secured-with-api-key/
开头的路由)和使用 OAuth2 保护的默认路由(所有与之前的过滤器链不匹配的路由):

    @Order(Ordered.HIGHEST_PRECEDENCE)
    @Bean
    SecurityFilterChain apiKeyFilterChain(HttpSecurity http) {
        http.securityMatcher(new AntPathRequestMatcher("/secured-with-api-key/**"));
        // more API key security conf
        return http.build();
    }

    @Bean
    SecurityFilterChain defaultFilterChain(HttpSecurity http) {
        http.oauth2ResourceServer().jwt();
        // resource-server security conf
        return http.build();
    }
© www.soinside.com 2019 - 2024. All rights reserved.