Refactor AuthController to enhance refresh token handling and support CORS
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
package fr.gameovergne.api.controller.auth;
|
||||
|
||||
import fr.gameovergne.api.dto.auth.AuthRequest;
|
||||
import fr.gameovergne.api.dto.auth.AuthResponse;
|
||||
import fr.gameovergne.api.dto.user.UserDTO;
|
||||
import fr.gameovergne.api.mapper.user.UserMapper;
|
||||
import fr.gameovergne.api.service.auth.AuthService;
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import fr.gameovergne.api.dto.auth.AuthResponse;
|
||||
import fr.gameovergne.api.dto.user.UserDTO;
|
||||
import fr.gameovergne.api.dto.auth.AuthRequest;
|
||||
import fr.gameovergne.api.mapper.user.UserMapper;
|
||||
import fr.gameovergne.api.service.auth.AuthService;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseCookie;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -17,6 +17,12 @@ import java.util.Arrays;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
@CrossOrigin(
|
||||
origins = "https://dev.vincent-guillet.fr",
|
||||
allowCredentials = "true",
|
||||
allowedHeaders = "*",
|
||||
methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS}
|
||||
)
|
||||
public class AuthController {
|
||||
|
||||
private final AuthService authService;
|
||||
@@ -25,26 +31,34 @@ public class AuthController {
|
||||
this.authService = authService;
|
||||
}
|
||||
|
||||
// ===================== REGISTER =====================
|
||||
|
||||
@PostMapping("/register")
|
||||
public ResponseEntity<AuthResponse> register(@RequestBody UserDTO dto) {
|
||||
public ResponseEntity<AuthResponse> register(@RequestBody UserDTO dto,
|
||||
HttpServletResponse response) {
|
||||
return authService.register(UserMapper.fromDto(dto))
|
||||
.map((ResponseEntity::ok))
|
||||
.map(authResponse -> createAuthResponse(authResponse, response))
|
||||
.orElse(ResponseEntity.badRequest().build());
|
||||
}
|
||||
|
||||
// ===================== LOGIN =====================
|
||||
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<AuthResponse> authenticate(@RequestBody AuthRequest request, HttpServletResponse response) {
|
||||
public ResponseEntity<AuthResponse> authenticate(@RequestBody AuthRequest request,
|
||||
HttpServletResponse response) {
|
||||
return authService.authenticate(request)
|
||||
.map(authResponse -> createAuthResponse(authResponse, response))
|
||||
.orElse(ResponseEntity.badRequest().build());
|
||||
}
|
||||
|
||||
// ===================== LOGOUT =====================
|
||||
|
||||
@GetMapping("/logout")
|
||||
public ResponseEntity<Void> logout(HttpServletResponse response) {
|
||||
// Supprime le cookie de refresh token
|
||||
ResponseCookie cookie = ResponseCookie.from("refreshToken", "")
|
||||
.httpOnly(true)
|
||||
.secure(false) // true en prod
|
||||
.secure(false) // true en prod derrière HTTPS
|
||||
.path("/")
|
||||
.maxAge(0) // expire immédiatement
|
||||
.sameSite("Lax")
|
||||
@@ -53,11 +67,16 @@ public class AuthController {
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
// ===================== ME =====================
|
||||
|
||||
@GetMapping("/me")
|
||||
public ResponseEntity<UserDTO> getCurrentUser(HttpServletRequest request) {
|
||||
String username = request.getUserPrincipal() != null ? request.getUserPrincipal().getName() : null;
|
||||
String username = request.getUserPrincipal() != null
|
||||
? request.getUserPrincipal().getName()
|
||||
: null;
|
||||
|
||||
if (username == null) {
|
||||
return ResponseEntity.status(401).build(); // Unauthorized
|
||||
return ResponseEntity.status(401).build();
|
||||
}
|
||||
|
||||
return authService.getCurrentUser(username)
|
||||
@@ -65,20 +84,26 @@ public class AuthController {
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
// --------- REFRESH TOKEN : accepte POST et GET ---------
|
||||
// ===================== REFRESH =====================
|
||||
|
||||
// Accepte POST et GET pour être robuste aux proxies / redirects bizarres
|
||||
|
||||
@PostMapping("/refresh")
|
||||
public ResponseEntity<AuthResponse> refreshPost(HttpServletRequest request, HttpServletResponse response) {
|
||||
public ResponseEntity<AuthResponse> refreshPost(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
return handleRefresh(request, response);
|
||||
}
|
||||
|
||||
@GetMapping("/refresh")
|
||||
public ResponseEntity<AuthResponse> refreshGet(HttpServletRequest request, HttpServletResponse response) {
|
||||
public ResponseEntity<AuthResponse> refreshGet(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
return handleRefresh(request, response);
|
||||
}
|
||||
|
||||
private ResponseEntity<AuthResponse> handleRefresh(HttpServletRequest request, HttpServletResponse response) {
|
||||
private ResponseEntity<AuthResponse> handleRefresh(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
String refreshToken = null;
|
||||
|
||||
if (request.getCookies() != null) {
|
||||
refreshToken = Arrays.stream(request.getCookies())
|
||||
.filter(c -> "refreshToken".equals(c.getName()))
|
||||
@@ -94,13 +119,15 @@ public class AuthController {
|
||||
|
||||
return authService.refresh(refreshToken)
|
||||
.map(authResponse -> createAuthResponse(authResponse, response))
|
||||
// Token inconnu/expiré -> 204 aussi, pas d'erreur réseau
|
||||
// token expiré / invalide -> 204 aussi (pas d’erreur réseau)
|
||||
.orElse(ResponseEntity.noContent().build());
|
||||
}
|
||||
|
||||
// --------- Utilitaire pour poser le cookie + réponse ---------
|
||||
// ===================== UTILITAIRE =====================
|
||||
|
||||
private ResponseEntity<AuthResponse> createAuthResponse(AuthResponse authResponse, HttpServletResponse response) {
|
||||
private ResponseEntity<AuthResponse> createAuthResponse(AuthResponse authResponse,
|
||||
HttpServletResponse response) {
|
||||
// Cookie HTTP-only pour le refresh
|
||||
ResponseCookie cookie = ResponseCookie.from("refreshToken", authResponse.refreshToken())
|
||||
.httpOnly(true)
|
||||
.secure(false) // true en prod
|
||||
@@ -110,7 +137,7 @@ public class AuthController {
|
||||
.build();
|
||||
response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());
|
||||
|
||||
// Ne pas renvoyer le refresh token dans le body
|
||||
// On ne renvoie pas le refresh token dans le body
|
||||
return ResponseEntity.ok(new AuthResponse(
|
||||
authResponse.username(),
|
||||
authResponse.accessToken(),
|
||||
|
||||
Reference in New Issue
Block a user