본문으로 건너뛰기

RBAC

Lumie의 authorization 모델은 계층적으로 구성됩니다.

  1. 거친 수준의 identity와 role은 auth 모듈과 JWT claim에서 옵니다
  2. 테넌트 범위 staff permission은 staff 모듈에 존재합니다
  3. 모듈 service는 ownership, 수명주기, quota 규칙 같은 business-state check를 추가합니다

이 페이지는 현재 모델을 다루는 레퍼런스 문서입니다.

소스 경로

경로역할
libs/common/src/main/java/com/lumie/common/auth/Role.java전역 역할 hierarchy와 legacy alias parsing
libs/common/src/main/java/com/lumie/common/auth/AuthorizationGuard.java공용 OWNER-only guard
modules/staff/src/main/java/com/lumie/staff/domain/entity/Permission.java테넌트 범위 권한 카탈로그
modules/staff/src/main/java/com/lumie/staff/domain/entity/StaffPermission.javastaff-to-permission assignment 행
modules/staff/src/main/java/com/lumie/staff/domain/vo/AccessLevel.javapermission access level enum
modules/staff/src/main/java/com/lumie/staff/application/service/StaffCommandService.javastaff 수명주기 작업에서 역할 hierarchy 강제
modules/staff/src/main/java/com/lumie/staff/adapter/in/web/PermissionController.javapermission 쿼리 인터페이스

적용 계층

전역 역할 계층

공용 Role enum은 네 가지 상위 역할을 정의합니다.

역할권한 수준일반적인 의미
OWNER가장 높음테넌트 OWNER
MANAGER높음관리 staff
INSTRUCTOR중간교사 또는 일반 staff 역할
STUDENT가장 낮음student-facing user

중요한 helper method 두 가지:

  • hasAuthority(required)는 같은 권한이거나 더 높은 권한을 뜻합니다
  • canManage(target)은 대상보다 명확히 높은 권한만 허용합니다

Role.fromString(...)은 또한 legacy alias를 보존합니다.

  • ADMIN -> INSTRUCTOR
  • DEVELOPER -> MANAGER

이 alias 동작은 과거 데이터나 오래된 client가 예전 역할 이름을 여전히 보낼 때 중요합니다.

테넌트 범위 Staff 권한 모델

staff 모듈은 staff 사용자에 대해 두 번째 authorization 계층을 추가합니다.

유형저장 역할
Permissioncode, name, category, description를 가진 catalog 행
StaffPermissionstaff_id + permission_code로 식별되는 join 행
AccessLevelNONE, READ, WRITE

중요한 경계 사실:

  • PermissionTenantScopedEntity를 상속하므로 권한 카탈로그도 테넌트 범위입니다.
  • StaffPermission은 base class를 상속하지 않지만, insert 시 tenant_id를 명시적으로 씁니다.
  • permission 쿼리 엔드포인트는 /v1/permissions 아래에 있습니다.
  • staff permission 할당 흐름은 staff service에 있으며, Spring Security가 이를 전역적으로 자동 적용하지는 않습니다.

현재 백엔드가 RBAC를 적용하는 방식

계층 1: 인증과 상위 역할 구분

  • JwtAuthenticationFilter는 사용자 role을 UserContextHolder에 기록합니다.
  • Spring Security는 /internal/**를 synthetic ROLE_INTERNAL에 매핑합니다.

계층 2: 명시적인 공통 가드

AuthorizationGuard.requireOwner()는 homepage 게시나 테넌트 관리, 내보내기 일부처럼 OWNER만 수행할 수 있는 작업에 사용됩니다.

계층 3: 모듈 서비스 규칙

가장 분명한 예시는 StaffCommandService입니다.

  • 생성은 MANAGER 또는 INSTRUCTOR만 허용
  • 요청자는 자신을 관리할 수 없음
  • 요청자는 canManage(...)를 통해 대상보다 명확히 높은 권한을 가져야 함
  • 역할 check를 통과해도 billing quota와 배정된 class가 작업을 막을 수 있음

중요한 아키텍처 포인트는 이것입니다. RBAC만으로 authorization 결정이 끝나지 않습니다. 비즈니스 불변식은 역할 평가 이후에도 계속 적용됩니다.

현재 이 모델이 하지 않는 것

  • 중앙 정책 엔진이나 annotation 기반의 통합 fine-grained permission framework가 없습니다.
  • staff permission은 web layer에서 모든 엔드포인트에 대해 자동으로 검사되지 않습니다.
  • student는 상위 역할 모델만 사용하며, staff 권한 카탈로그는 staff capability를 위한 것입니다.

결과적으로 authorization logic은 다음 위치에 분산되어 있습니다.

  • Spring Security
  • 공용 guard
  • 애플리케이션 서비스
  • 테넌트 범위 permission 조회

실패 모드와 경계 위험

  • Role.fromString(...)를 엄격한 파서로 취급하면, 코드에 아직 남아 있는 legacy alias 동작을 놓치게 됩니다.
  • 명시적인 service 수준 check 없이 새 admin workflow를 추가하면, 호출자가 인증되었다 하더라도 authorization hole이 생길 수 있습니다.
  • permission 데이터는 테넌트 범위이므로, cross-테넌트 관리 도구는 permission row를 읽거나 쓰기 전에 테넌트 컨텍스트를 올바르게 복원해야 합니다.

검증 명령어

cd /Users/bluemayne/Projects/Lumie/lumie-backend
./gradlew test
./gradlew :modules:staff:test
./gradlew :modules:auth:test

가장 관련 있는 테스트는 현재 주로 다음에 있습니다.

  • modules/staff/src/test/java/com/lumie/staff/application/service/StaffCommandServiceTest.java

관련 페이지