← 프로젝트 회고 · Backend
RETROSPECTIVE · 회고

하드코딩된 역할 체크를 '행위 단위 권한키'로 바꾸기

Backend

관리자 기능 곳곳에 if (isAdmin(user) || isCsManager(user)) 같은 조건이 서비스, 컨트롤러, JSP에 흩어져 있었다. 특정 담당자에게 기능 하나만 열어주려 해도 코드를 고치고 배포해야 했고, 어떤 사람이 무엇을 할 수 있는지 한눈에 볼 방법도 없었다.

역할이 아니라 행위에 이름을 붙인다

"누가(Role)"를 코드에 박는 대신 "무엇을(Action)"에 키를 붙이고, 누가 그 키를 갖는지는 데이터로 관리하도록 바꿨다.

  1. coupon.master.write: 쿠폰 등록
  2. delivery.comment.edit: 배송 비고 수정
  3. member.account.edit: 회원 계좌 정보 수정

코드는 "이 행위를 할 수 있는가"만 묻는다.

if (!authService.hasPermission(memberId, "coupon.master.write")) {
throw new AccessDeniedException("coupon.master.write");
}
<auth:has key="delivery.comment.edit">
<button id="btnEditComment">비고 수정</button>
</auth:has>

데이터 구조

  1. 권한키 테이블: 키, 설명, 사용 여부
  2. 매핑 테이블: 권한키 × 대상(역할 / 팀 / 그룹 / 특정 회원)

hasPermission은 회원의 역할, 소속 팀, 그룹을 모은 뒤 매핑 중 하나라도 있으면 허용한다. 개인 단위 예외도 같은 구조로 처리된다.

마이그레이션 전략

  1. 최고 관리자 체크는 OR 조건으로 남겨둔다. 새 구조에 매핑이 빠져도 최소한 기존 관리자는 막히지 않는다.
  2. 기존 하드코딩 허용 목록을 그대로 매핑 데이터로 옮겨서 전환 전후 동작이 같게 만든다.
  3. 화면(버튼 숨김)과 서버(API 검증) 양쪽에 적용한다. 화면만 가리면 요청을 직접 보내서 우회할 수 있다.

조회 비용

요청마다 매핑을 조회하면 부담이 되므로, 로그인 시점에 권한키 Set을 만들어 세션에 두거나 짧은 TTL로 캐시한다. 권한 변경이 즉시 반영돼야 하는 경우와 트레이드오프라 캐시 무효화 시점을 같이 정해야 한다.

Gunmo Lee
하드코딩된 역할 체크를 '행위 단위 권한키'로 바꾸기 | Gunmo's Dev Life