Hybrid RBAC (Role + Permission)

Hybrid RBAC (Role + Permission) 접근 제어

https://github.com/implement-study-25/ticket-reserve-service/pull/14

티켓 예매 서비스에서의 Role & Privilege 기반 접근 제어(R&PBAC) 설계와 구현

요약

  • 핵심: JWT로 사용자 식별 → 별도 필터가 DB에서 roles + privileges 로딩 → @PreAuthorize("hasAuthority(..)")로 인가.

  • 장점: 역할 폭발 방지, 무배포 정책 변경, 셀프서비스 운영, 감사 용이, 기간제 권한, 캐시 확장.

  • 구현: SecurityConfig@EnableMethodSecurity, GrantedAuthorityDefaults(""), 필터 체인. JwtAuthenticationFilter는 식별만, RbacAuthoritiesFilter는 권한 주입.

왜 R&PBAC인가? (RBAC과의 차이 및 장점)

  • RBAC(Role-Based Access Control): 사용자는 하나 이상의 역할(Role)을 갖고, 리소스 접근은 역할 단위로 제어한다. 단순하고 관리가 쉽지만, 역할이 세분화될수록 역할 폭발(Role Explosion) 문제가 발생한다.

  • R&PBAC(Role & Privilege-Based Access Control): 역할과 함께 보다 세밀한 권한(Privilege) 을 별도로 정의하고, 역할과 권한을 매핑한다. 결과적으로 사용자의 권한은 역할 + 권한의 합으로 구성된다.

    • 장점

      • 세분화된 권한 설계: ADMIN, USER 같은 거친 역할과 EVENT_CREATE, EVENT_UPDATE 같은 미세 권한을 분리해 관리.

      • 역할 폭발 방지: 역할 수는 적정 수준으로 유지하고, 신규 기능은 권한만 추가해 역할-권한 매핑으로 유연하게 확장.

      • 정책 변경 용이성: 비즈니스 변화(새 기능, 한시적 오퍼레이션)에 맞춰 권한만 수정/추가 가능.

    • RBAC 대비 차이점

      • RBAC은 역할만으로 접근 제어. R&PBAC은 역할과 권한을 동시에 사용하며, 최종 인가 판단 시 두 집합을 모두 GrantedAuthority로 주입해 hasAuthority로 일관되게 검증.

RBAC을 도입하지 않았을 때의 문제와, R&PBAC 도입 후 해결

  • 미도입 시 발생 문제

    • 코드 곳곳에서 임시 플래그, 하드코딩된 이메일/사용자 체크 등으로 접근 제어 로직이 분산·중복.

    • 권한 변경 요구 시 코드 수정 범위가 광범위하고 테스트 비용 증가.

    • 기능 단위 권한 위임(예: 관리자 중 특정 작업만 가능한 운영자) 구현 난이도 급상승.

  • R&PBAC 도입 후 개선

    • 인증과 인가를 분리: JWT 기반 인증 필터는 사용자 식별까지만, 이후 R&PBAC 필터가 역할·권한을 로딩해 SecurityContext에 주입.

    • 컨트롤러/서비스 단에는 @PreAuthorize("hasAuthority('...')")만 배치 → 단일 진입점으로 가독성과 변경 용이성 향상.

    • 역할·권한 모델이 DB로 관리되어 운영 환경에서 정책 변경이 코드 배포 없이 가능(매핑 변경만으로 반영).


구현 구조 개요

  • 위치: com.study.ticketservice.common.security, com.study.ticketservice.domain.auth, com.study.ticketservice.utils

  • 핵심 흐름

    1. JwtAuthenticationFilter가 쿠키의 Access Token을 검증하고 principaluserId만 설정

    2. RbacAuthoritiesFilter가 DB에서 roles + privileges를 로딩해 GrantedAuthority로 주입

    3. @PreAuthorize("hasAuthority('...')")로 엔드포인트/메서드 보호

    4. GrantedAuthorityDefaults("")로 ROLE_ 프리픽스 제거 → ADMIN, USER, EVENT_* 그대로 사용


