Skip to content

Commit 732cdd9

Browse files
committed
feat: 스터디 룸 jwt 설정 확인
1 parent e43034d commit 732cdd9

File tree

4 files changed

+109
-34
lines changed

4 files changed

+109
-34
lines changed

README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,69 @@
44
<br/>
55
<br/>
66

7+
---
8+
9+
# ✅ PR #1: JWT 인증 통합 완료
10+
11+
## 📋 작업 요약
12+
스터디룸 API에서 하드코딩된 사용자 ID를 제거하고, JWT 인증 시스템을 완전히 통합했습니다.
13+
14+
### 🔄 주요 변경 사항
15+
16+
#### 1. SecurityConfig 수정
17+
- `/api/rooms/**` 경로의 `permitAll()` 제거
18+
- 모든 방 API가 이제 JWT 인증 필수
19+
20+
#### 2. RoomController JWT 통합
21+
- `CurrentUser` 의존성 주입으로 실제 사용자 ID 추출
22+
- 하드코딩된 `Long currentUserId = 1L;` 제거 (10개 메서드)
23+
- 불필요한 `@RequestHeader("Authorization")` 파라미터 제거
24+
25+
### 🔐 인증 흐름
26+
1. **클라이언트 요청**: Authorization 헤더에 "Bearer {token}" 전달
27+
2. **JwtAuthenticationFilter**: 토큰 추출 및 검증
28+
3. **Controller**: `CurrentUser.getUserId()`로 사용자 ID 획득
29+
4. **인증 실패 시**: 401 Unauthorized 자동 응답
30+
31+
### 🧪 테스트 방법
32+
```bash
33+
# 1. 로그인하여 JWT 토큰 받기
34+
POST /api/auth/login
35+
{
36+
"username": "user",
37+
"password": "password"
38+
}
39+
40+
# 2. 토큰으로 방 생성
41+
POST /api/rooms
42+
Authorization: Bearer {받은_토큰}
43+
{
44+
"title": "테스트 방",
45+
"isPrivate": false
46+
}
47+
48+
# 3. 토큰 없이 요청 시 401 에러 확인
49+
POST /api/rooms # ❌ 401 Unauthorized
50+
```
51+
52+
### 📊 영향받는 API 엔드포인트
53+
| 엔드포인트 | 메서드 | 변경 사항 |
54+
|-----------|--------|----------|
55+
| `/api/rooms` | POST | JWT 인증 필수 |
56+
| `/api/rooms/{roomId}/join` | POST | JWT 인증 필수 |
57+
| `/api/rooms/{roomId}/leave` | POST | JWT 인증 필수 |
58+
| `/api/rooms` | GET | JWT 인증 필수 |
59+
| `/api/rooms/{roomId}` | GET | JWT 인증 필수 |
60+
| `/api/rooms/my` | GET | JWT 인증 필수 |
61+
| `/api/rooms/{roomId}` | PUT | JWT 인증 필수 |
62+
| `/api/rooms/{roomId}` | DELETE | JWT 인증 필수 |
63+
| `/api/rooms/{roomId}/members` | GET | JWT 인증 필수 |
64+
| `/api/rooms/popular` | GET | JWT 인증 필수 |
65+
66+
---
67+
<br/>
68+
<br/>
69+
770
# 개발 및 배포 프로세스 & Git 컨벤션 가이드
871
해당 프로젝트는 `dev` 브랜치에서 개발하고, `main`브랜치에서 배포합니다. <br/> <br/>
972
아래에 브랜치 전략, 커밋/PR 컨벤션, 워크플로우 전략, 브랜치 보호 규칙, 응답 데이터 및 예외처리 전략을 정리하였습니다. <br/> <br/>

src/main/java/com/back/domain/studyroom/controller/RoomController.java

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
import com.back.domain.studyroom.entity.RoomMember;
66
import com.back.domain.studyroom.service.RoomService;
77
import com.back.global.common.dto.RsData;
8+
import com.back.global.security.CurrentUser;
89
import io.swagger.v3.oas.annotations.Operation;
910
import io.swagger.v3.oas.annotations.Parameter;
10-
import io.swagger.v3.oas.annotations.media.Content;
11-
import io.swagger.v3.oas.annotations.media.Schema;
1211
import io.swagger.v3.oas.annotations.responses.ApiResponse;
1312
import io.swagger.v3.oas.annotations.responses.ApiResponses;
13+
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
1414
import io.swagger.v3.oas.annotations.tags.Tag;
1515
import jakarta.validation.Valid;
1616
import lombok.RequiredArgsConstructor;
@@ -27,16 +27,18 @@
2727
import java.util.stream.Collectors;
2828

