📅  最后修改于: 2023-12-03 15:20:12.475000             🧑  作者: Mango
在本示例中,将演示如何使用 Spring Boot 从 HTTP 请求头中获取密钥并进行认证。
首先,需要在 pom.xml
中添加以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
这将为我们提供所需的安全功能。
接下来,需要创建一个自定义的 WebSecurityConfigurerAdapter
类,以实现密钥认证。
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final String AUTHENTICATION_HEADER = "Authorization";
private final String AUTHENTICATION_PREFIX = "Bearer ";
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.anyRequest().permitAll()
.and()
.addFilter(new AuthenticationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new ApiKeyAuthenticationProvider());
}
private ApiKeyAuthenticationFilter authenticationFilter() throws Exception {
ApiKeyAuthenticationFilter filter = new ApiKeyAuthenticationFilter(AUTHENTICATION_HEADER, AUTHENTICATION_PREFIX);
filter.setAuthenticationManager(authenticationManager());
return filter;
}
private static class ApiKeyAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String apiKey = authentication.getName();
// Perform API key validation here
return new UsernamePasswordAuthenticationToken(apiKey, null, Collections.emptyList());
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
private static class ApiKeyAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private final String authenticationHeader;
private final String authenticationPrefix;
protected ApiKeyAuthenticationFilter(String authenticationHeader, String authenticationPrefix) {
super(new AntPathRequestMatcher("/api/**"));
this.authenticationHeader = authenticationHeader;
this.authenticationPrefix = authenticationPrefix;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
String apiKey = request.getHeader(authenticationHeader);
if (apiKey == null || !apiKey.startsWith(authenticationPrefix)) {
throw new BadCredentialsException("Invalid API key");
}
apiKey = apiKey.substring(authenticationPrefix.length()).trim();
return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(apiKey, null));
}
}
}
此配置文件启用了基于 HTTP 头的密钥认证,并且只允许 /api/
路径下的请求进行认证。它还为我们提供了自定义 ApiAuthenticationProvider
类和过滤器,用于处理密钥认证。
在 ApiAuthenticationProvider
中,可以验证 API 密钥并返回身份验证令牌。在此示例中,只是返回了 API 密钥,但实际情况中,需要执行更复杂的验证操作,如在数据库中检查密钥是否存在等等。
在 ApiAuthenticationFilter
中,可以从 HTTP 请求头中提取 API 密钥,并使用身份验证管理器对其进行验证。
最后,可以编写一个集成测试来测试密钥认证功能:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ApiIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void givenApiKey_whenAccessSecureApi_thenAuthorized() {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer my-api-key");
HttpEntity<String> entity = new HttpEntity<>("body", headers);
ResponseEntity<String> response = restTemplate.exchange("/api/secure", HttpMethod.GET, entity, String.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("Hello, World!", response.getBody());
}
@Test
public void givenInvalidApiKey_whenAccessSecureApi_thenUnauthorized() {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer invalid-api-key");
HttpEntity<String> entity = new HttpEntity<>("body", headers);
ResponseEntity<String> response = restTemplate.exchange("/api/secure", HttpMethod.GET, entity, String.class);
assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
}
}
在上面的测试中,将使用 TestRestTemplate
来模拟发送带有有效或无效 API 密钥的 HTTP 请求,并验证响应是否正常。
在本示例中,演示了如何使用 Spring Boot 实现基于 HTTP 头的密钥认证。在实际情况中,需要在认证过程中执行更复杂的验证操作,但此示例可以作为一个起点。