📜  spring boot api 密钥认证示例 - Java (1)

📅  最后修改于: 2023-12-03 15:20:12.475000             🧑  作者: Mango

Spring Boot API 密钥认证示例

在本示例中,将演示如何使用 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 头的密钥认证。在实际情况中,需要在认证过程中执行更复杂的验证操作,但此示例可以作为一个起点。