Skip to content

[FEAT] 비공개방 비밀번호 입력 기반 입장 처리 및 직접 URL 접근 제어#109

Merged
minseokim0113 merged 4 commits intodevfrom
FEAT-방-비밀번호
Dec 26, 2025

Hidden character warning

The head ref may contain hidden characters: "FEAT-\ubc29-\ube44\ubc00\ubc88\ud638"
Merged

[FEAT] 비공개방 비밀번호 입력 기반 입장 처리 및 직접 URL 접근 제어#109
minseokim0113 merged 4 commits intodevfrom
FEAT-방-비밀번호

Conversation

@gaeunnlee
Copy link
Member

@gaeunnlee gaeunnlee commented Dec 25, 2025

📌 작업 내용

  • 비공개방 입장 시 비밀번호 검증 기반으로 접근 제어 로직 구현
  • 공개방 / 비공개방 여부를 클라이언트 파라미터가 아닌 DB 기준으로 판별하도록 수정
  • 비공개방의 경우 비밀번호 검증 성공 시에만 세션에 입장 인증 정보(ROOM_AUTH_<roomId>) 저장
  • 방장(host)은 DB 기준으로 판별하여 비공개방이라도 비밀번호 입력 없이 입장 가능하도록 예외 처리
  • 비공개방에 대해 직접 URL(/room) 접근 시 세션 인증 정보가 없으면 /room/enter로 리다이렉트되도록 제어

🔗 관련 이슈


👀 리뷰 시 참고사항


💭 느낀 점

  • 동적으로 세션에 인증 정보를 저장하고 제거하는 로직을 직접 구현할 수 있게 되었습니다.

💻 스크린샷 (선택)

Summary by CodeRabbit

  • 새로운 기능

    • 비공개 방 비밀번호 보호 및 인증 흐름 추가(입장 시 비밀번호 입력/검증).
    • 클라이언트에서 비공개 방 진입 시 비밀번호를 묻고 제출하는 동작 추가.
  • 버그 수정 / 동작 변경

    • 방 입장 경로가 /room? → /room/enter?로 변경되어 진입 흐름이 업데이트됨.
    • 방 생성 폼의 공개/비공개 값 전달 방식이 역전되어 기본값 해석이 변경됨.
  • 기타

    • 방별 세션 인증 상태를 설정/제거하여 입장·퇴장 시 권한 상태를 관리.

✏️ Tip: You can customize this high-level summary in your review settings.

@gaeunnlee gaeunnlee self-assigned this Dec 25, 2025
@gaeunnlee gaeunnlee added the FEAT 새로운 기능 추가 또는 기존 기능 확장 label Dec 25, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 25, 2025

Walkthrough

비공개방 입장용 비밀번호 검증과 세션 기반 인증 플래그(ROOM_AUTH_{roomId})를 추가하고, 클라이언트/JS·컨트롤러·DAO간 입장 흐름과 직접 URL 접근 제어를 구현했습니다. 리다이렉트 경로 일부가 /room/enter로 변경되었습니다.

Changes

