diff --git a/api/src/main/java/fr/gameovergne/api/controller/auth/AuthController.java b/api/src/main/java/fr/gameovergne/api/controller/auth/AuthController.java index 123cd72..2c72eeb 100644 --- a/api/src/main/java/fr/gameovergne/api/controller/auth/AuthController.java +++ b/api/src/main/java/fr/gameovergne/api/controller/auth/AuthController.java @@ -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 register(@RequestBody UserDTO dto) { + public ResponseEntity 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 authenticate(@RequestBody AuthRequest request, HttpServletResponse response) { + public ResponseEntity authenticate(@RequestBody AuthRequest request, + HttpServletResponse response) { return authService.authenticate(request) .map(authResponse -> createAuthResponse(authResponse, response)) .orElse(ResponseEntity.badRequest().build()); } + // ===================== LOGOUT ===================== + @GetMapping("/logout") public ResponseEntity 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 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 refreshPost(HttpServletRequest request, HttpServletResponse response) { + public ResponseEntity refreshPost(HttpServletRequest request, + HttpServletResponse response) { return handleRefresh(request, response); } @GetMapping("/refresh") - public ResponseEntity refreshGet(HttpServletRequest request, HttpServletResponse response) { + public ResponseEntity refreshGet(HttpServletRequest request, + HttpServletResponse response) { return handleRefresh(request, response); } - private ResponseEntity handleRefresh(HttpServletRequest request, HttpServletResponse response) { + private ResponseEntity 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 createAuthResponse(AuthResponse authResponse, HttpServletResponse response) { + private ResponseEntity 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(),