Skip to content

Commit 87ef195

Browse files
authored
Feat: 스터디룸 JWT 인증 통합 (#86) (#93)
* feat: dto 도입과 스터디룸 설정 외부화 * feat: 상태 검증, n+1 문제 해결, 동시성 제어 추가 * refactor: 스터디룸 레퍼지토리 쿼리dsl 타입으로 안정성 추가 * refactor: 스터디름 스웨거 어노테이션 추가 * Test: 지금까지 만들어왔던 테스트코드 정리 * Test: 테스트 룸 컨트롤러단에서 SecurityConfig 제외 * Test:룸 컨트롤러 webMvcTest제거, 단위테스트로 진행 * fix: 코드리뷰 받은 문서파일 제거 * feat: 스터디 룸 jwt 설정 확인 * test: 스터디룸 jwt 테스트 코드 통합 * Fix: 스터디 룸 내 잡혀 있어 오류난 룸 채팅 파트 부분 허용 * fix: 룸 채팅 api path 재 확인 후 허용 경로 수정
1 parent 0104908 commit 87ef195

File tree

5 files changed

+128
-85
lines changed

5 files changed

+128
-85
lines changed

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# 개발 및 배포 프로세스 & Git 컨벤션 가이드
88
해당 프로젝트는 `dev` 브랜치에서 개발하고, `main`브랜치에서 배포합니다. <br/> <br/>
99
아래에 브랜치 전략, 커밋/PR 컨벤션, 워크플로우 전략, 브랜치 보호 규칙, 응답 데이터 및 예외처리 전략을 정리하였습니다. <br/> <br/>
10-
개발 전에 꼭 읽어봐주세요!
10+
개발 전에 꼭 읽어봐주세요!
1111
<br/>
1212
<br/>
1313

@@ -21,7 +21,7 @@
2121
- 안정화된 코드를 머지하여 배포
2222
- `dev``main` PR은 관리자 혹은 릴리즈 담당자만 생성 및 승인 가능
2323
- 직접 push 및 외부 PR 제한
24-
<br/>
24+
<br/>
2525

2626
## 2. 커밋/PR 컨벤션
2727

@@ -153,11 +153,11 @@ public ResponseEntity<RsData<Void>> handleCustomException(
153153
// 응답 데이터 예시 (json)
154154

155155
{
156-
"code": ErrorCode.code,
157-
"message": ErrorCode.message,
158-
"data": {...} or {null},
159-
"success": false
160-
}
156+
"code": ErrorCode.code,
157+
"message": ErrorCode.message,
158+
"data": {...} or {null},
159+
"success": false
160+
}
161161
```
162162

163163
<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: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
3030
auth -> auth
3131
.requestMatchers("/api/auth/**").permitAll()
3232
.requestMatchers("/api/ws/**").permitAll()
33-
.requestMatchers("/api/rooms/**").permitAll() // 테스트용 임시 허용
33+
.requestMatchers("/api/rooms/*/messages/**").permitAll() //스터디 룸 내에 잡혀있어 있는 채팅 관련 전체 허용
34+
//.requestMatchers("/api/rooms/RoomChatApiControllerTest").permitAll() // 테스트용 임시 허용
3435
.requestMatchers("/","/swagger-ui/**", "/v3/api-docs/**").permitAll() // Swagger 허용
3536
.requestMatchers("/h2-console/**").permitAll() // H2 Console 허용
3637
.anyRequest().authenticated()

0 commit comments

Comments
 (0)