개발 slecs

어드민 특정 경로에 설정 허브 권한 처리 추가

목차

어드민 권한 체계를 손볼 때마다 느끼는 건데, 이게 딱 보면 간단해 보이는데 실제로는 건드릴 곳이 생각보다 많다. 이번에도 마찬가지였음. SETTINGS_HUB 권한을 특정 어드민 경로에 추가하는 작업이었는데, 변경 파일은 백엔드 로직 3개뿐이었지만 영향 범위를 파악하는 데 시간을 꽤 썼다.

왜 이런 작업이 필요했나

어드민 시스템에서 경로별 권한 처리는 초기에 대충 짜면 나중에 반드시 문제가 생긴다. 특히 SETTINGS_HUB 같이 설정 전반을 다루는 허브성 권한은, 어떤 경로에 어떤 권한 체크가 붙어 있는지 일관성이 없으면 두 가지 문제가 동시에 생김.

하나는 보안 구멍이다. 특정 경로에 권한 체크가 빠져 있으면 의도치 않게 접근이 열려 있는 케이스가 생긴다. 이게 실제로 악용되기보다는 "왜 이게 돼요?" 하는 문의가 먼저 오는 경우가 많지만, 본질적으로는 같은 문제다.

다른 하나는 유지보수 비용이다. 권한 체크 로직이 여기저기 흩어져 있으면, 나중에 SETTINGS_HUB 권한의 정의가 바뀌거나 새로운 하위 권한이 생겼을 때 빠진 곳을 찾아야 한다. 이게 은근히 시간을 잡아먹음.

이번 작업의 핵심은 그 일관성을 맞추는 것이었다. 기존에 권한 처리가 있던 경로들과 동일한 패턴으로 SETTINGS_HUB 체크를 추가하고, 중복으로 흩어진 코드는 공통화했음.

변경 범위와 작업 내용

레이어 파일 수 주요 변경
백엔드 로직 3개 권한 처리 추가 및 공통화
화면 (JSP) 0개 변경 없음
쿼리 (XML) 0개 변경 없음
스타일 0개 변경 없음

백엔드 3개 파일만 건드렸는데, 작업 포인트는 크게 네 가지였음.

  • 중복 권한 체크 로직 제거하고 공통 메서드로 위임
  • 권한 없을 때의 엣지 케이스 처리 보강 (null, 빈 권한 목록 등)
  • 로그 메시지 개선 - 어떤 권한으로 어떤 경로에 접근했는지 트레이스 가능하게
  • 불필요한 주석과 죽은 코드 정리

권한 체크 패턴을 정리하면 대략 이런 형태다.

// Before: 각 핸들러마다 직접 체크
if (user.hasRole("ADMIN") || user.hasRole("SUPER_ADMIN")) {
    // 처리
}

// After: 공통 메서드로 위임, SETTINGS_HUB 명시적 포함
if (!permissionService.hasSettingsHubAccess(user, requestPath)) {
    log.warn("Unauthorized access attempt: user={}, path={}", user.getId(), requestPath);
    throw new UnauthorizedException("SETTINGS_HUB permission required");
}

이렇게 하면 SETTINGS_HUB 접근 조건이 바뀌었을 때 permissionService 한 곳만 수정하면 된다. 핸들러를 순회하면서 수정할 필요가 없음.

에러 처리도 신경 썼다. 권한 없을 때 그냥 예외 던지는 게 아니라 로그에 어떤 사용자가 어떤 경로를 요청했는지 남기게 했음. 새벽에 뭔가 이상한 접근이 있을 때 이런 로그가 없으면 원인 파악이 한참 걸린다.

운영 중 코드 변경할 때 체크하는 것들

운영 서비스 변경에서 가장 나쁜 건 "돌아가니까 됐다"고 넘어가는 거다. 권한 로직은 특히 그렇다. 정상 케이스만 테스트하면 엣지 케이스에서 터짐.

이번에 직접 확인한 케이스들:

  • 권한이 없는 사용자가 해당 경로에 접근했을 때 403이 제대로 떨어지는지
  • 권한이 있는 사용자는 기존과 동일하게 접근되는지
  • 권한 목록이 비어 있는 엣지 케이스에서 NPE가 안 나는지
  • 로그가 의도한 형식으로 찍히는지

변경 전후 동작을 직접 손으로 두드려보는 게 귀찮아도 결국 가장 빠른 방법이다. 배포 후 모니터링도 당일은 좀 더 자주 로그 확인함.

코드 작성 원칙도 이번에 재확인했음.

원칙 이유
단일 책임 권한 체크 로직이 핸들러에 섞이면 양쪽 다 테스트하기 어려워짐
명시적 코드 hasSettingsHubAccesscheckPermission("SH")보다 훨씬 나음
실패 우선 처리 권한 없는 케이스를 먼저 처리하고 나머지 로직 진행
작은 커밋 공통화 작업과 권한 추가를 분리해서 롤백 단위를 작게

회고

당장 사용자 눈에 보이는 변화가 없는 작업이다. 화면도 안 바뀌고, 쿼리도 안 바뀌고, 정상 플로우에서 달라지는 게 없음. 그래서 이런 작업의 가치를 설명하는 게 가끔 어렵긴 함.

근데 이런 게 쌓여야 시스템이 버틴다. 권한 로직이 여기저기 흩어진 채로 기능이 계속 붙으면, 어느 순간 "이 경로는 왜 권한 체크가 없지?" 같은 걸 발견했을 때 수습 범위가 커진다.

코드 쓸 때 항상 생각하는 기준이 있음.

  • 6개월 후에 내가 이 코드를 다시 봤을 때 의도를 바로 파악할 수 있는가
  • 다른 개발자가 이 권한 체크 패턴을 보고 동일하게 따라 쓸 수 있는가
  • 새벽에 뭔가 이상한 접근이 생겼을 때 이 로그로 빠르게 원인을 찾을 수 있는가

이번 작업은 세 가지 다 OK다. 그걸로 충분함.

댓글 0

첫 댓글 달아줘.