2929
/**
30-
* - 모든 API는 Authorization 헤더 필요 (JWT 토큰)
31-
* - 현재는 임시로 하드코딩된 사용자 ID 사용
32-
* - JWT 연동@CurrentUser 애노테이션으로 교체 예정
30+
* 스터디 룸 관련 API 컨트롤러
31+
* - JWT 인증 필수 (Spring Security + CurrentUser)
32+
* - Swagger에서 테스트"Authorize" 버튼으로 토큰 입력
3333
*/
3434
@RestController
3535
@RequestMapping("/api/rooms")
3636
@RequiredArgsConstructor
3737
@Tag(name = "Room API", description = "스터디 룸 관련 API")
38+
@SecurityRequirement(name = "Bearer Authentication")
3839
public class RoomController {
3940
private final RoomService roomService;
41+
private final CurrentUser currentUser;
4042

4143
@PostMapping
4244
@Operation(
@@ -49,10 +51,9 @@ public class RoomController {
4951
@ApiResponse(responseCode = "401", description = "인증 실패")
5052
})
5153
public ResponseEntity<RsData<RoomResponse>> createRoom(
52-
@Valid @RequestBody CreateRoomRequest request,
53-
@RequestHeader("Authorization") String authorization) {
54+
@Valid @RequestBody CreateRoomRequest request) {
5455

55-
Long currentUserId = 1L; // 임시 하드코딩 - JWT 연동 시 @CurrentUser로 교체
56+
Long currentUserId = currentUser.getUserId();
5657

5758
Room room = roomService.createRoom(
5859
request.getTitle(),
@@ -83,10 +84,9 @@ public ResponseEntity<RsData<RoomResponse>> createRoom(
8384
})
8485
public ResponseEntity<RsData<JoinRoomResponse>> joinRoom(
8586
@Parameter(description = "방 ID", required = true) @PathVariable Long roomId,
86-
@RequestBody(required = false) JoinRoomRequest request,
87-
@RequestHeader("Authorization") String authorization) {
87+
@RequestBody(required = false) JoinRoomRequest request) {
8888

89-
Long currentUserId = 1L; // 임시 하드코딩
89+
Long currentUserId = currentUser.getUserId();
9090

9191
String password = null;
9292
if (request != null) {
@@ -112,10 +112,9 @@ public ResponseEntity<RsData<JoinRoomResponse>> joinRoom(
112112
@ApiResponse(responseCode = "401", description = "인증 실패")
113113
})
114114
public ResponseEntity<RsData<Void>> leaveRoom(
115-
@Parameter(description = "방 ID", required = true) @PathVariable Long roomId,
116-
@RequestHeader("Authorization") String authorization) {
115+
@Parameter(description = "방 ID", required = true) @PathVariable Long roomId) {
117116

118-
Long currentUserId = 1L; // 임시 하드코딩
117+
Long currentUserId = currentUser.getUserId();
119118

120119
roomService.leaveRoom(roomId, currentUserId);
121120

@@ -169,10 +168,9 @@ public ResponseEntity<RsData<Map<String, Object>>> getRooms(
169168
@ApiResponse(responseCode = "401", description = "인증 실패")
170169
})
171170
public ResponseEntity<RsData<RoomDetailResponse>> getRoomDetail(
172-
@Parameter(description = "방 ID", required = true) @PathVariable Long roomId,
173-
@RequestHeader("Authorization") String authorization) {
171+
@Parameter(description = "방 ID", required = true) @PathVariable Long roomId) {
174172

175-
Long currentUserId = 1L; // 임시 하드코딩
173+
Long currentUserId = currentUser.getUserId();
176174

177175
Room room = roomService.getRoomDetail(roomId, currentUserId);
178176
List<RoomMember> members = roomService.getRoomMembers(roomId, currentUserId);
@@ -197,10 +195,9 @@ public ResponseEntity<RsData<RoomDetailResponse>> getRoomDetail(
197195
@ApiResponse(responseCode = "200", description = "조회 성공"),
198196
@ApiResponse(responseCode = "401", description = "인증 실패")
199197
})
200-
public ResponseEntity<RsData<List<MyRoomResponse>>> getMyRooms(
201-
@RequestHeader("Authorization") String authorization) {
198+
public ResponseEntity<RsData<List<MyRoomResponse>>> getMyRooms() {
202199

203-
Long currentUserId = 1L; // 임시 하드코딩
200+
Long currentUserId = currentUser.getUserId();
204201

205202
List<Room> rooms = roomService.getUserRooms(currentUserId);
206203

@@ -230,10 +227,9 @@ public ResponseEntity<RsData<List<MyRoomResponse>>> getMyRooms(
230227
})
231228
public ResponseEntity<RsData<Void>> updateRoom(
232229
@Parameter(description = "방 ID", required = true) @PathVariable Long roomId,
233-
@Valid @RequestBody UpdateRoomSettingsRequest request,
234-
@RequestHeader("Authorization") String authorization) {
230+
@Valid @RequestBody UpdateRoomSettingsRequest request) {
235231

236-
Long currentUserId = 1L; // 임시 하드코딩
232+
Long currentUserId = currentUser.getUserId();
237233

238234
roomService.updateRoomSettings(
239235
roomId,
@@ -263,10 +259,9 @@ public ResponseEntity<RsData<Void>> updateRoom(
263259
@ApiResponse(responseCode = "401", description = "인증 실패")
264260
})
265261
public ResponseEntity<RsData<Void>> deleteRoom(
266-
@Parameter(description = "방 ID", required = true) @PathVariable Long roomId,
267-
@RequestHeader("Authorization") String authorization) {
262+
@Parameter(description = "방 ID", required = true) @PathVariable Long roomId) {
268263

269-
Long currentUserId = 1L; // 임시 하드코딩
264+
Long currentUserId = currentUser.getUserId();
270265

271266
roomService.terminateRoom(roomId, currentUserId);
272267

@@ -287,10 +282,9 @@ public ResponseEntity<RsData<Void>> deleteRoom(
287282
@ApiResponse(responseCode = "401", description = "인증 실패")
288283
})
289284
public ResponseEntity<RsData<List<RoomMemberResponse>>> getRoomMembers(
290-
@Parameter(description = "방 ID", required = true) @PathVariable Long roomId,
291-
@RequestHeader("Authorization") String authorization) {
285+
@Parameter(description = "방 ID", required = true) @PathVariable Long roomId) {
292286

293-
Long currentUserId = 1L; // 임시 하드코딩
287+
Long currentUserId = currentUser.getUserId();
294288

295289
List<RoomMember> members = roomService.getRoomMembers(roomId, currentUserId);
296290

src/main/java/com/back/global/config/SpringDocConfig.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,35 @@
11
package com.back.global.config;
22

3-
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
4-
import io.swagger.v3.oas.annotations.info.Info;
3+
import io.swagger.v3.oas.models.Components;
4+
import io.swagger.v3.oas.models.OpenAPI;
5+
import io.swagger.v3.oas.models.info.Info;
6+
import io.swagger.v3.oas.models.security.SecurityRequirement;
7+
import io.swagger.v3.oas.models.security.SecurityScheme;
58
import org.springdoc.core.models.GroupedOpenApi;
69
import org.springframework.context.annotation.Bean;
710
import org.springframework.context.annotation.Configuration;
811

912
@Configuration
10-
@OpenAPIDefinition(info = @Info(title = "Catfe API 서버", version = "beta", description = "Catfe API 문서입니다."))
1113
public class SpringDocConfig {
1214

13-
// API 버전별 그룹화
15+
@Bean
16+
public OpenAPI openAPI() {
17+
String securitySchemeName = "Bearer Authentication";
18+
19+
return new OpenAPI()
20+
.info(new Info()
21+
.title("Catfe API 서버")
22+
.version("beta")
23+
.description("Catfe API 문서입니다."))
24+
.addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
25+
.components(new Components()
26+
.addSecuritySchemes(securitySchemeName, new SecurityScheme()
27+
.name(securitySchemeName)
28+
.type(SecurityScheme.Type.HTTP)
29+
.scheme("bearer")
30+
.bearerFormat("JWT")));
31+
}
32+
1433
@Bean
1534
public GroupedOpenApi groupApiV1() {
1635
return GroupedOpenApi.builder()

src/main/java/com/back/global/security/SecurityConfig.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
2929
.authorizeHttpRequests(
3030
auth -> auth
3131
.requestMatchers("/api/auth/**").permitAll()
32-
.requestMatchers("/api/rooms/**").permitAll() // 테스트용 임시 허용
3332
.requestMatchers("/","/swagger-ui/**", "/v3/api-docs/**").permitAll() // Swagger 허용
3433
.requestMatchers("/h2-console/**").permitAll() // H2 Console 허용
3534
.anyRequest().authenticated()

0 commit comments

Comments
 (0)