도메인 모델링 (엔티티 & 매핑)

  • 사용자-역할 다대다: usersrolesuser_roles로 매핑

  • 역할-권한 다대다: rolesprivilegesrole_privileges로 매핑

  • 엔티티

    • User, Role, Privilege, UserRoleMap, RolePrivilegeMap

  • 조회 쿼리


컨트롤러 인가 적용 예시

  • 관리자 전용 이벤트 관리

  • 사용자 좌석 예약

  • 통합 데모(RBAC vs Privilege 비교)


인증(JWT)과 쿠키 전략

  • JwtUtil

    • Access/Refresh 분리, 각기 다른 시크릿/만료

    • accessToken, refreshTokenHttpOnly, Secure 쿠키로 설정 (프론트는 credentials: 'include' 필요)

    • 토큰 페이로드: userId, roles, type

  • 리프레시 플로우


예외 처리(인가/인증/공통)

  • 인가 실패: 403 Access Denied 통일

  • 인증 실패: 401 Unauthorized 통일

  • 도메인 예외: ApiException → 일관 응답 포맷


주요 포인트:

  • 권한 주입 이원화: 인증 필터에서 사용자 식별만, 별도 필터에서 roles + privileges를 로딩 후 주입 → 성능/책임 분리 명확.

  • ROLE_ 프리픽스 제거: GrantedAuthorityDefaults("")ADMIN, USER, EVENT_* 그대로 사용 → 팀/프론트와의 커뮤니케이션 비용 절감.

  • DB 기반 동적 인가: UserRoleMapRepository, RolePrivilegeMapRepository 쿼리로 인가 정책을 DB만 바꿔도 즉시 반영 가능.

  • 쿠키 기반 JWT: HttpOnly + Secure 쿠키로 XSS 취약점 완화, SameSite=None(운영 환경) 적용 전제.

  • 테스트 픽스처 제공: rbac-test-data.sql로 역할/권한/매핑을 한눈에 확인 가능 → 데모/테스트 재현 용이.


운영 효과: 개발자 개입 최소화(셀프서비스 권한 관리)

  • 무배포 정책 변경: 인가 정책을 코드가 아닌 데이터(user_roles, role_privileges)로 관리하므로, 운영/보안 담당자가 UI나 승인된 배치로 매핑만 변경하면 즉시 반영된다. 개발자가 데이터를 직접 조작하거나 코드를 고쳐 배포할 필요가 없다.

  • 셀프서비스 권한 관리: 어드민 콘솔에서 사용자-역할, 역할-권한 매핑을 관리하도록 만들기 쉽다. 온보딩/조직 변경 때 운영자가 스스로 권한을 부여/회수 가능.

  • 정책 거버넌스와 감사(Audit): 매핑 변경 이력을 별도 테이블로 남기고(예: auth_policy_change_log), 승인 워크플로를 붙이면 누가 언제 어떤 권한을 변경했는지 추적 가능.

  • 임시/시간제한 권한 부여: 매핑 테이블에 granted_until 같은 유효기간 컬럼을 확장하고, RbacAuthoritiesFilter 조회 시 현재 시각 기준으로 필터링하면 기간 한정 권한을 안전하게 운용 가능.

  • 롤백과 실험(A/B): 새로운 기능 권한을 역할에 점진적으로 붙였다 떼는 방식으로 실험과 롤백이 쉽다. 실패 시 매핑만 되돌리면 된다.

  • 멀티테넌시/팀별 정책 응용: 권한 네임스페이스(예: ORG_A:EVENT_CREATE)를 도입하면 테넌트/조직별로 다른 정책을 같은 코드로 운용 가능.

한 줄 요약: R&PBAC은 접근 정책을 “코드”가 아니라 “데이터”로 다루게 하므로, 운영이 개발자에게 의존하지 않고 자율·민첩하게 권한을 관리할 수 있게 만든다.


마무리

  • 본 프로젝트는 역할과 권한을 분리해 유연성과 유지보수성을 확보했고, 스프링 시큐리티 필터 체인을 활용해 인증과 인가의 책임을 명확히 분리했습니다.

  • 컨트롤러 단의 인가는 @PreAuthorize("hasAuthority('...')")로 일관되게 표현되어 가독성이 높고, 운영 중 정책 변경에도 신속히 대응 가능합니다.

Last updated