refactor(auth): centralise cookie building

- Move cookie construction logic into CookieManager
- Remove CookieService
This commit is contained in:
zihluwang committed 2026-08-11 12:48:20 +08:00
1 parent dadd9a7221
commit 1aeefb6733
5 files changed
+89 -93

No files matched your search

@@ -2,11 +2,8 @@ package com.onixbyte.deltaforceguide.controller;
import com.onixbyte.deltaforceguide.domain.dto.LoginRequest;
import com.onixbyte.deltaforceguide.domain.dto.UserResponse;
import com.onixbyte.deltaforceguide.client.TokenClient;
import com.onixbyte.deltaforceguide.security.annotation.RequiresAuth;
import com.onixbyte.deltaforceguide.service.AuthService;
import com.onixbyte.deltaforceguide.service.CookieService;
import com.onixbyte.deltaforceguide.shared.CookieName;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpHeaders;
@@ -17,9 +14,6 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.Duration;
import java.time.LocalDateTime;
/**
* REST controller for user authentication endpoints (login, logout).
*
@@ -31,34 +25,23 @@ import java.time.LocalDateTime;
public class AuthController {
private final AuthService authService;
private final TokenClient tokenClient;
private final CookieService cookieService;
public AuthController(AuthService authService, TokenClient tokenClient, CookieService cookieService) {
public AuthController(AuthService authService) {
this.authService = authService;
this.tokenClient = tokenClient;
this.cookieService = cookieService;
}
@Operation(description = "用户登录")
@PostMapping("/login")
public ResponseEntity<UserResponse> login(@Validated @RequestBody LoginRequest request) {
var user = authService.login(request);
var currentTime = LocalDateTime.now();
var accessToken = tokenClient.generateToken(user);
var accessTokenCookie = cookieService.buildCookie(CookieName.ACCESS_TOKEN, accessToken);
var cookieMaxAge = accessTokenCookie.getMaxAge();
return ResponseEntity.ok()
.header(HttpHeaders.SET_COOKIE, accessTokenCookie.toString())
.body(UserResponse.from(user, currentTime.plus(cookieMaxAge)));
return authService.getUserResponseResponseEntity(user);
}
@RequiresAuth
@Operation(description = "退出登录")
@PostMapping("/logout")
public ResponseEntity<Void> logout() {
var expiredCookie = cookieService.buildCookie(CookieName.ACCESS_TOKEN, "", Duration.ZERO);
var expiredCookie = authService.logout();
return ResponseEntity.noContent()
.header(HttpHeaders.SET_COOKIE, expiredCookie.toString())
.build();
@@ -3,10 +3,10 @@ package com.onixbyte.deltaforceguide.filter;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.onixbyte.deltaforceguide.client.TokenClient;
import com.onixbyte.deltaforceguide.exeption.UnauthorisedException;
import com.onixbyte.deltaforceguide.manager.CookieManager;
import com.onixbyte.deltaforceguide.manager.UserManager;
import com.onixbyte.deltaforceguide.manager.UserRoleManager;
import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication;
import com.onixbyte.deltaforceguide.service.CookieService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
@@ -45,20 +45,20 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
private final UserManager userManager;
private final UserRoleManager userRoleManager;
private final TokenClient tokenClient;
private final CookieService cookieService;
private final CookieManager cookieManager;
private final HandlerExceptionResolver handlerExceptionResolver;
public TokenAuthenticationFilter(
UserManager userManager,
UserRoleManager userRoleManager,
TokenClient tokenClient,
CookieService cookieService,
CookieManager cookieManager,
HandlerExceptionResolver handlerExceptionResolver
) {
this.userManager = userManager;
this.userRoleManager = userRoleManager;
this.tokenClient = tokenClient;
this.cookieService = cookieService;
this.cookieManager = cookieManager;
this.handlerExceptionResolver = handlerExceptionResolver;
}
@@ -102,7 +102,7 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
if (shouldRenew(decodedToken.getExpiresAt().toInstant())) {
var renewedToken = tokenClient.generateToken(user);
var renewedTokenCookie = cookieService.buildCookie("AccessToken", renewedToken);
var renewedTokenCookie = cookieManager.buildCookie("AccessToken", renewedToken);
response.addHeader(HttpHeaders.SET_COOKIE, renewedTokenCookie.toString());
}
@@ -2,6 +2,7 @@ package com.onixbyte.deltaforceguide.manager;
import com.onixbyte.deltaforceguide.properties.CookieProperties;
import org.springframework.boot.web.server.Cookie;
import org.springframework.http.ResponseCookie;
import org.springframework.stereotype.Component;
import java.time.Duration;
@@ -39,4 +40,49 @@ public class CookieManager {
public Duration getMaxAge() {
return cookieProperties.maxAge();
}
/**
* Builds a response cookie with the default max age from configuration.
*
* @param cookieName the cookie name
* @param value the cookie value
* @return a configured ResponseCookie
*/
public ResponseCookie buildCookie(String cookieName, String value) {
return buildCookieInternal(cookieName, value, getMaxAge());
}
/**
* Builds a response cookie with a custom valid duration.
*
* @param cookieName the cookie name
* @param value the cookie value
* @param validDuration the cookie's max age
* @return a configured ResponseCookie
*/
public ResponseCookie buildCookie(String cookieName, String value, Duration validDuration) {
return buildCookieInternal(cookieName, value, validDuration);
}
/**
* Creates a response cookie builder with specified name, value and valid duration.
*
* @param name name of the cookie
* @param value value of the cookie
* @param maxAge valid duration of the cookie
* @return cookie builder
*/
protected ResponseCookie buildCookieInternal(
String name,
String value,
Duration maxAge
) {
return ResponseCookie.from(name, value)
.secure(getSecure())
.maxAge(maxAge)
.httpOnly(getHttpOnly())
.path(getPath())
.sameSite(getSameSite().attributeValue())
.build();
}
}
@@ -1,14 +1,25 @@
package com.onixbyte.deltaforceguide.service;
import com.onixbyte.deltaforceguide.client.TokenClient;
import com.onixbyte.deltaforceguide.domain.dto.LoginRequest;
import com.onixbyte.deltaforceguide.domain.dto.UserResponse;
import com.onixbyte.deltaforceguide.domain.entity.User;
import com.onixbyte.deltaforceguide.exeption.InternalServerErrorException;
import com.onixbyte.deltaforceguide.manager.CookieManager;
import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication;
import com.onixbyte.deltaforceguide.shared.CookieName;
import org.jspecify.annotations.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.stereotype.Service;
import java.time.Duration;
import java.time.LocalDateTime;
/**
* Service handling user authentication, login, and session management.
*
@@ -19,9 +30,17 @@ public class AuthService {
private static final Logger log = LoggerFactory.getLogger(AuthService.class);
private final AuthenticationManager authenticationManager;
private final TokenClient tokenClient;
private final CookieManager cookieManager;
public AuthService(AuthenticationManager authenticationManager) {
public AuthService(
AuthenticationManager authenticationManager,
TokenClient tokenClient,
CookieManager cookieManager
) {
this.authenticationManager = authenticationManager;
this.tokenClient = tokenClient;
this.cookieManager = cookieManager;
}
/**
@@ -47,4 +66,19 @@ public class AuthService {
return authentication.getDetails();
}
@NonNull
public ResponseEntity<UserResponse> getUserResponseResponseEntity(User user) {
var currentTime = LocalDateTime.now();
var accessToken = tokenClient.generateToken(user);
var accessTokenCookie = cookieManager.buildCookie(CookieName.ACCESS_TOKEN, accessToken);
var cookieMaxAge = accessTokenCookie.getMaxAge();
return ResponseEntity.ok()
.header(HttpHeaders.SET_COOKIE, accessTokenCookie.toString())
.body(UserResponse.from(user, currentTime.plus(cookieMaxAge)));
}
public HttpCookie logout() {
return cookieManager.buildCookie(CookieName.ACCESS_TOKEN, "", Duration.ZERO);
}
}
@@ -1,67 +0,0 @@
package com.onixbyte.deltaforceguide.service;
import com.onixbyte.deltaforceguide.manager.CookieManager;
import org.springframework.http.ResponseCookie;
import org.springframework.stereotype.Service;
import java.time.Duration;
/**
* Service for building HTTP cookies with configurable properties.
*
* @author zihluwang
*/
@Service
public class CookieService {
private final CookieManager cookieManager;
public CookieService(CookieManager cookieManager) {
this.cookieManager = cookieManager;
}
/**
* Builds a response cookie with the default max age from configuration.
*
* @param cookieName the cookie name
* @param value the cookie value
* @return a configured ResponseCookie
*/
public ResponseCookie buildCookie(String cookieName, String value) {
return buildCookieInternal(cookieName, value, cookieManager.getMaxAge());
}
/**
* Builds a response cookie with a custom valid duration.
*
* @param cookieName the cookie name
* @param value the cookie value
* @param validDuration the cookie's max age
* @return a configured ResponseCookie
*/
public ResponseCookie buildCookie(String cookieName, String value, Duration validDuration) {
return buildCookieInternal(cookieName, value, validDuration);
}
/**
* Creates a response cookie builder with specified name, value and valid duration.
*
* @param name name of the cookie
* @param value value of the cookie
* @param maxAge valid duration of the cookie
* @return cookie builder
*/
protected ResponseCookie buildCookieInternal(
String name,
String value,
Duration maxAge
) {
return ResponseCookie.from(name, value)
.secure(cookieManager.getSecure())
.maxAge(maxAge)
.httpOnly(cookieManager.getHttpOnly())
.path(cookieManager.getPath())
.sameSite(cookieManager.getSameSite().attributeValue())
.build();
}
}