我需要使用 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/**"
可以为任何人访问。
使用两个
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();
}