diff --git a/src/main/java/com/onixbyte/deltaforceguide/controller/AuthController.java b/src/main/java/com/onixbyte/deltaforceguide/controller/AuthController.java index db0f42e..4648bb3 100644 --- a/src/main/java/com/onixbyte/deltaforceguide/controller/AuthController.java +++ b/src/main/java/com/onixbyte/deltaforceguide/controller/AuthController.java @@ -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 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 logout() { - var expiredCookie = cookieService.buildCookie(CookieName.ACCESS_TOKEN, "", Duration.ZERO); + var expiredCookie = authService.logout(); return ResponseEntity.noContent() .header(HttpHeaders.SET_COOKIE, expiredCookie.toString()) .build(); diff --git a/src/main/java/com/onixbyte/deltaforceguide/filter/TokenAuthenticationFilter.java b/src/main/java/com/onixbyte/deltaforceguide/filter/TokenAuthenticationFilter.java index 9a1da51..0bbe14f 100644 --- a/src/main/java/com/onixbyte/deltaforceguide/filter/TokenAuthenticationFilter.java +++ b/src/main/java/com/onixbyte/deltaforceguide/filter/TokenAuthenticationFilter.java @@ -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()); } diff --git a/src/main/java/com/onixbyte/deltaforceguide/manager/CookieManager.java b/src/main/java/com/onixbyte/deltaforceguide/manager/CookieManager.java index f6ef16f..209c9dc 100644 --- a/src/main/java/com/onixbyte/deltaforceguide/manager/CookieManager.java +++ b/src/main/java/com/onixbyte/deltaforceguide/manager/CookieManager.java @@ -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(); + } } diff --git a/src/main/java/com/onixbyte/deltaforceguide/service/AuthService.java b/src/main/java/com/onixbyte/deltaforceguide/service/AuthService.java index 440ea31..99743b2 100644 --- a/src/main/java/com/onixbyte/deltaforceguide/service/AuthService.java +++ b/src/main/java/com/onixbyte/deltaforceguide/service/AuthService.java @@ -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 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); + } } diff --git a/src/main/java/com/onixbyte/deltaforceguide/service/CookieService.java b/src/main/java/com/onixbyte/deltaforceguide/service/CookieService.java deleted file mode 100644 index eb93086..0000000 --- a/src/main/java/com/onixbyte/deltaforceguide/service/CookieService.java +++ /dev/null @@ -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(); - } -}