Cohort / File(s) 변경 요약
방 입장 컨트롤러
src/main/java/room/controller/EnterRoomController.java
GET/POST 통합 handler 추가. RoomDAO 주입 및 비공개방 판별(isPrivateRoom), roomPwd 검사(matchRoomPassword), 호스트 예외 처리, 성공 시 ROOM_AUTH_{roomId} 세션 설정. 에러 코드에 need_password, wrong_password 추가.
방 생성 및 세션 설정
src/main/java/lobby/controller/CreateRoomController.java
룸 생성 후 브로드캐스트 이후 세션에 ROOM_AUTH_{roomId} 설정 추가 및 리다이렉트 대상 변경(/room/enter?roomId=...).
방 조회/퇴장 처리
src/main/java/room/controller/ViewRoomController.java, src/main/java/room/controller/ExitRoomController.java
View: 컨텍스트 경로 사용으로 리다이렉트 경로 변경, 비공개방 접근 시 세션 ROOM_AUTH_{roomId} 확인 후 미인증이면 /room/enter로 리다이렉트. Exit: 퇴장 시 해당 ROOM_AUTH_{roomId} 세션 속성 제거.
DAO 인터페이스/구현
src/main/java/room/dao/RoomDAO.java, src/main/java/room/dao/RoomDAOImpl.java
인터페이스에 matchRoomPassword(roomId, inputPwd)isPrivateRoom(roomId) 추가. 구현체에 SQL 기반 비밀번호 매칭 및 비공개 여부 판별 메서드 추가(try-with-resources 사용).
뷰/프론트엔드 입장 로직
src/main/webapp/WEB-INF/views/room/create.jsp, src/main/webapp/static/lobby/lobby.js
create.jsp 라디오 값 재정의(0=공개/1=비공개). lobby.js에서 공개/비공개 판정 역전, 각 enter-form에 hidden isPublic 필드 추가, 비공개인 경우 비밀번호 프롬프트 및 hidden roomPwd 주입 후 제출 로직 추가.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant LobbyJS as Lobby (lobby.js)
    participant EnterCtrl as EnterRoomController
    participant RoomDAO
    participant DB
    participant Session
    participant ViewCtrl as ViewRoomController

    rect rgb(200,220,255)
    note right of Client: 클라이언트 입장 시 (엔터 버튼)
    Client->>LobbyJS: submit enter-room-form (roomId, isPublic)
    alt isPublic == private
        LobbyJS->>Client: prompt for password
        Client->>LobbyJS: provide roomPwd
        LobbyJS->>EnterCtrl: POST /room/enter (roomId, roomPwd)
    else public
        LobbyJS->>EnterCtrl: POST /room/enter (roomId)
    end
    end

    rect rgb(220,240,220)
    note right of EnterCtrl: 서버: 비공개 여부/비밀번호 검사
    EnterCtrl->>RoomDAO: isPrivateRoom(roomId)
    RoomDAO->>DB: SELECT ... room_pwd IS NOT NULL
    DB-->>RoomDAO: result
    RoomDAO-->>EnterCtrl: isPrivate
    alt isPrivate
        EnterCtrl->>RoomDAO: matchRoomPassword(roomId, roomPwd)
        RoomDAO->>DB: SELECT ... room_pwd = ?
        DB-->>RoomDAO: match?
        RoomDAO-->>EnterCtrl: matched
        alt matched
            EnterCtrl->>Session: set ROOM_AUTH_{roomId} = true
            EnterCtrl-->>Client: redirect /room?roomId=...
        else not matched
            EnterCtrl-->>Client: redirect /room/enter?error=wrong_password
        end
    else not private
        EnterCtrl->>Session: set ROOM_AUTH_{roomId} = true
        EnterCtrl-->>Client: redirect /room?roomId=...
    end
    end

    rect rgb(255,240,200)
    note right of Client: 직접 URL 접근 시
    Client->>ViewCtrl: GET /room?roomId=...
    ViewCtrl->>RoomDAO: isPrivateRoom(roomId)
    RoomDAO->>DB: SELECT ...
    DB-->>RoomDAO: result
    RoomDAO-->>ViewCtrl: isPrivate
    alt isPrivate and not Session[ROOM_AUTH_{roomId}]
        ViewCtrl-->>Client: redirect /room/enter?roomId=...
    else allowed
        ViewCtrl-->>Client: forward room view
    end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • ochanhyeok
  • hjh79gw

개요 섹션의 내용은 변경사항에 맞게 위와 같이 업데이트되었습니다.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 비공개방 비밀번호 입력 기반 입장 처리 및 직접 URL 접근 제어라는 핵심 변경사항을 정확하게 요약하고 있습니다.
Linked Issues check ✅ Passed 모든 코딩 관련 요구사항이 충족되었습니다: 서버 기반 공개/비공개 판별, 비밀번호 검증 로직, 세션 기반 인증 정보 저장, 직접 URL 접근 제어 등 모든 기능이 구현되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 비공개방 비밀번호 검증 및 접근 제어라는 PR 목표와 밀접하게 연관되어 있으며, 범위를 벗어난 변경사항은 없습니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch FEAT-방-비밀번호

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/room/controller/ExitRoomController.java (1)

25-35: roomId null 처리 검증 필요

roomId가 null인 경우 session.removeAttribute("ROOM_AUTH_" + null)이 실행되어 의도하지 않은 세션 키를 제거할 수 있습니다. exitAndHandleHost가 실패하면 예외로 처리되지만, 방어적으로 roomId를 먼저 검증하는 것이 좋습니다.

🔎 제안하는 수정
 String roomId = request.getParameter("roomId");
 HttpSession session = request.getSession(false);
 String userId = (session == null) ? null : (String)session.getAttribute("loginUserId");
