Skip to content

Commit d39c69d

Browse files
authored
Merge pull request #38 from Dalguring/feature/ming/user-1
민지 | 2026-01-29 | 로그인 토큰 값 쿠키 저장 로직 추가 및 API 문서 응답 메시지 수정
2 parents c0e949f + 5ba0850 commit d39c69d

File tree

8 files changed

+129
-48
lines changed

8 files changed

+129
-48
lines changed

src/main/java/com/rentify/rentify_api/category/controller/CategoryApiDocs.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public interface CategoryApiDocs {
2525
{
2626
"success": true,
2727
"code": "SUCCESS",
28-
"message": "요청이 성공했습니다.",
28+
"message": "요청이 성공적으로 처리되었습니다.",
2929
"data": {
3030
"categories": [
3131
{

src/main/java/com/rentify/rentify_api/common/response/ApiResponse.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ public class ApiResponse<T> {
1414

1515
// success
1616
public static <T> ApiResponse<T> success(T data) {
17-
return new ApiResponse<>(true, "SUCCESS", "요청이 성공했습니다.", data);
17+
return new ApiResponse<>(true, "SUCCESS", "요청이 성공적으로 처리되었습니다.", data);
1818
}
1919

2020
public static <T> ApiResponse<T> success(String message, T data) {
2121
return new ApiResponse<>(true, "SUCCESS", message, data);
2222
}
2323

2424
public static ApiResponse<Void> success() {
25-
return new ApiResponse<>(true, "SUCCESS", "요청이 성공했습니다.", null);
25+
return new ApiResponse<>(true, "SUCCESS", "요청이 성공적으로 처리되었습니다.", null);
2626
}
2727

2828
public static ApiResponse<Void> success(String message) {

src/main/java/com/rentify/rentify_api/post/controller/PostApiDocs.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ ResponseEntity<com.rentify.rentify_api.common.response.ApiResponse<Void>> getPos
5050
{
5151
"success": true,
5252
"code": "SUCCESS",
53-
"message": "요청이 성공했습니다.",
53+
"message": "요청이 성공적으로 처리되었습니다.",
5454
"data": {
5555
"categoryName": "갤럭시 울트라",
5656
"createAt": "2026-01-28T20:55:58.522954",

src/main/java/com/rentify/rentify_api/user/controller/AuthApi.java

Lines changed: 0 additions & 34 deletions
This file was deleted.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.rentify.rentify_api.user.controller;
2+
3+
import com.rentify.rentify_api.user.dto.AuthMeResponse;
4+
import io.swagger.v3.oas.annotations.Operation;
5+
import io.swagger.v3.oas.annotations.media.Content;
6+
import io.swagger.v3.oas.annotations.media.Schema;
7+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
8+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
9+
import io.swagger.v3.oas.annotations.tags.Tag;
10+
import org.springframework.http.ResponseEntity;
11+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
12+
import org.springframework.web.bind.annotation.GetMapping;
13+
14+
@Tag(name = "Auth", description = "인증 API")
15+
public interface AuthApiDocs {
16+
17+
@Operation(
18+
summary = "내 정보 조회",
19+
description = "쿠키에 저장된 JWT accessToken으로 현재 로그인한 사용자 정보를 조회합니다."
20+
)
21+
@ApiResponses({
22+
@ApiResponse(
23+
responseCode = "200",
24+
description = "인증 성공 - 사용자 정보 반환 (userId, email, name)",
25+
content = @Content(
26+
mediaType = "application/json",
27+
schema = @Schema(implementation = com.rentify.rentify_api.common.response.ApiResponse.class),
28+
examples = @io.swagger.v3.oas.annotations.media.ExampleObject(
29+
value = "{\"success\": true, \"code\": \"SUCCESS\", \"message\": \"요청이 성공적으로 처리되었습니다.\", \"data\": {\"userId\": 1, \"email\": \"[email protected]\", \"name\": \"홍길동\"}}"
30+
)
31+
)
32+
),
33+
@ApiResponse(
34+
responseCode = "403",
35+
description = "인증 실패 - 토큰이 없거나 유효하지 않음",
36+
content = @Content(
37+
mediaType = "application/json",
38+
examples = @io.swagger.v3.oas.annotations.media.ExampleObject(
39+
value = ""
40+
)
41+
)
42+
)
43+
})
44+
@GetMapping("/me")
45+
ResponseEntity<com.rentify.rentify_api.common.response.ApiResponse<AuthMeResponse>> me(@AuthenticationPrincipal Long userId);
46+
}

src/main/java/com/rentify/rentify_api/user/controller/AuthController.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33

44
import com.rentify.rentify_api.common.response.ApiResponse;
55
import com.rentify.rentify_api.user.dto.AuthMeResponse;
6-
import com.rentify.rentify_api.user.dto.UserResponse;
76
import com.rentify.rentify_api.user.service.AuthService;
8-
import com.rentify.rentify_api.user.service.UserService;
97
import lombok.RequiredArgsConstructor;
108
import org.springframework.http.ResponseEntity;
119
import org.springframework.web.bind.annotation.GetMapping;
@@ -16,18 +14,14 @@
1614
@RestController
1715
@RequiredArgsConstructor
1816
@RequestMapping("/auth")
19-
public class AuthController implements AuthApi {
17+
public class AuthController implements AuthApiDocs {
2018

2119
private final AuthService authService;
2220

2321
@GetMapping("/me")
22+
@Override
2423
public ResponseEntity<ApiResponse<AuthMeResponse>> me(@AuthenticationPrincipal Long userId) {
2524
AuthMeResponse response = authService.getMe(userId);
2625
return ResponseEntity.ok(ApiResponse.success(response));
2726
}
28-
29-
@Override
30-
public ResponseEntity<AuthMeResponse> me() {
31-
return null;
32-
}
3327
}

src/main/java/com/rentify/rentify_api/user/controller/UserApiDocs.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.rentify.rentify_api.user.controller;
22

33
import com.rentify.rentify_api.user.dto.CreateUserRequest;
4+
import com.rentify.rentify_api.user.dto.LoginRequest;
45
import io.swagger.v3.oas.annotations.Operation;
56
import io.swagger.v3.oas.annotations.Parameter;
67
import io.swagger.v3.oas.annotations.enums.ParameterIn;
@@ -12,6 +13,7 @@
1213
import io.swagger.v3.oas.annotations.responses.ApiResponse;
1314
import io.swagger.v3.oas.annotations.responses.ApiResponses;
1415
import io.swagger.v3.oas.annotations.tags.Tag;
16+
import jakarta.servlet.http.HttpServletResponse;
1517
import jakarta.validation.Valid;
1618
import java.util.UUID;
1719
import org.springframework.http.HttpHeaders;
@@ -92,4 +94,66 @@ ResponseEntity<com.rentify.rentify_api.common.response.ApiResponse<Void>> create
9294
)
9395
@Valid CreateUserRequest request
9496
);
97+
98+
@Operation(summary = "로그인", description = "이메일과 비밀번호로 로그인하여 JWT 토큰을 쿠키로 발급받습니다.")
99+
@ApiResponses(value = {
100+
@ApiResponse(
101+
responseCode = "200",
102+
description = "로그인 성공 (JWT 토큰이 쿠키에 설정됨)",
103+
headers = @Header(
104+
name = "Set-Cookie",
105+
description = "accessToken (HttpOnly, 24시간 유효)",
106+
schema = @Schema(type = "string", example = "accessToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...; Path=/; Max-Age=86400; HttpOnly")
107+
),
108+
content = @Content(
109+
mediaType = "application/json",
110+
examples = @ExampleObject(
111+
value = "{\"success\": true, \"code\": \"SUCCESS\", \"message\": \"로그인 성공\", \"data\": null}"
112+
)
113+
)
114+
),
115+
@ApiResponse(
116+
responseCode = "401",
117+
description = "인증 실패",
118+
content = @Content(
119+
mediaType = "application/json",
120+
examples = {
121+
@ExampleObject(
122+
name = "비밀번호 불일치",
123+
value = "{\"success\": false, \"code\": \"INVALID_PASSWORD\", \"message\": \"비밀번호가 일치하지 않습니다.\", \"data\": null}"
124+
),
125+
@ExampleObject(
126+
name = "비활성화된 계정",
127+
value = "{\"success\": false, \"code\": \"ACCOUNT_DEACTIVATED\", \"message\": \"비활성화된 계정입니다.\", \"data\": null}"
128+
)
129+
}
130+
)
131+
),
132+
@ApiResponse(
133+
responseCode = "404",
134+
description = "사용자를 찾을 수 없음",
135+
content = @Content(
136+
mediaType = "application/json",
137+
examples = @ExampleObject(
138+
value = "{\"success\": false, \"code\": \"NOT_FOUND\", \"message\": \"존재하지 않는 사용자입니다.\", \"data\": null}"
139+
)
140+
)
141+
)
142+
})
143+
@PostMapping("/login")
144+
ResponseEntity<com.rentify.rentify_api.common.response.ApiResponse<Void>> login(
145+
@RequestBody(
146+
description = "로그인 요청 데이터",
147+
required = true,
148+
content = @Content(
149+
mediaType = "application/json",
150+
schema = @Schema(implementation = LoginRequest.class),
151+
examples = @ExampleObject(
152+
value = "{\"email\": \"[email protected]\", \"password\": \"1234\"}"
153+
)
154+
)
155+
)
156+
@org.springframework.web.bind.annotation.RequestBody LoginRequest request,
157+
HttpServletResponse httpResponse
158+
);
95159
}

src/main/java/com/rentify/rentify_api/user/controller/UserController.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import com.rentify.rentify_api.user.dto.UserResponse;
77
import com.rentify.rentify_api.user.entity.LoginResponse;
88
import com.rentify.rentify_api.user.service.UserService;
9+
import jakarta.servlet.http.Cookie;
10+
import jakarta.servlet.http.HttpServletResponse;
911
import jakarta.validation.Valid;
1012
import java.net.URI;
1113
import java.util.UUID;
@@ -47,10 +49,19 @@ public ResponseEntity<ApiResponse<UserResponse>> getUserById(@PathVariable Long
4749
}
4850

4951
@PostMapping("/login")
50-
public ResponseEntity<ApiResponse<LoginResponse>> login(@RequestBody LoginRequest request) {
52+
@Override
53+
public ResponseEntity<ApiResponse<Void>> login(@RequestBody LoginRequest request, HttpServletResponse httpResponse) {
5154
LoginResponse response = userService.login(request);
5255

53-
return ResponseEntity.ok(ApiResponse.success(response));
56+
// JWT 토큰 쿠키 설정
57+
Cookie cookie = new Cookie("accessToken", response.getAccessToken());
58+
cookie.setHttpOnly(true); // XSS 공격 방지
59+
//cookie.setSecure(true); // HTTPS에서만 전송
60+
cookie.setPath("/");
61+
cookie.setMaxAge(24 * 60 * 60); // 24시간 (초 단위)
62+
httpResponse.addCookie(cookie);
63+
64+
return ResponseEntity.ok(ApiResponse.success("로그인 성공"));
5465
}
5566

5667
@PostMapping("/logout")

0 commit comments

Comments
 (0)