문제 상황
처음에 User URI 설계를 다음과 같이 진행했다.
PATCH /users/{userId}
POST /users/{userId}/delete
이때 서비스 단에서는
User user = globalValidator.findOrException(userRepository, userId);
globalValidator.matchPassword(user, request.getPassword());
globalValidator.forbiddenErrorHandler(user, sessionUserId);
- forbiddenErrorHandeler 메소드로 URL로 전달된 userId, 세션에 저장된 로그인 유저의 userId가 일치하는지 매번 검증
하지만 여기서 문제가 발생했는데
문제 분석
1.URL 조작 위험
- 클라이언트가 /users/2 → /users/3 으로 바꾸면 다른 사람의 리소스에 접근 시도가 가능해짐.
- 물론 서버에서 세션 검증(forbiddenErrorHandler)으로 막고 있었지만, 테스트시 직접 바꾸면 여전히 접근 가능
2. UI적으로 생각하면 모순됨
- 현재는 특정 ID의 리소스에 접근한다는 의미인데 이상하게 느껴짐
- 이미 쿠키에 세션아이디가 존재
- 로그인 세션이 존재한다면 현재 로그인한 유저가 유일한 리소스 대상
- 인증된 사용자에게 userId는 불필요한 데이터
3. 중복 검증 로직의 복잡성
- 서비스단마다 forbiddenErrorHandler(user, sessionUserId) 검증이 반복
- 결국 모든 메서드에 같은 검증이 들어가서 코드 중복 + 가독성 저하 발생
해결 - /me URI 수정
URI를 다음과 같이 수정했다
PATCH /users/me
DELETE /users/me
GET /users/me
개선된 점
- URL 조작 가능했는데 세션 기반으로 조작할수 없게 되었다
- 특정 ID 리소스에 접근한다 에서 로그인 유저 자신의 리소스 접근으로 의미가 명확해졌다
- 매번 ID 비교 검증이 필요했는데 세션에서 바로 가져옴
배운점
처음에는 단순히 REST 규칙대로 , 아니 그전 일정 CRUD처럼 리소스의 id를 명시해야한다고 생각했다. 하지만 다른 도메인과 다르게 인증된 사용자 시스템에서는 URL에 userId가 들어가는게 말이 안된다고 생각했다. 어떤 웹서비스 마이페이지를 생각해도 userId는 없다. 그래서 /user/me로 표현하는게 더 명확했다.
이번 트러블슈팅으로 인증 기반 시스템에서는 세션이 이미 사용자 식별자를 포함하므로, /users/me처럼 명시적인 ID를 제거하는 편이 보안과 표현도 더 낫다는 것을 깨달았다
'BootCamp' 카테고리의 다른 글
| [Error] 일정 관리 트러블 슈팅 2- 양방향vs단방향 (0) | 2025.11.14 |
|---|---|
| [Error] 일정 트러블 슈팅 (1) | 2025.11.05 |
| [내배캠] 한달 회고 (0) | 2025.10.31 |
| [Error] 키오스크 트러블 슈팅 3 - 장바구니 구조 설계 (0) | 2025.10.28 |
| [Error] 키오스크 트러블 슈팅 2 -책임 분리 (0) | 2025.10.27 |