Skip to content

Commit d0d53f0

Browse files
committed
Feat: 로그아웃 API 구현
1 parent 3130646 commit d0d53f0

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

src/main/java/com/back/domain/user/controller/AuthController.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import io.swagger.v3.oas.annotations.Operation;
99
import io.swagger.v3.oas.annotations.responses.ApiResponse;
1010
import io.swagger.v3.oas.annotations.responses.ApiResponses;
11+
import jakarta.servlet.http.HttpServletRequest;
1112
import jakarta.servlet.http.HttpServletResponse;
1213
import jakarta.validation.Valid;
1314
import lombok.RequiredArgsConstructor;
@@ -66,4 +67,24 @@ public ResponseEntity<RsData<UserResponse>> login(
6667
loginResponse
6768
));
6869
}
70+
71+
@PostMapping("/logout")
72+
@Operation(summary = "로그아웃", description = "Refresh Token을 무효화합니다.")
73+
@ApiResponses({
74+
@ApiResponse(responseCode = "200", description = "로그아웃 성공"),
75+
@ApiResponse(responseCode = "400", description = "잘못된 요청"),
76+
@ApiResponse(responseCode = "401", description = "이미 만료되었거나 유효하지 않은 토큰"),
77+
@ApiResponse(responseCode = "500", description = "서버 내부 오류")
78+
})
79+
public ResponseEntity<RsData<Void>> logout(
80+
HttpServletRequest request,
81+
HttpServletResponse response
82+
) {
83+
userService.logout(request, response);
84+
return ResponseEntity
85+
.ok(RsData.success(
86+
"로그아웃 되었습니다.",
87+
null
88+
));
89+
}
6990
}

src/main/java/com/back/domain/user/service/UserService.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,28 @@ public UserResponse login(LoginRequest request, HttpServletResponse response) {
135135
return UserResponse.from(user, user.getUserProfile());
136136
}
137137

138+
public void logout(HttpServletRequest request, HttpServletResponse response) {
139+
// 쿠키에서 Refresh Token 추출
140+
String refreshToken = resolveRefreshToken(request);
141+
142+
// 토큰 검증
143+
if (refreshToken == null || !jwtTokenProvider.validateToken(refreshToken)) {
144+
throw new CustomException(ErrorCode.INVALID_TOKEN);
145+
}
146+
147+
// DB에서 Refresh Token 삭제
148+
userTokenRepository.deleteByRefreshToken(refreshToken);
149+
150+
// TODO: 중복 코드 -> 리팩토링 필요
151+
// 쿠키 삭제
152+
Cookie cookie = new Cookie("refreshToken", null);
153+
cookie.setHttpOnly(true);
154+
cookie.setSecure(true);
155+
cookie.setPath("/api/auth/refresh");
156+
cookie.setMaxAge(0);
157+
response.addCookie(cookie);
158+
}
159+
138160
/**
139161
* 회원가입 시 중복 검증
140162
* - username, email, nickname
@@ -162,4 +184,18 @@ private void validatePasswordPolicy(String password) {
162184
throw new CustomException(ErrorCode.INVALID_PASSWORD);
163185
}
164186
}
187+
188+
/**
189+
* 쿠키에서 Refresh Token 추출
190+
*/
191+
private String resolveRefreshToken(HttpServletRequest request) {
192+
if (request.getCookies() != null) {
193+
for (Cookie cookie : request.getCookies()) {
194+
if ("refreshToken".equals(cookie.getName())) {
195+
return cookie.getValue();
196+
}
197+
}
198+
}
199+
return null;
200+
}
165201
}

0 commit comments

Comments
 (0)