Skip to content

Commit 4660fee

Browse files
authored
Refactor: 로그인 API 응답 구조 수정 (#82) (#84)
* Ref: 로그인 API 수정 * Docs: Swagger 문서 수정 * Test: 테스트 수정
1 parent da65d32 commit 4660fee

File tree

6 files changed

+48
-46
lines changed

6 files changed

+48
-46
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.back.domain.user.controller;
22

33
import com.back.domain.user.dto.LoginRequest;
4+
import com.back.domain.user.dto.LoginResponse;
45
import com.back.domain.user.dto.UserRegisterRequest;
56
import com.back.domain.user.dto.UserResponse;
67
import com.back.domain.user.service.UserService;
@@ -40,11 +41,11 @@ public ResponseEntity<RsData<UserResponse>> register(
4041

4142
// 로그인
4243
@PostMapping("/login")
43-
public ResponseEntity<RsData<UserResponse>> login(
44+
public ResponseEntity<RsData<LoginResponse>> login(
4445
@Valid @RequestBody LoginRequest request,
4546
HttpServletResponse response
4647
) {
47-
UserResponse loginResponse = userService.login(request, response);
48+
LoginResponse loginResponse = userService.login(request, response);
4849
return ResponseEntity
4950
.ok(RsData.success(
5051
"로그인에 성공했습니다.",

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

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.back.domain.user.controller;
22

33
import com.back.domain.user.dto.LoginRequest;
4+
import com.back.domain.user.dto.LoginResponse;
45
import com.back.domain.user.dto.UserRegisterRequest;
56
import com.back.domain.user.dto.UserResponse;
67
import com.back.global.common.dto.RsData;
@@ -130,8 +131,7 @@ ResponseEntity<RsData<UserResponse>> register(
130131

131132
@Operation(
132133
summary = "로그인",
133-
description = "username + password로 로그인합니다. " +
134-
"로그인 성공 시 Access Token은 `Authorization` 헤더에, Refresh Token은 HttpOnly 쿠키로 발급됩니다."
134+
description = "username + password로 로그인합니다. "
135135
)
136136
@ApiResponses({
137137
@ApiResponse(
@@ -145,13 +145,16 @@ ResponseEntity<RsData<UserResponse>> register(
145145
"code": "SUCCESS_200",
146146
"message": "로그인에 성공했습니다.",
147147
"data": {
148-
"userId": 1,
149-
"username": "testuser",
150-
"email": "[email protected]",
151-
"nickname": "홍길동",
152-
"role": "USER",
153-
"status": "ACTIVE",
154-
"createdAt": "2025-09-19T15:00:00"
148+
"accessToken": "{accessToken}",
149+
"user": {
150+
"userId": 1,
151+
"username": "testuser",
152+
"email": "[email protected]",
153+
"nickname": "홍길동",
154+
"role": "USER",
155+
"status": "ACTIVE",
156+
"createdAt": "2025-09-19T15:00:00"
157+
}
155158
}
156159
}
157160
""")
@@ -228,7 +231,7 @@ ResponseEntity<RsData<UserResponse>> register(
228231
)
229232
)
230233
})
231-
ResponseEntity<RsData<UserResponse>> login(
234+
ResponseEntity<RsData<LoginResponse>> login(
232235
@Valid @RequestBody LoginRequest request,
233236
HttpServletResponse response
234237
);
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.back.domain.user.dto;
2+
3+
public record LoginResponse(
4+
String accessToken,
5+
UserResponse user
6+
) {}

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.back.domain.user.service;
22

33
import com.back.domain.user.dto.LoginRequest;
4+
import com.back.domain.user.dto.LoginResponse;
45
import com.back.domain.user.dto.UserRegisterRequest;
56
import com.back.domain.user.dto.UserResponse;
67
import com.back.domain.user.entity.User;
@@ -87,9 +88,9 @@ public UserResponse register(UserRegisterRequest request) {
8788
* 2. 사용자 상태 검증 (PENDING, SUSPENDED, DELETED)
8889
* 3. Access/Refresh Token 발급
8990
* 4. Refresh Token을 HttpOnly 쿠키로, Access Token은 헤더로 설정
90-
* 5. UserResponse 반환
91+
* 5. LoginResponse 반환
9192
*/
92-
public UserResponse login(LoginRequest request, HttpServletResponse response) {
93+
public LoginResponse login(LoginRequest request, HttpServletResponse response) {
9394
// 사용자 조회
9495
User user = userRepository.findByUsername(request.username())
9596
.orElseThrow(() -> new CustomException(ErrorCode.INVALID_CREDENTIALS));
@@ -127,11 +128,11 @@ public UserResponse login(LoginRequest request, HttpServletResponse response) {
127128
"/api/auth"
128129
);
129130

130-
// Access Token을 응답 헤더에 설정
131-
response.setHeader("Authorization", "Bearer " + accessToken);
132-
133-
// UserResponse 반환
134-
return UserResponse.from(user, user.getUserProfile());
131+
// LoginResponse 반환
132+
return new LoginResponse(
133+
accessToken,
134+
UserResponse.from(user, user.getUserProfile())
135+
);
135136
}
136137

137138
/**

src/test/java/com/back/domain/user/controller/AuthControllerTest.java

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
import com.back.domain.user.entity.UserStatus;
66
import com.back.domain.user.repository.UserRepository;
77
import com.back.fixture.TestJwtTokenProvider;
8-
import io.jsonwebtoken.Jwts;
9-
import io.jsonwebtoken.SignatureAlgorithm;
108
import jakarta.servlet.http.Cookie;
119
import org.junit.jupiter.api.DisplayName;
1210
import org.junit.jupiter.api.Test;
@@ -20,9 +18,6 @@
2018
import org.springframework.test.web.servlet.ResultActions;
2119
import org.springframework.transaction.annotation.Transactional;
2220

23-
import java.util.Date;
24-
25-
import static org.assertj.core.api.Assertions.assertThat;
2621
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
2722
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
2823
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@@ -202,7 +197,7 @@ void register_invalidRequest_missingField() throws Exception {
202197
}
203198

204199
@Test
205-
@DisplayName("정상 로그인 → 200 OK + Authorization 헤더 + refreshToken 쿠키")
200+
@DisplayName("정상 로그인 → 200 OK + accessToken + refreshToken 쿠키")
206201
void login_success() throws Exception {
207202
// given: 회원가입 요청으로 DB에 정상 유저 저장
208203
String rawPassword = "P@ssw0rd!";
@@ -233,12 +228,12 @@ void login_success() throws Exception {
233228
.content(loginBody))
234229
.andDo(print());
235230

236-
// then: 200 OK 응답 + username/Authorization 헤더/refreshToken 쿠키 확인
231+
// then: 200 OK 응답 + username/accessToken/refreshToken 쿠키 확인
237232
resultActions
238233
.andExpect(status().isOk())
239234
.andExpect(jsonPath("$.success").value(true))
240-
.andExpect(jsonPath("$.data.username").value("loginuser"))
241-
.andExpect(header().exists("Authorization"))
235+
.andExpect(jsonPath("$.data.user.username").value("loginuser"))
236+
.andExpect(jsonPath("$.data.accessToken").exists())
242237
.andExpect(cookie().exists("refreshToken"));
243238
}
244239

@@ -484,16 +479,13 @@ void refreshToken_success() throws Exception {
484479
// 기존 AccessToken, RefreshToken 확보
485480
String oldAccessToken = loginResult.andReturn()
486481
.getResponse()
487-
.getHeader("Authorization")
488-
.substring(7); // "Bearer " 제거
482+
.getContentAsString(); // body에서 accessToken 꺼낼 수 있도록 JSON 파싱 필요
483+
489484
String refreshCookie = loginResult.andReturn()
490485
.getResponse()
491486
.getCookie("refreshToken")
492487
.getValue();
493488

494-
// Issued At(발급 시간) 분리를 위해 1초 대기
495-
// Thread.sleep(1000);
496-
497489
// when: 재발급 요청 (RefreshToken 쿠키 포함)
498490
ResultActions refreshResult = mvc.perform(post("/api/auth/refresh")
499491
.cookie(new Cookie("refreshToken", refreshCookie)))
@@ -503,15 +495,11 @@ void refreshToken_success() throws Exception {
503495
refreshResult
504496
.andExpect(status().isOk())
505497
.andExpect(jsonPath("$.success").value(true))
506-
.andExpect(jsonPath("$.data.accessToken").exists())
507-
.andExpect(header().exists("Authorization"));
508-
509-
String newAccessToken = refreshResult.andReturn()
510-
.getResponse()
511-
.getHeader("Authorization")
512-
.substring(7);
498+
.andExpect(jsonPath("$.data.accessToken").exists());
513499

514-
// 새 토큰은 기존 토큰과 달라야 함
500+
// 새 토큰은 기존 토큰과 달라야 함 (파싱 후 비교)
501+
// String newAccessToken = JsonPath.read(refreshResult.andReturn()
502+
// .getResponse().getContentAsString(), "$.data.accessToken");
515503
// assertThat(newAccessToken).isNotEqualTo(oldAccessToken);
516504
}
517505

src/test/java/com/back/domain/user/service/UserServiceTest.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.back.domain.user.service;
22

33
import com.back.domain.user.dto.LoginRequest;
4+
import com.back.domain.user.dto.LoginResponse;
45
import com.back.domain.user.dto.UserRegisterRequest;
56
import com.back.domain.user.dto.UserResponse;
67
import com.back.domain.user.entity.User;
@@ -184,17 +185,19 @@ void login_success() {
184185
MockHttpServletResponse response = new MockHttpServletResponse();
185186

186187
// when: 로그인 요청 실행
187-
UserResponse userResponse = userService.login(
188+
LoginResponse loginResponse = userService.login(
188189
new LoginRequest("loginuser", rawPassword), response);
189190

190191
// then: 응답에 username과 토큰/쿠키가 포함됨
191-
assertThat(userResponse.username()).isEqualTo("loginuser");
192-
assertThat(response.getHeader("Authorization")).startsWith("Bearer ");
192+
assertThat(loginResponse.user().username()).isEqualTo("loginuser");
193+
assertThat(loginResponse.accessToken()).isNotBlank();
194+
193195
Cookie refreshCookie = response.getCookie("refreshToken");
194196
assertThat(refreshCookie).isNotNull();
195197
assertThat(refreshCookie.isHttpOnly()).isTrue();
196198
}
197199

200+
198201
@Test
199202
@DisplayName("잘못된 비밀번호 → INVALID_CREDENTIALS 예외 발생")
200203
void login_invalidPassword() {
@@ -332,8 +335,8 @@ void refreshToken_success() throws InterruptedException {
332335
User user = setupUser("refreshuser", "[email protected]", rawPassword, "닉네임", UserStatus.ACTIVE);
333336
MockHttpServletResponse loginResponse = new MockHttpServletResponse();
334337

335-
userService.login(new LoginRequest("refreshuser", rawPassword), loginResponse);
336-
String oldAccessToken = loginResponse.getHeader("Authorization").substring(7);
338+
LoginResponse loginRes = userService.login(new LoginRequest("refreshuser", rawPassword), loginResponse);
339+
String oldAccessToken = loginRes.accessToken();
337340
Cookie refreshCookie = loginResponse.getCookie("refreshToken");
338341
assertThat(refreshCookie).isNotNull();
339342

0 commit comments

Comments
 (0)