+
+if (roomId == null || roomId.isBlank()) {
+    response.sendRedirect(ctx + "/lobby?error=invalid_room");
+    return;
+}
+
 if (userId == null || userId.isBlank()) {
🧹 Nitpick comments (1)
src/main/java/lobby/controller/CreateRoomController.java (1)

61-69: 방어적 프로그래밍: roomId null 체크 권장

roomResult.getId()가 null을 반환할 가능성은 낮지만, 세션 속성 키 생성 전에 null 체크를 추가하면 더 안전합니다.

🔎 제안하는 방어 코드
 String roomId = roomResult.getId();
+
+if (roomId == null || roomId.isBlank()) {
+    throw new ServletException("방 ID 생성 실패");
+}

 session.setAttribute("hostUserId", hostUserId);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 370db3d and 08d48b0.

📒 Files selected for processing (8)
  • src/main/java/lobby/controller/CreateRoomController.java
  • src/main/java/room/controller/EnterRoomController.java
  • src/main/java/room/controller/ExitRoomController.java
  • src/main/java/room/controller/ViewRoomController.java
  • src/main/java/room/dao/RoomDAO.java
  • src/main/java/room/dao/RoomDAOImpl.java
  • src/main/webapp/WEB-INF/views/room/create.jsp
  • src/main/webapp/static/lobby/lobby.js
🧰 Additional context used
🧬 Code graph analysis (5)
src/main/java/room/controller/ExitRoomController.java (3)
src/main/java/room/ws/RoomWebSocketService.java (2)
  • cleanup (105-113)
  • onExit (80-102)
src/main/java/room/service/RoomService.java (2)
  • RoomService (9-226)
  • exitAndHandleHost (21-225)
src/main/java/room/ws/RoomSessionRegistry.java (1)
  • leave (26-36)
src/main/java/room/dao/RoomDAO.java (3)
src/main/java/room/dao/RoomPlayerDAO.java (2)
  • RoomPlayerDAO (7-24)
  • enterIfAbsent (11-11)
src/main/java/game/single/dao/SinglePlayerDAO.java (1)
  • SinglePlayerDAO (3-13)
src/main/java/game/multi/dao/MultiPlayerDAO.java (1)
  • MultiPlayerDAO (3-13)
src/main/java/lobby/controller/CreateRoomController.java (2)
src/main/webapp/static/room/room.js (6)
  • roomId (3-3)
  • send (244-250)
  • setStatus (138-141)
  • pageEl (1-344)
  • setStatus (237-237)
  • location (240-242)
src/main/java/room/ws/RoomWebSocketService.java (2)
  • onEnter (50-66)
  • broadcastHostChanged (130-139)
src/main/java/room/controller/EnterRoomController.java (1)
src/main/java/room/dao/RoomDAOImpl.java (1)
  • RoomDAOImpl (15-252)
src/main/java/room/controller/ViewRoomController.java (3)
src/main/webapp/static/room/room.js (1)
  • roomId (3-3)
src/main/java/room/controller/CreateRoomController.java (1)
  • WebServlet (15-61)
src/main/java/lobby/controller/ViewRoomListController.java (1)
  • Override (22-45)
🔇 Additional comments (11)
src/main/java/lobby/controller/CreateRoomController.java (1)

68-73: 방 생성자에게 자동 인증 부여 로직 확인 완료

방 생성 후 세션에 ROOM_AUTH_<roomId> 플래그를 설정하여 방장이 비밀번호 입력 없이 입장할 수 있도록 처리한 로직이 정확합니다. /room/enter로의 리다이렉트도 새로운 입장 플로우와 일치합니다.

src/main/java/room/controller/ExitRoomController.java (1)

35-35: 세션 정리 로직 확인 완료

방 퇴장 후 ROOM_AUTH_<roomId> 세션 속성을 제거하여 인증 정보를 정리하는 로직이 올바르게 구현되었습니다.

src/main/java/room/controller/ViewRoomController.java (1)

36-43: 비공개방 접근 제어 로직 검증 필요

현재 구현은 ROOM_AUTH_<roomId> 세션 플래그를 확인하여 비공개방 접근을 제어합니다. 그러나 EnterRoomController와 달리 방장(host) 예외 처리가 없습니다.

시나리오: 방장의 세션이 만료되거나 방장이 URL을 직접 입력하면, 자신이 만든 방임에도 불구하고 /room/enter로 리다이렉트됩니다.

의도된 동작인지 확인이 필요합니다:

  1. 의도된 경우: 모든 사용자(방장 포함)가 /room/enter를 거쳐야 함 → 현재 코드 유지
  2. 의도되지 않은 경우: 방장은 세션 플래그 없이도 접근 가능해야 함 → EnterRoomController (line 66)와 같은 방장 확인 로직 추가 필요
🔎 방장 예외 처리를 추가하는 경우의 수정안
+String userId = (String)session.getAttribute("loginUserId");
+String hostUserId = roomDAO.findHostUserIdByRoomId(roomId);
+boolean isHost = userId != null && userId.equals(hostUserId);
+
 boolean isPrivate = roomDAO.isPrivateRoom(roomId);
 Boolean isRoomAuthed = (Boolean)session.getAttribute("ROOM_AUTH_" + roomId);

-if (isPrivate && (isRoomAuthed == null || !isRoomAuthed)) {
+if (isPrivate && !isHost && (isRoomAuthed == null || !isRoomAuthed)) {
     response.sendRedirect("/room/enter?roomId=" + URLEncoder.encode(roomId, StandardCharsets.UTF_8)
         + "&playType=" + URLEncoder.encode(playType, StandardCharsets.UTF_8));
     return;
 }
src/main/webapp/WEB-INF/views/room/create.jsp (1)

190-194: 공개/비공개 값 변경 확인 완료

isPublic 값을 "0"(공개), "1"(비공개)로 변경한 것이 서버 측 로직(RoomDAOImpl line 111-115)과 일치합니다. UI 동작은 그대로 유지되며 의미적 일관성이 확보되었습니다.

src/main/java/room/dao/RoomDAO.java (1)

32-52: 새로운 DAO 메서드 추가 확인 완료

비공개방 비밀번호 검증(matchRoomPassword)과 비공개방 여부 확인(isPrivateRoom) 메서드가 적절히 추가되었습니다. Javadoc 문서화도 명확합니다.

src/main/webapp/static/lobby/lobby.js (2)

82-86: 공개/비공개 판별 로직 변경 확인 완료

isPublic 값 해석을 "0"=공개, 그 외=비공개로 변경하여 서버 측 로직과 일치시켰습니다. 숨겨진 입력 필드를 통해 폼 제출 시 공개/비공개 정보가 올바르게 전달됩니다.

Also applies to: 102-102


110-142: 비공개방 비밀번호 입력 플로우 구현 확인 완료

비공개방 입장 시 prompt를 통해 비밀번호를 입력받고, 유효성을 검증한 후 폼에 숨겨진 필드로 추가하여 제출하는 로직이 올바르게 구현되었습니다.

src/main/java/room/dao/RoomDAOImpl.java (2)

195-215: 비밀번호 검증 메서드 구현 확인 완료

matchRoomPassword 메서드가 SQL COUNT(*)를 사용하여 비공개방 여부(is_public='1')와 비밀번호 일치(room_pwd=?)를 동시에 확인합니다. 로직이 정확하며 리소스 관리도 try-with-resources로 안전하게 처리됩니다.


217-239: 비공개방 확인 메서드 구현 확인 완료

isPrivateRoom 메서드가 room_pwd IS NOT NULL을 통해 비공개방 여부를 확인합니다. COUNT(*)는 항상 결과를 반환하므로 line 236의 return false는 방어 코드입니다. 현재 사용 사례에 적합한 구현입니다.

src/main/java/room/controller/EnterRoomController.java (2)

27-37: GET/POST 요청 통합 처리 확인 완료

doGetdoPost를 공통 handler 메서드로 위임하여 코드 중복을 제거하고 일관된 처리를 보장합니다.


66-77: 비공개방 비밀번호 검증 및 방장 우회 로직 확인

비공개방 입장 시 방장이 아닌 사용자에게만 비밀번호 검증을 요구하고, 검증 성공 시 세션에 ROOM_AUTH_<roomId> 플래그를 저장하는 로직이 올바르게 구현되었습니다. (단, line 59의 NPE 이슈 수정이 선행되어야 합니다)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08d48b0 and 2a3a19c.

📒 Files selected for processing (4)
  • src/main/java/room/controller/EnterRoomController.java
  • src/main/java/room/controller/ViewRoomController.java
  • src/main/java/room/dao/RoomDAO.java
  • src/main/webapp/static/lobby/lobby.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/webapp/static/lobby/lobby.js
🧰 Additional context used
🧬 Code graph analysis (3)
src/main/java/room/controller/ViewRoomController.java (1)
src/main/webapp/static/room/room.js (1)
  • roomId (3-3)
src/main/java/room/dao/RoomDAO.java (1)
src/main/webapp/static/room/room.js (1)
  • roomId (3-3)
src/main/java/room/controller/EnterRoomController.java (1)
src/main/java/room/dao/RoomDAOImpl.java (1)
  • RoomDAOImpl (15-252)
🔇 Additional comments (12)
src/main/java/room/dao/RoomDAO.java (2)

32-45: 메서드 시그니처와 문서화가 명확합니다.

비공개방 비밀번호 검증 로직의 계약이 Javadoc에 잘 정의되어 있습니다. 공개방/비공개방 처리 규칙과 반환값이 명확하게 문서화되었습니다.


47-52: 메서드 문서화가 적절합니다.

비공개방 여부 조회 메서드의 목적과 파라미터가 명확하게 정의되어 있습니다.

src/main/java/room/controller/ViewRoomController.java (4)

4-5: 컨텍스트 경로 처리가 올바르게 적용되었습니다.

URLEncoderStandardCharsets import와 request.getContextPath() 사용으로 이전 리뷰에서 지적된 하드코딩된 경로 문제가 해결되었습니다.

Also applies to: 26-26


33-36: 파라미터 검증 및 리다이렉트가 적절합니다.

필수 파라미터와 세션에 대한 조기 검증과 명시적인 return 처리가 올바르게 구현되었습니다.


38-45: 비공개방 접근 제어 로직이 올바르게 구현되었습니다.

세션 기반 인증 플래그(ROOM_AUTH_<roomId>)를 확인하여 비인증 사용자를 /room/enter로 리다이렉트하는 로직이 정확합니다. URL 파라미터 인코딩과 null 처리가 적절합니다.

다만, EnterRoomController에서 방장(host)이 비공개방 입장 시 ROOM_AUTH 플래그를 설정하는지 확인이 필요합니다. 방장이 비밀번호 없이 입장 가능하다는 요구사항이 있으므로, 방장도 이 플래그를 받아야 이후 /room 접근이 정상 동작합니다.


54-54: 방장 조회 실패 시 에러 처리가 적절합니다.

컨텍스트 경로를 포함한 리다이렉트와 명확한 에러 파라미터가 올바르게 구현되었습니다.

src/main/java/room/controller/EnterRoomController.java (6)

15-16: 핸들러 통합과 RoomDAO 추가가 적절합니다.

GET과 POST 요청을 단일 handler 메서드로 통합하여 코드 중복을 제거했으며, RoomDAO 추가로 비공개방 검증 기능을 지원합니다.

Also applies to: 28-37, 39-40


45-52: 파라미터 검증 순서가 개선되었습니다.

이전 리뷰에서 지적된 문제(DB 호출 전 파라미터 검증 누락)가 해결되었습니다. 이제 null/blank 체크(49-52행)가 DB 호출(54-55행)보다 먼저 수행되어 잘못된 입력으로 인한 DB 에러를 방지합니다.


54-55: DB 조회 배치가 적절합니다.

파라미터 검증 후 DB를 조회하는 순서가 올바르게 구현되었습니다.


57-63: userId null 체크가 수정되었습니다.

이전 리뷰에서 지적된 NPE 위험(null 체크 전 userId.equals() 호출)이 해결되었습니다. 이제 userId null/blank 검증(60-63행)이 equals 호출(65행)보다 먼저 수행됩니다.


68-76: 비밀번호 검증 로직이 정확하게 구현되었습니다.

비공개방에 대한 비밀번호 입력 확인(68-71행)과 검증(73-76행)이 올바르게 분리되어 있으며, 각 실패 케이스에 적절한 에러 메시지(need_password, wrong_password)를 제공합니다.


80-86: 방 입장 및 리다이렉트 처리가 적절합니다.

enterIfAbsent 호출, 로비 브로드캐스트, 그리고 URL 인코딩된 파라미터를 사용한 /room으로의 리다이렉트가 올바르게 구현되었습니다.

Copy link
Collaborator

@ochanhyeok ochanhyeok left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다!!

Copy link
Collaborator

@minseokim0113 minseokim0113 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니당

@minseokim0113 minseokim0113 merged commit 7aa75bd into dev Dec 26, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FEAT 새로운 기능 추가 또는 기존 기능 확장

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 비공개방 비밀번호 입력 기반 입장 처리 및 직접 URL 접근 제어

3 participants