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;
|
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.Cookie;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
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.HttpHeaders;
|
||||||
import org.springframework.http.ResponseCookie;
|
import org.springframework.http.ResponseCookie;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@@ -17,6 +17,12 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/auth")
|
@RequestMapping("/api/auth")
|
||||||
|
@CrossOrigin(
|
||||||
|
origins = "https://dev.vincent-guillet.fr",
|
||||||
|
allowCredentials = "true",
|
||||||
|
allowedHeaders = "*",
|
||||||
|
methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS}
|
||||||
|
)
|
||||||
public class AuthController {
|
public class AuthController {
|
||||||
|
|
||||||
private final AuthService authService;
|
private final AuthService authService;
|
||||||
@@ -25,26 +31,34 @@ public class AuthController {
|
|||||||
this.authService = authService;
|
this.authService = authService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===================== REGISTER =====================
|
||||||
|
|
||||||
@PostMapping("/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))
|
return authService.register(UserMapper.fromDto(dto))
|
||||||
.map((ResponseEntity::ok))
|
.map(authResponse -> createAuthResponse(authResponse, response))
|
||||||
.orElse(ResponseEntity.badRequest().build());
|
.orElse(ResponseEntity.badRequest().build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===================== LOGIN =====================
|
||||||
|
|
||||||
@PostMapping("/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)
|
return authService.authenticate(request)
|
||||||
.map(authResponse -> createAuthResponse(authResponse, response))
|
.map(authResponse -> createAuthResponse(authResponse, response))
|
||||||
.orElse(ResponseEntity.badRequest().build());
|
.orElse(ResponseEntity.badRequest().build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===================== LOGOUT =====================
|
||||||
|
|
||||||
@GetMapping("/logout")
|
@GetMapping("/logout")
|
||||||
public ResponseEntity<Void> logout(HttpServletResponse response) {
|
public ResponseEntity<Void> logout(HttpServletResponse response) {
|
||||||
// Supprime le cookie de refresh token
|
// Supprime le cookie de refresh token
|
||||||
ResponseCookie cookie = ResponseCookie.from("refreshToken", "")
|
ResponseCookie cookie = ResponseCookie.from("refreshToken", "")
|
||||||
.httpOnly(true)
|
.httpOnly(true)
|
||||||
.secure(false) // true en prod
|
.secure(false) // true en prod derrière HTTPS
|
||||||
.path("/")
|
.path("/")
|
||||||
.maxAge(0) // expire immédiatement
|
.maxAge(0) // expire immédiatement
|
||||||
.sameSite("Lax")
|
.sameSite("Lax")
|
||||||
@@ -53,11 +67,16 @@ public class AuthController {
|
|||||||
return ResponseEntity.ok().build();
|
return ResponseEntity.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===================== ME =====================
|
||||||
|
|
||||||
@GetMapping("/me")
|
@GetMapping("/me")
|
||||||
public ResponseEntity<UserDTO> getCurrentUser(HttpServletRequest request) {
|
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) {
|
if (username == null) {
|
||||||
return ResponseEntity.status(401).build(); // Unauthorized
|
return ResponseEntity.status(401).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
return authService.getCurrentUser(username)
|
return authService.getCurrentUser(username)
|
||||||
@@ -65,20 +84,26 @@ public class AuthController {
|
|||||||
.orElse(ResponseEntity.notFound().build());
|
.orElse(ResponseEntity.notFound().build());
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------- REFRESH TOKEN : accepte POST et GET ---------
|
// ===================== REFRESH =====================
|
||||||
|
|
||||||
|
// Accepte POST et GET pour être robuste aux proxies / redirects bizarres
|
||||||
|
|
||||||
@PostMapping("/refresh")
|
@PostMapping("/refresh")
|
||||||
public ResponseEntity<AuthResponse> refreshPost(HttpServletRequest request, HttpServletResponse response) {
|
public ResponseEntity<AuthResponse> refreshPost(HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
return handleRefresh(request, response);
|
return handleRefresh(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/refresh")
|
@GetMapping("/refresh")
|
||||||
public ResponseEntity<AuthResponse> refreshGet(HttpServletRequest request, HttpServletResponse response) {
|
public ResponseEntity<AuthResponse> refreshGet(HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
return handleRefresh(request, response);
|
return handleRefresh(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResponseEntity<AuthResponse> handleRefresh(HttpServletRequest request, HttpServletResponse response) {
|
private ResponseEntity<AuthResponse> handleRefresh(HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
String refreshToken = null;
|
String refreshToken = null;
|
||||||
|
|
||||||
if (request.getCookies() != null) {
|
if (request.getCookies() != null) {
|
||||||
refreshToken = Arrays.stream(request.getCookies())
|
refreshToken = Arrays.stream(request.getCookies())
|
||||||
.filter(c -> "refreshToken".equals(c.getName()))
|
.filter(c -> "refreshToken".equals(c.getName()))
|
||||||
@@ -94,13 +119,15 @@ public class AuthController {
|
|||||||
|
|
||||||
return authService.refresh(refreshToken)
|
return authService.refresh(refreshToken)
|
||||||
.map(authResponse -> createAuthResponse(authResponse, response))
|
.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());
|
.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())
|
ResponseCookie cookie = ResponseCookie.from("refreshToken", authResponse.refreshToken())
|
||||||
.httpOnly(true)
|
.httpOnly(true)
|
||||||
.secure(false) // true en prod
|
.secure(false) // true en prod
|
||||||
@@ -110,7 +137,7 @@ public class AuthController {
|
|||||||
.build();
|
.build();
|
||||||
response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());
|
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(
|
return ResponseEntity.ok(new AuthResponse(
|
||||||
authResponse.username(),
|
authResponse.username(),
|
||||||
authResponse.accessToken(),
|
authResponse.accessToken(),
|
||||||
|
|||||||
Reference in New Issue
Block a user