88import org .springframework .http .HttpStatus ;
99import org .springframework .http .ResponseCookie ;
1010import org .springframework .http .ResponseEntity ;
11+ import org .springframework .security .core .AuthenticationException ;
1112import org .springframework .web .bind .annotation .*;
12- import org .springframework . web . reactive . function . client . WebClient ;
13- import org .tuna .zoopzoop .backend .domain .auth .service .KakaoUserInfoService ;
13+ import org .tuna . zoopzoop . backend . domain . auth . entity . RefreshToken ;
14+ import org .tuna .zoopzoop .backend .domain .auth .service .RefreshTokenService ;
1415import org .tuna .zoopzoop .backend .domain .member .entity .Member ;
15- import org .tuna .zoopzoop .backend .domain .member .service .MemberService ;
16- import org .tuna .zoopzoop .backend .global .config .jwt .JwtProperties ;
1716import org .tuna .zoopzoop .backend .global .rsData .RsData ;
1817import org .tuna .zoopzoop .backend .global .security .jwt .JwtUtil ;
1918
2322@ Tag (name = "ApiV1AuthController" , description = "인증/인가 REST API 컨트롤러" )
2423public class ApiV1AuthController {
2524 private final JwtUtil jwtUtil ;
26- private final MemberService memberService ;
27- private final JwtProperties jwtProperties ;
28- private final KakaoUserInfoService kakaoUserInfoService ;
29- private final WebClient webClient ;
25+ private final RefreshTokenService refreshTokenService ;
3026
3127 /**
3228 * 사용자 로그아웃 API
3329 * @param response Servlet 기반 웹에서 server -> client로 http 응답을 보내기 위한 객체, 자동 주입.
3430 */
3531 @ GetMapping ("/logout" )
3632 @ Operation (summary = "사용자 로그아웃" )
37- public ResponseEntity <RsData <Void >> logout (HttpServletResponse response ) {
33+ public ResponseEntity <RsData <Void >> logout (
34+ @ CookieValue (name = "sessionId" )
35+ String sessionId ,
36+ HttpServletResponse response ) {
37+
38+ // 서버에서 RefreshToken 삭제
39+ refreshTokenService .deleteBySessionId (sessionId );
40+
41+ // 클라이언트 쿠키 삭제 (AccessToken + SessionId)
3842 ResponseCookie accessCookie = ResponseCookie .from ("accessToken" , "" )
3943 .httpOnly (true )
4044 .path ("/" )
41- .maxAge (0 ) // 쿠키 삭제
45+ .maxAge (0 )
4246 .sameSite ("Lax" )
4347 .build ();
4448
45- ResponseCookie refreshCookie = ResponseCookie .from ("refreshToken " , "" )
49+ ResponseCookie sessionCookie = ResponseCookie .from ("sessionId " , "" )
4650 .httpOnly (true )
4751 .path ("/" )
48- .maxAge (0 ) // 쿠키 삭제
52+ .maxAge (0 )
4953 .sameSite ("Lax" )
5054 .build ();
5155
5256 response .addHeader (HttpHeaders .SET_COOKIE , accessCookie .toString ());
53- response .addHeader (HttpHeaders .SET_COOKIE , refreshCookie .toString ());
57+ response .addHeader (HttpHeaders .SET_COOKIE , sessionCookie .toString ());
5458
5559 return ResponseEntity
5660 .status (HttpStatus .OK )
57- .body (new RsData <>(
58- "200" ,
59- "정상적으로 로그아웃 했습니다." ,
60- null
61- )
62- );
61+ .body (new RsData <>("200" , "정상적으로 로그아웃 했습니다." , null ));
6362 }
6463
6564 /**
6665 * refreshToken 기반으로 accessToken 재발급
67- * @param refreshToken 쿠키에 포함된 현재 로그인한 사용자의 refreshToken
66+ * @param sessionId 쿠키에 포함된 현재 로그인한 사용자의 sessionId.
6867 * @param response Servlet 기반 웹에서 server -> client로 http 응답을 보내기 위한 객체, 자동 주입.
6968 */
7069
7170 @ PostMapping ("/refresh" )
72- @ Operation (summary = "사용자 액세스 토큰 재발급 (리프레시 토큰이 유효할 경우)" )
73- public ResponseEntity <RsData <Void >> refreshToken (@ CookieValue (name = "refreshToken" , required = false ) String refreshToken ,
74- HttpServletResponse response ) {
71+ @ Operation (summary = "사용자 액세스 토큰 재발급 (서버 저장 RefreshToken 사용)" )
72+ public ResponseEntity <RsData <Void >> refreshToken (
73+ @ CookieValue (name = "sessionId" )
74+ String sessionId ,
75+ HttpServletResponse response
76+ ) {
77+
78+ if (sessionId == null ) {
79+ return ResponseEntity
80+ .status (HttpStatus .UNAUTHORIZED )
81+ .body (new RsData <>("401" , "세션이 존재하지 않습니다." , null ));
82+ }
83+
84+ // sessionId로 RefreshToken 조회
85+ RefreshToken refreshTokenEntity ;
86+ try {
87+ refreshTokenEntity = refreshTokenService .getBySessionId (sessionId );
88+ } catch (AuthenticationException e ) {
89+ return ResponseEntity
90+ .status (HttpStatus .UNAUTHORIZED )
91+ .body (new RsData <>("401" , e .getMessage (), null ));
92+ }
93+
94+ String refreshToken = refreshTokenEntity .getRefreshToken ();
7595
76- if (refreshToken == null || !jwtUtil .validateToken (refreshToken ) || !jwtUtil .isRefreshToken (refreshToken )) {
96+ // RefreshToken 유효성 검사
97+ if (!jwtUtil .validateToken (refreshToken ) || !jwtUtil .isRefreshToken (refreshToken )) {
7798 return ResponseEntity
7899 .status (HttpStatus .UNAUTHORIZED )
79- .body (new RsData <>(
80- "401" ,
81- "유효하지 않은 리프레시 토큰입니다." ,
82- null
83- ));
100+ .body (new RsData <>("401" , "유효하지 않은 리프레시 토큰입니다." , null ));
84101 }
85102
86- String providerKey = jwtUtil .getProviderKeyFromToken (refreshToken );
87- Member member = memberService .findByProviderKey (providerKey );
103+ Member member = refreshTokenEntity .getMember ();
88104
105+ // 새 AccessToken 발급
89106 String newAccessToken = jwtUtil .generateToken (member );
90107
91108 ResponseCookie accessCookie = ResponseCookie .from ("accessToken" , newAccessToken )
@@ -99,10 +116,6 @@ public ResponseEntity<RsData<Void>> refreshToken(@CookieValue(name = "refreshTok
99116
100117 return ResponseEntity
101118 .status (HttpStatus .OK )
102- .body (new RsData <>(
103- "200" ,
104- "액세스 토큰을 재발급 했습니다." ,
105- null
106- ));
119+ .body (new RsData <>("200" , "액세스 토큰을 재발급 했습니다." , null ));
107120 }
108121}
0 commit comments