데이터 권한 정의

Fabric 앱은 @role 데코레이터를 사용하여 권한 부여 규칙을 데이터 모델에 직접 연결합니다. 사용 권한은 형식이 안전하며 리팩터링이 가능하며 기본 데이터 액세스 구성으로 자동으로 컴파일됩니다.

시작하기 전 주의 사항:

  • 인증(현재 사용자)과 권한 부여(수행할 수 있는 작업)의 차이점 이해
  • ID 확인을 설정하기 위한 인증 구성 검토
  • 엔터티 기본 사항에 대한 데이터 모델 개요 이해

기본 제공 역할

Fabric 앱은 기본 제공 authenticated 역할을 인식합니다. 필요한 경우 정책에서 사용자 지정 역할을 정의할 수도 있습니다.

역할 Description 사용 사례
authenticated Fabric 인증을 사용하는 유효한 사용자 세션 필요 사용자별 데이터, 보호된 리소스

@role 데코레이터

어떤 역할이 엔터티에 대해 어떤 작업을 수행할 수 있는지 제어하려면 클래스 수준에 @role를 적용하세요.

@role(roleName, actions, options?)

매개 변수

매개 변수 Type Description
roleName string 역할 이름(예: 'authenticated' 사용자 지정 애플리케이션 역할)
actions string \| string[] 단일 작업 또는 배열: 'create', 'read', 'update'또는 'delete''*' 모두
options object check, includeexclude 속성을 가진 선택적 객체

기본 예제

인증된 사용자를 자신의 데이터로 제한합니다.

import { entity, role, uuid, text } from '@microsoft/rayfin-core';

@entity()
@role('authenticated', ['create', 'read', 'update', 'delete'], {
  policy: (claims, item) => claims.sub.eq(item.userId),
})
export class Todo {
  @uuid() id!: string;
  @text() title!: string;
  @text({ optional: true }) description?: string;
  @text() userId!: string;
}

이 예제에서:

  • 인증된 사용자는 JWT userId 클레임과 일치하는 Todo 항목 sub 에만 액세스할 수 있습니다.

타입 안전 정책 표현식

콜백은 policy 클레임 및 엔터티 필드 모두에 대한 형식화된 액세스를 제공합니다. TypeScript는 데코레이팅된 클래스에서 엔터티 형식을 유추하여 자동 완성 및 리팩터링 보안을 제공합니다.

policy: (claims, item) => claims.sub.eq(item.userId)

지원되는 클레임

클레임 Description 예제 값
claims.sub 주체 식별자(사용자 ID) 00000000-0000-0000-0000-000000000001
claims.email 사용자 전자 메일 주소 user@contoso.com
claims.role 사용자 역할(ID 공급자가 제공하는 경우) admin

식 연산자

Operator Example Description
.eq() claims.sub.eq(item.userId) 동일 여부 확인

논리 연산자

식과 다음을 결합 .and().or()합니다.

// User must own the item AND item must be active
@role('authenticated', 'read', {
  policy: (claims, item) =>
    claims.sub.eq(item.userId).and(item.isActive.eq(true))
})

// User is admin OR user owns the item
@role('authenticated', ['update', 'delete'], {
  policy: (claims, item) =>
    claims.role.eq('admin').or(claims.sub.eq(item.ownerId))
})

양쪽 모두 올바른 그룹화를 위해 자동으로 괄호로 지정됩니다.

필드 수준 권한

역할 옵션에서 include 또는 exclude을 사용하여 역할이 액세스할 수 있는 필드를 지정합니다.

특정 필드 포함

생성 작업 중에는 title 필드만 허용하세요.

@entity()
@role('authenticated', 'create', {
  policy: (claims, item) => claims.sub.eq(item.createdBy),
  include: ['title'],
})
export class Document {
  @uuid() id!: string;
  @text() title!: string;
  @text({ optional: true }) content?: string;
  @text() createdBy!: string;
}

특정 필드 제외

읽기 작업에서 중요한 필드 숨기기:

@entity()
@role('authenticated', 'read', {
  exclude: ['lastLogin', 'passwordHash'],
})
export class User {
  @uuid() id!: string;
  @text() email!: string;
  @date({ optional: true }) lastLogin?: Date;
  @text() passwordHash!: string;
}

비고

필드 배열은 엔터티의 실제 속성 이름에 입력됩니다. 필드 이름을 바꾸면 필드를 참조하는 모든 include 또는 exclude 목록에서 컴파일 시간 오류가 발생합니다.

작업별 권한

여러 @role 데코레이터를 사용하여 작업당 다른 규칙을 적용합니다.

@entity()
@role('authenticated', 'create', {
  policy: (claims, item) => claims.sub.eq(item.createdBy),
  include: ['title', 'content'],
})
@role('authenticated', 'read', {
  policy: (claims, item) => claims.sub.eq(item.createdBy),
})
@role('authenticated', 'update', {
  policy: (claims, item) => claims.sub.eq(item.createdBy),
  exclude: ['adminNotes'],
})
@role('authenticated', 'delete', {
  policy: (claims, item) => claims.sub.eq(item.createdBy),
})
export class SecureDocument {
  @uuid() id!: string;
  @text() title!: string;
  @text({ optional: true }) content?: string;
  @text({ optional: true }) adminNotes?: string;
  @text() createdBy!: string;
}

이 구성은 다음과 같습니다.

  • 만들기: 작성자만 만들 수 있으며 필드만 titlecontent 허용됩니다.
  • 읽기: 작성자만 자신의 문서를 읽을 수 있습니다.
  • 업데이트: 작성자만 업데이트할 수 있지만 수정 adminNotes할 수는 없습니다.
  • 삭제: 작성자만 삭제할 수 있습니다.

사용 권한의 작동 방식

  • 메타데이터 컬렉션: 클래스가 @role 정의되면 데코레이터가 사용 권한 메타데이터를 수집합니다.
  • 스키마 생성: 실행할 db apply때 CLI는 메타데이터를 읽고 권한 구성을 생성합니다.
  • 정책 컴파일: TypeScript 정책 콜백은 데이터 액세스 정책 식(예 @claims.sub eq @item.userId: )으로 컴파일됩니다.
  • 런타임 적용: 데이터 액세스 계층은 모든 API 요청에 대한 권한을 적용합니다.
  • 충돌 감지: 동일한 클래스의 여러 @role 데코레이터가 역할별로 집계되며 충돌 선언에 대한 경고가 표시됩니다.

일반적인 패턴

소유자 전용 액세스

@entity()
@role('authenticated', '*', {
  policy: (claims, item) => claims.sub.eq(item.ownerId)
})
export class PrivateNote {
  @uuid() id!: string;
  @text() ownerId!: string;
  @text() content!: string;
}

인증된 사용자에 대한 모든 권한

@entity()
@role('authenticated', '*')
export class BlogPost {
  @uuid() id!: string;
  @text() title!: string;
  @text() content!: string;
}

관리자 재정의

@entity()
@role('authenticated', ['create', 'read', 'update'], {
  policy: (claims, item) =>
    claims.role.eq('admin').or(claims.sub.eq(item.ownerId))
})
@role('authenticated', 'delete', {
  policy: (claims, _item) => claims.role.eq('admin')
})
export class ManagedResource {
  @uuid() id!: string;
  @text() ownerId!: string;
  @text() name!: string;
}

관리자는 모든 리소스를 수정할 수 있지만 관리자만 삭제할 수 있습니다.

다음 단계