Como seria um exemplo de uma api spring boot com api key? Seria necessário toda configuração que realizamos no projeto do curso?
Como seria um exemplo de uma api spring boot com api key? Seria necessário toda configuração que realizamos no projeto do curso?
Oi!
Pode dar mais detalhes sobre API_KEY? Qual seria o cenário de uso que você está pensando?
Oi Rodrigo, o cenário seria o seguinte, precisava passar valores no cabeçalho da requisição para que um fiiltro realizasse essa validação. Mas nesse caso seriam 2 cabeçalhos distintos, pois isso iria depender de onde a API seria chamada, nesse caso tenho 2 cenários: 1- ela será chamada de dentro do banco de dados oracle, ae neste caso ele passaria um cabecalho. 2 - ela seria chamada via postman ou ser consumida por outra api.
Eu consegui fazer com apenas um cabeçalho, só alterando o valor de acordo com ela é chamada, mas minha duvida seria como melhorar este código para incluir 2 cabeçalhos distintios ao invés de ficar setando os valroes.
Segue os códigos
public class KeyAuthFilter extends AbstractPreAuthenticatedProcessingFilter{
private final String headerName;
public KeyAuthFilter(final String headerName) {
this.headerName = headerName;
}
@Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
return request.getHeader(headerName);
}
@Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
// No creds when using API key
return null;
}
}
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
@Value("${http.auth-token-header-name}")
private String principalRequestHeader;
@Value("${http.auth-token}")
private String principalRequestValue;
@Value("${http.auth-token-credenciais-list}")
private List<String> credenciais;
private boolean isAutenticar;
@Bean
@Order
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
KeyAuthFilter filter = new KeyAuthFilter(principalRequestHeader);
filter.setAuthenticationManager(new AuthenticationManager() {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String principal = (String) authentication.getPrincipal();
if(verificarCredencial(principal)) {
authentication.setAuthenticated(true);
return authentication;
}
if (!principalRequestValue.equals(principal)) {
authentication.setAuthenticated(false);
throw new BadCredentialsException("The API key was not found or not the expected value.");
}
authentication.setAuthenticated(true);
return authentication;
}
});
http.csrf((csrf) -> csrf.disable())
.httpBasic(b-> b.disable())
.formLogin(f-> f.disable())
.logout(l-> l.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
.addFilter(filter)
;
http.requiresChannel(
req -> req.requestMatchers(r -> r.getHeader("X-Forwarded-Proto") != null).requiresSecure());
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().requestMatchers("/actuator", "/actuator/**","/v3/api-docs/**", "/swagger-ui.html", "/swagger-ui/**");
}
private boolean verificarCredencial(String segundaApiKey) {
isAutenticar = false;
credenciais.forEach(e -> {
if (e.equals(segundaApiKey)) {
isAutenticar = true;
}
});
return isAutenticar;
}
}
Para incluir dois cabeçalhos distintos no seu código, você pode fazer algumas modificações no filtro e na configuração de segurança.
Primeiro, vamos modificar a classe KeyAuthFilter
para receber dois cabeçalhos ao invés de apenas um. Podemos fazer isso criando dois atributos headerName1
e headerName2
na classe e modificando os métodos getPreAuthenticatedPrincipal
() e getPreAuthenticatedCredentials
() para retornar os valores dos cabeçalhos correspondentes:
public class KeyAuthFilter extends AbstractPreAuthenticatedProcessingFilter {
private final String headerName1;
private final String headerName2;
public KeyAuthFilter(final String headerName1, final String headerName2) {
this.headerName1 = headerName1;
this.headerName2 = headerName2;
}
@Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
String header1 = request.getHeader(headerName1);
String header2 = request.getHeader(headerName2);
// Retorne uma classe que encapsule os valores dos cabeçalhos, se necessário
return new HeaderValues(header1, header2);
}
@Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
// No creds when using API key
return null;
}
}
A classe HeaderValues
é uma classe que você pode criar para armazenar os valores dos cabeçalhos. Ela pode ter os atributos header1
e header2
e os respectivos métodos getters e setters.
Em seguida, vamos modificar a classe SecurityConfig
para criar uma instância de KeyAuthFilter
com os dois cabeçalhos e configurar o AuthenticationManager
com base nesses valores:
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
@Value("${http.auth-token-header-name1}")
private String principalRequestHeader1;
@Value("${http.auth-token-header-name2}")
private String principalRequestHeader2;
@Value("${http.auth-token1}")
private String principalRequestValue1;
@Value("${http.auth-token2}")
private String principalRequestValue2;
// Resto do código...
@Bean
@Order
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
KeyAuthFilter filter = new KeyAuthFilter(principalRequestHeader1, principalRequestHeader2);
filter.setAuthenticationManager(new AuthenticationManager() {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
HeaderValues headerValues = (HeaderValues) authentication.getPrincipal();
String header1 = headerValues.getHeader1();
String header2 = headerValues.getHeader2();
if (verificarCredencial(header1, header2)) {
authentication.setAuthenticated(true);
return authentication;
}
if (!principalRequestValue1.equals(header1) || !principalRequestValue2.equals(header2)) {
authentication.setAuthenticated(false);
throw new BadCredentialsException("The API key was not found or not the expected value.");
}
authentication.setAuthenticated(true);
return authentication;
}
});
// Resto do código...
}
// Resto do código...
private boolean verificarCredencial(String segundaApiKey1, String segundaApiKey2) {
isAutenticar = false;
credenciais.forEach(e -> {
if (e.equals(segundaApiKey1) && e.equals(segundaApiKey2)) {
isAutenticar = true;
}
});
return isAutenticar;
}
}
Lembre-se de ajustar as propriedades http.auth-token-header-name1
, http.auth-token-header-name2
, http.auth-token1
e http.auth-token2
no arquivo de configuração para corresponderem aos nomes dos cabeçalhos e aos valores esperados.
Essas modificações permitem que você tenha dois cabeçalhos distintos e execute a validação correta de acordo com o cenário em que a API é chamada.