refactor(auth): centralise cookie building
- Move cookie construction logic into CookieManager - Remove CookieService
This commit is contained in:
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.LoginRequest;
|
||||||
import com.onixbyte.deltaforceguide.domain.dto.UserResponse;
|
import com.onixbyte.deltaforceguide.domain.dto.UserResponse;
|
||||||
import com.onixbyte.deltaforceguide.client.TokenClient;
|
|
||||||
import com.onixbyte.deltaforceguide.security.annotation.RequiresAuth;
|
import com.onixbyte.deltaforceguide.security.annotation.RequiresAuth;
|
||||||
import com.onixbyte.deltaforceguide.service.AuthService;
|
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.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.http.HttpHeaders;
|
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.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* REST controller for user authentication endpoints (login, logout).
|
* REST controller for user authentication endpoints (login, logout).
|
||||||
*
|
*
|
||||||
@@ -31,34 +25,23 @@ import java.time.LocalDateTime;
|
|||||||
public class AuthController {
|
public class AuthController {
|
||||||
|
|
||||||
private final AuthService authService;
|
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.authService = authService;
|
||||||
this.tokenClient = tokenClient;
|
|
||||||
this.cookieService = cookieService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(description = "用户登录")
|
@Operation(description = "用户登录")
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public ResponseEntity<UserResponse> login(@Validated @RequestBody LoginRequest request) {
|
public ResponseEntity<UserResponse> login(@Validated @RequestBody LoginRequest request) {
|
||||||
var user = authService.login(request);
|
var user = authService.login(request);
|
||||||
var currentTime = LocalDateTime.now();
|
return authService.getUserResponseResponseEntity(user);
|
||||||
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)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresAuth
|
@RequiresAuth
|
||||||
@Operation(description = "退出登录")
|
@Operation(description = "退出登录")
|
||||||
@PostMapping("/logout")
|
@PostMapping("/logout")
|
||||||
public ResponseEntity<Void> logout() {
|
public ResponseEntity<Void> logout() {
|
||||||
var expiredCookie = cookieService.buildCookie(CookieName.ACCESS_TOKEN, "", Duration.ZERO);
|
var expiredCookie = authService.logout();
|
||||||
return ResponseEntity.noContent()
|
return ResponseEntity.noContent()
|
||||||
.header(HttpHeaders.SET_COOKIE, expiredCookie.toString())
|
.header(HttpHeaders.SET_COOKIE, expiredCookie.toString())
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ package com.onixbyte.deltaforceguide.filter;
|
|||||||
import com.auth0.jwt.exceptions.JWTVerificationException;
|
import com.auth0.jwt.exceptions.JWTVerificationException;
|
||||||
import com.onixbyte.deltaforceguide.client.TokenClient;
|
import com.onixbyte.deltaforceguide.client.TokenClient;
|
||||||
import com.onixbyte.deltaforceguide.exeption.UnauthorisedException;
|
import com.onixbyte.deltaforceguide.exeption.UnauthorisedException;
|
||||||
|
import com.onixbyte.deltaforceguide.manager.CookieManager;
|
||||||
import com.onixbyte.deltaforceguide.manager.UserManager;
|
import com.onixbyte.deltaforceguide.manager.UserManager;
|
||||||
import com.onixbyte.deltaforceguide.manager.UserRoleManager;
|
import com.onixbyte.deltaforceguide.manager.UserRoleManager;
|
||||||
import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication;
|
import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication;
|
||||||
import com.onixbyte.deltaforceguide.service.CookieService;
|
|
||||||
import jakarta.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.Cookie;
|
import jakarta.servlet.http.Cookie;
|
||||||
@@ -45,20 +45,20 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
private final UserManager userManager;
|
private final UserManager userManager;
|
||||||
private final UserRoleManager userRoleManager;
|
private final UserRoleManager userRoleManager;
|
||||||
private final TokenClient tokenClient;
|
private final TokenClient tokenClient;
|
||||||
private final CookieService cookieService;
|
private final CookieManager cookieManager;
|
||||||
private final HandlerExceptionResolver handlerExceptionResolver;
|
private final HandlerExceptionResolver handlerExceptionResolver;
|
||||||
|
|
||||||
public TokenAuthenticationFilter(
|
public TokenAuthenticationFilter(
|
||||||
UserManager userManager,
|
UserManager userManager,
|
||||||
UserRoleManager userRoleManager,
|
UserRoleManager userRoleManager,
|
||||||
TokenClient tokenClient,
|
TokenClient tokenClient,
|
||||||
CookieService cookieService,
|
CookieManager cookieManager,
|
||||||
HandlerExceptionResolver handlerExceptionResolver
|
HandlerExceptionResolver handlerExceptionResolver
|
||||||
) {
|
) {
|
||||||
this.userManager = userManager;
|
this.userManager = userManager;
|
||||||
this.userRoleManager = userRoleManager;
|
this.userRoleManager = userRoleManager;
|
||||||
this.tokenClient = tokenClient;
|
this.tokenClient = tokenClient;
|
||||||
this.cookieService = cookieService;
|
this.cookieManager = cookieManager;
|
||||||
this.handlerExceptionResolver = handlerExceptionResolver;
|
this.handlerExceptionResolver = handlerExceptionResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
|
|
||||||
if (shouldRenew(decodedToken.getExpiresAt().toInstant())) {
|
if (shouldRenew(decodedToken.getExpiresAt().toInstant())) {
|
||||||
var renewedToken = tokenClient.generateToken(user);
|
var renewedToken = tokenClient.generateToken(user);
|
||||||
var renewedTokenCookie = cookieService.buildCookie("AccessToken", renewedToken);
|
var renewedTokenCookie = cookieManager.buildCookie("AccessToken", renewedToken);
|
||||||
response.addHeader(HttpHeaders.SET_COOKIE, renewedTokenCookie.toString());
|
response.addHeader(HttpHeaders.SET_COOKIE, renewedTokenCookie.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.onixbyte.deltaforceguide.manager;
|
|||||||
|
|
||||||
import com.onixbyte.deltaforceguide.properties.CookieProperties;
|
import com.onixbyte.deltaforceguide.properties.CookieProperties;
|
||||||
import org.springframework.boot.web.server.Cookie;
|
import org.springframework.boot.web.server.Cookie;
|
||||||
|
import org.springframework.http.ResponseCookie;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
@@ -39,4 +40,49 @@ public class CookieManager {
|
|||||||
public Duration getMaxAge() {
|
public Duration getMaxAge() {
|
||||||
return cookieProperties.maxAge();
|
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;
|
package com.onixbyte.deltaforceguide.service;
|
||||||
|
|
||||||
|
import com.onixbyte.deltaforceguide.client.TokenClient;
|
||||||
import com.onixbyte.deltaforceguide.domain.dto.LoginRequest;
|
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.domain.entity.User;
|
||||||
import com.onixbyte.deltaforceguide.exeption.InternalServerErrorException;
|
import com.onixbyte.deltaforceguide.exeption.InternalServerErrorException;
|
||||||
|
import com.onixbyte.deltaforceguide.manager.CookieManager;
|
||||||
import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service handling user authentication, login, and session management.
|
* 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 static final Logger log = LoggerFactory.getLogger(AuthService.class);
|
||||||
private final AuthenticationManager authenticationManager;
|
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.authenticationManager = authenticationManager;
|
||||||
|
this.tokenClient = tokenClient;
|
||||||
|
this.cookieManager = cookieManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,4 +66,19 @@ public class AuthService {
|
|||||||
return authentication.getDetails();
|
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user