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 .dto .AuthResultData ;
14+ import org .tuna .zoopzoop .backend .domain .auth .entity .AuthResult ;
15+ import org .tuna .zoopzoop .backend .domain .auth .entity .RefreshToken ;
16+ import org .tuna .zoopzoop .backend .domain .auth .service .RefreshTokenService ;
1417import 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 ;
1718import org .tuna .zoopzoop .backend .global .rsData .RsData ;
1819import org .tuna .zoopzoop .backend .global .security .jwt .JwtUtil ;
1920
2324@ Tag (name = "ApiV1AuthController" , description = "인증/인가 REST API 컨트롤러" )
2425public class ApiV1AuthController {
2526 private final JwtUtil jwtUtil ;
26- private final MemberService memberService ;
27- private final JwtProperties jwtProperties ;
28- private final KakaoUserInfoService kakaoUserInfoService ;
29- private final WebClient webClient ;
27+ private final RefreshTokenService refreshTokenService ;
28+ private final AuthResult authResult ;
3029
3130 /**
3231 * 사용자 로그아웃 API
3332 * @param response Servlet 기반 웹에서 server -> client로 http 응답을 보내기 위한 객체, 자동 주입.
3433 */
3534 @ GetMapping ("/logout" )
3635 @ Operation (summary = "사용자 로그아웃" )
37- public ResponseEntity <RsData <Void >> logout (HttpServletResponse response ) {
36+ public ResponseEntity <RsData <Void >> logout (
37+ @ CookieValue (name = "sessionId" )
38+ String sessionId ,
39+ HttpServletResponse response ) {
40+
41+ // 서버에서 RefreshToken 삭제
42+ refreshTokenService .deleteBySessionId (sessionId );
43+
44+ // 클라이언트 쿠키 삭제 (AccessToken + SessionId)
3845 ResponseCookie accessCookie = ResponseCookie .from ("accessToken" , "" )
3946 .httpOnly (true )
4047 .path ("/" )
41- .maxAge (0 ) // 쿠키 삭제
48+ .maxAge (0 )
4249 .sameSite ("Lax" )
4350 .build ();
4451
45- ResponseCookie refreshCookie = ResponseCookie .from ("refreshToken " , "" )
52+ ResponseCookie sessionCookie = ResponseCookie .from ("sessionId " , "" )
4653 .httpOnly (true )
4754 .path ("/" )
48- .maxAge (0 ) // 쿠키 삭제
55+ .maxAge (0 )
4956 .sameSite ("Lax" )
5057 .build ();
5158
5259 response .addHeader (HttpHeaders .SET_COOKIE , accessCookie .toString ());
53- response .addHeader (HttpHeaders .SET_COOKIE , refreshCookie .toString ());
60+ response .addHeader (HttpHeaders .SET_COOKIE , sessionCookie .toString ());
5461
5562 return ResponseEntity
5663 .status (HttpStatus .OK )
57- .body (new RsData <>(
58- "200" ,
59- "정상적으로 로그아웃 했습니다." ,
60- null
61- )
62- );
64+ .body (new RsData <>("200" , "정상적으로 로그아웃 했습니다." , null ));
6365 }
6466
6567 /**
6668 * refreshToken 기반으로 accessToken 재발급
67- * @param refreshToken 쿠키에 포함된 현재 로그인한 사용자의 refreshToken
69+ * @param sessionId 쿠키에 포함된 현재 로그인한 사용자의 sessionId.
6870 * @param response Servlet 기반 웹에서 server -> client로 http 응답을 보내기 위한 객체, 자동 주입.
6971 */
7072
7173 @ PostMapping ("/refresh" )
72- @ Operation (summary = "사용자 액세스 토큰 재발급 (리프레시 토큰이 유효할 경우)" )
73- public ResponseEntity <RsData <Void >> refreshToken (@ CookieValue (name = "refreshToken" , required = false ) String refreshToken ,
74- HttpServletResponse response ) {
74+ @ Operation (summary = "사용자 액세스 토큰 재발급 (서버 저장 RefreshToken 사용)" )
75+ public ResponseEntity <RsData <Void >> refreshToken (
76+ @ CookieValue (name = "sessionId" )
77+ String sessionId ,
78+ HttpServletResponse response
79+ ) {
7580
76- if (refreshToken == null || ! jwtUtil . validateToken ( refreshToken ) || ! jwtUtil . isRefreshToken ( refreshToken ) ) {
81+ if (sessionId == null ) {
7782 return ResponseEntity
7883 .status (HttpStatus .UNAUTHORIZED )
79- .body (new RsData <>(
80- "401" ,
81- "유효하지 않은 리프레시 토큰입니다." ,
82- null
83- ));
84+ .body (new RsData <>("401" , "세션이 존재하지 않습니다." , null ));
85+ }
86+
87+ // sessionId로 RefreshToken 조회
88+ RefreshToken refreshTokenEntity ;
89+ try {
90+ refreshTokenEntity = refreshTokenService .getBySessionId (sessionId );
91+ } catch (AuthenticationException e ) {
92+ return ResponseEntity
93+ .status (HttpStatus .UNAUTHORIZED )
94+ .body (new RsData <>("401" , e .getMessage (), null ));
95+ }
96+
97+ String refreshToken = refreshTokenEntity .getRefreshToken ();
98+
99+ // RefreshToken 유효성 검사
100+ if (!jwtUtil .validateToken (refreshToken ) || !jwtUtil .isRefreshToken (refreshToken )) {
101+ return ResponseEntity
102+ .status (HttpStatus .UNAUTHORIZED )
103+ .body (new RsData <>("401" , "유효하지 않은 리프레시 토큰입니다." , null ));
84104 }
85105
86- String providerKey = jwtUtil .getProviderKeyFromToken (refreshToken );
87- Member member = memberService .findByProviderKey (providerKey );
106+ Member member = refreshTokenEntity .getMember ();
88107
108+ // 새 AccessToken 발급
89109 String newAccessToken = jwtUtil .generateToken (member );
90110
91111 ResponseCookie accessCookie = ResponseCookie .from ("accessToken" , newAccessToken )
@@ -97,12 +117,33 @@ public ResponseEntity<RsData<Void>> refreshToken(@CookieValue(name = "refreshTok
97117
98118 response .addHeader (HttpHeaders .SET_COOKIE , accessCookie .toString ());
99119
120+ return ResponseEntity
121+ .status (HttpStatus .OK )
122+ .body (new RsData <>("200" , "액세스 토큰을 재발급 했습니다." , null ));
123+ }
124+
125+ @ GetMapping ("/result" )
126+ @ Operation (summary = "확장프로그램 백그라운드 풀링 대응 API" )
127+ public ResponseEntity <RsData <AuthResultData >> pullingResult (
128+ @ RequestParam String state
129+ ) {
130+ AuthResultData resultData = authResult .get (state );
131+ if (resultData == null ) {
132+ return ResponseEntity
133+ .status (HttpStatus .NOT_FOUND )
134+ .body (new RsData <>(
135+ "404" ,
136+ "state에 해당하는 토큰이 준비되지 않았거나, 잘못된 state 입니다." ,
137+ null
138+ )
139+ );
140+ }
100141 return ResponseEntity
101142 .status (HttpStatus .OK )
102143 .body (new RsData <>(
103- "200" ,
104- "액세스 토큰을 재발급 했습니다 ." ,
105- null
144+ "200" ,
145+ "토큰이 정상적으로 발급되었습니다 ." ,
146+ resultData
106147 ));
107148 }
108149}
0 commit comments