Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.solaria.persistence.controller;

import com.solaria.persistence.dto.auth.AuthLoginResponseDTO;
import com.solaria.persistence.dto.auth.LoginRequestDTO;
import com.solaria.persistence.integration.auth.AuthClient;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

// Proxy de conveniência para autenticar direto pelo Swagger deste serviço,
// sem precisar acessar o Swagger de api-auth. Chama api-auth por baixo.
@RestController
@Tag(name = "Dev")
public class DevAuthController {

private final AuthClient authClient;

public DevAuthController(AuthClient authClient) {
this.authClient = authClient;
}

@Operation(summary = "Autentica em api-auth e devolve o JWT, para colar no botão Authorize deste Swagger")
@PostMapping("/dev/login")
public AuthLoginResponseDTO login(@Valid @RequestBody LoginRequestDTO request) {
return authClient.login(request.getEmail(), request.getPassword());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.solaria.persistence.dto.auth;

import lombok.Getter;
import lombok.Setter;

// Espelha o AuthResponse de api-auth (POST /auth/login)
@Setter
@Getter
public class AuthLoginResponseDTO {

private String accessToken;

private String refreshToken;

private String accessTokenExpiresAt;

private String userId;

private String email;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.solaria.persistence.dto.auth;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class LoginRequestDTO {

@Email
@NotBlank
private String email;

@NotBlank
private String password;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.solaria.persistence.integration.auth;

import com.solaria.persistence.dto.auth.AuthLoginResponseDTO;
import com.solaria.persistence.dto.auth.LoginRequestDTO;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestClientResponseException;

// Cliente do endpoint POST /auth/login em api-auth
@Component
public class AuthClient {

private final RestClient restClient;

public AuthClient(RestClient authRestClient) {
this.restClient = authRestClient;
}

public AuthLoginResponseDTO login(String email, String password) {
LoginRequestDTO request = new LoginRequestDTO();
request.setEmail(email);
request.setPassword(password);
try {
return restClient.post()
.uri("/auth/login")
.body(request)
.retrieve()
.body(AuthLoginResponseDTO.class);
} catch (RestClientResponseException e) {
throw new AuthIntegrationException(
"Falha ao autenticar em api-auth: HTTP " + e.getStatusCode().value(), e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.solaria.persistence.integration.auth;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.JdkClientHttpRequestFactory;
import org.springframework.web.client.RestClient;

import java.net.http.HttpClient;

// factory responsável por criar as chamadas http a api-auth
@Configuration
@EnableConfigurationProperties(AuthClientProperties.class)
public class AuthClientConfig {

@Bean
public RestClient authRestClient(AuthClientProperties properties) {
HttpClient httpClient = HttpClient.newBuilder()
.connectTimeout(properties.getConnectTimeout())
.build();
JdkClientHttpRequestFactory requestFactory = new JdkClientHttpRequestFactory(httpClient);
requestFactory.setReadTimeout(properties.getReadTimeout());
return RestClient.builder()
.baseUrl(properties.getBaseUrl())
.requestFactory(requestFactory)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.solaria.persistence.integration.auth;

import org.springframework.boot.context.properties.ConfigurationProperties;

import java.time.Duration;

// Liga esta classe ao prefixo "app.integration.auth" do application.properties
@ConfigurationProperties(prefix = "app.integration.auth")
public class AuthClientProperties {

// URL de api-auth
private String baseUrl;

// timeout de conexão da chamada HTTP a api-auth
private Duration connectTimeout = Duration.ofSeconds(5);

// timeout de leitura da chamada HTTP a api-auth
private Duration readTimeout = Duration.ofSeconds(5);

public String getBaseUrl() {
return baseUrl;
}

public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}

public Duration getConnectTimeout() {
return connectTimeout;
}

public void setConnectTimeout(Duration connectTimeout) {
this.connectTimeout = connectTimeout;
}

public Duration getReadTimeout() {
return readTimeout;
}

public void setReadTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.solaria.persistence.integration.auth;

// Lançada quando a chamada a POST /auth/login em api-auth falha
public class AuthIntegrationException extends RuntimeException {
public AuthIntegrationException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ public SecurityFilterChain resourceServerSecurityFilterChain(HttpSecurity http)
.requestMatchers("/v3/api-docs/**", "/swagger-ui/**",
"/swagger-ui.html")
.permitAll()
// Endpoint de conveniência para autenticar direto pelo Swagger
.requestMatchers(HttpMethod.POST, "/dev/login")
.permitAll()
// todos os outros endpoints exigem um jwt de usuário válido,
// decodificado por userJwtDecoder()
.anyRequest().authenticated())
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@ app.jwt.service.access-ttl-ms=${SERVICE_JWT_ACCESS_TTL_MS:600000}
# TTL do token de refresh
app.jwt.service.refresh-ttl-ms=${SERVICE_JWT_REFRESH_TTL_MS:3600000}

# URL de api-auth, usada pelo endpoint de conveniência POST /dev/login
app.integration.auth.base-url=${AUTH_SERVICE_URL}

Loading