본문으로 건너뛰기

RBAC

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

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

이 페이지는 현재 모델을 다루는 reference 문서입니다.

소스 경로

Path역할
libs/common/src/main/java/com/lumie/common/auth/Role.java전역 role 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.javatenant 범위 permission catalog
modules/staff/src/main/java/com/lumie/staff/domain/entity/StaffPermission.javastaff-to-permission assignment row
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 lifecycle 작업에서 role hierarchy 강제
modules/staff/src/main/java/com/lumie/staff/adapter/in/web/PermissionController.javapermission query surface

적용 계층

전역 역할 계층

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

RoleAuthority level일반적인 의미
OWNER가장 높음tenant 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가 예전 role 이름을 여전히 보낼 때 중요합니다.

테넌트 범위 Staff 권한 모델

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

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

중요한 경계 사실:

  • PermissionTenantScopedEntity를 상속하므로 permission catalog도 tenant 범위입니다.
  • StaffPermission은 base class를 상속하지 않지만, insert 시 tenant_id를 명시적으로 씁니다.
  • permission query endpoint는 /v1/permissions 아래에 있습니다.
  • staff permission 할당 흐름은 staff service에 있으며, Spring Security가 이를 전역적으로 자동 적용하지는 않습니다.

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

계층 1: 인증과 거친 역할 구분

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

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

AuthorizationGuard.requireOwner()는 homepage 게시나 tenant 관리, export 일부처럼 OWNER만 수행할 수 있는 작업에 사용됩니다.

계층 3: 모듈 서비스 규칙

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

  • 생성은 MANAGER 또는 INSTRUCTOR만 허용
  • 작업자는 자신을 관리할 수 없음
  • 작업자는 canManage(...)를 통해 대상보다 엄격하게 높아야 함
  • role check를 통과해도 billing quota, 배정된 class, 예정된 일정이 작업을 막을 수 있음

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

현재 이 모델이 하지 않는 것

  • 중앙 정책 엔진이나 annotation 기반의 통합 fine-grained permission framework가 없습니다.
  • staff permission은 web layer에서 모든 endpoint에 대해 자동으로 검사되지 않습니다.
  • student는 거친 role 모델만 사용하며, staff permission catalog는 staff capability를 위한 것입니다.

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

  • Spring Security
  • 공용 guard
  • application service
  • tenant 범위 permission 조회

실패 모드와 경계 위험

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

검증 명령어

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

관련 페이지