Definiowanie uprawnień do danych

Fabric Apps używa dekoratora @role do dołączania reguł autoryzacji bezpośrednio do modeli danych. Uprawnienia zapewniają bezpieczeństwo typów, ułatwiają refaktoryzację i są automatycznie kompilowane do bazowej konfiguracji dostępu do danych.

Zanim rozpoczniesz

Wbudowane role

Fabric Apps rozpoznaje wbudowaną rolę authenticated. W razie potrzeby można również zdefiniować role niestandardowe w zasadach.

Role Opis Przypadek użycia
authenticated Wymaga prawidłowej sesji użytkownika z uwierzytelnianiem Fabric Dane specyficzne dla użytkownika, chronione zasoby

Dekorator @role

Zastosuj @role na poziomie klasy, aby kontrolować, które role mogą wykonywać określone działania na encji:

@role(roleName, actions, options?)

Parameters

Parametr Typ Opis
roleName string Nazwa roli, taka jak 'authenticated' lub rola aplikacji niestandardowej
actions string \| string[] Pojedyncza akcja lub tablica: 'create', 'read', 'update', 'delete' lub '*' dla wszystkich
options object Opcjonalny obiekt z właściwościami check, includei exclude

Przykład podstawowy

Ogranicz uwierzytelnionych użytkowników do własnych danych:

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;
}

W tym przykładzie:

  • Uwierzytelnieni użytkownicy mogą uzyskiwać dostęp tylko do elementów Todo, w których wartość userId odpowiada roszczeniu sub tokenu JWT.

Wyrażenia zasad bezpieczne pod względem typów

Funkcja wywołania zwrotnego policy zapewnia typowany dostęp zarówno do pól deklaracji, jak i pól encji. TypeScript wywnioskuje typ encji na podstawie dekorowanej klasy, co zapewnia autouzupełnianie i bezpieczeństwo refaktoryzacji:

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

Obsługiwane roszczenia

Roszczenie Opis Przykładowa wartość
claims.sub Identyfikator podmiotu (identyfikator użytkownika) 00000000-0000-0000-0000-000000000001
claims.email Adres e-mail użytkownika user@contoso.com
claims.role Rola użytkownika (jeśli jest dostarczana przez dostawcę tożsamości) admin

Operatory wyrażeń

Obsługujący Example Opis
.eq() claims.sub.eq(item.userId) Sprawdzanie równości

Operatory logiczne

Łączenie wyrażeń za pomocą .and() i .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))
})

Obie strony są automatycznie ujmowane w nawiasy w celu prawidłowego grupowania.

Uprawnienia na poziomie pola

Określ pola, do których rola może uzyskiwać dostęp za pomocą include opcji roli lub exclude .

Uwzględnij określone pola

Zezwalaj tylko na title pole podczas operacji tworzenia:

@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;
}

Wykluczanie określonych pól

Ukryj poufne pola przed operacjami odczytu:

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

Uwaga / Notatka

Tablice pól są typowane zgodnie z faktycznymi nazwami właściwości encji. Zmiana nazwy pola powoduje błąd kompilacji na każdej liście include lub exclude, która się do niego odwołuje.

Uprawnienia specyficzne dla akcji

Zastosuj różne reguły dla każdej akcji przy użyciu wielu dekoratorów @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;
}

Ta konfiguracja:

  • Utwórz: Tylko autor może tworzyć i dozwolone są tylko pola title i content.
  • Odczyt: Tylko autor może odczytać własne dokumenty.
  • Aktualizacja: tylko twórca może aktualizować, ale nie może modyfikować adminNoteselementu .
  • Usuń: tylko twórca może usunąć.

Jak działają uprawnienia

  • Kolekcja metadanych: @role dekorator zbiera metadane uprawnień po zdefiniowaniu klasy.
  • Generowanie schematu: po uruchomieniu db applyinterfejs wiersza polecenia odczytuje metadane i generuje konfigurację uprawnień.
  • Kompilacja zasad: wywołania zwrotne zasad TypeScript są kompilowane w wyrażeniach zasad dostępu do danych (na przykład @claims.sub eq @item.userId).
  • Egzekwowanie w czasie wykonywania: warstwa dostępu do danych egzekwuje uprawnienia przy każdym żądaniu API.
  • Wykrywanie konfliktów: wiele dekoratorów @role w tej samej klasie jest grupowanych według ról, z ostrzeżeniami o sprzecznych deklaracjach.

Często używane wzorce

Dostęp wyłącznie dla właściciela

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

Pełny dostęp dla uwierzytelnionych użytkowników

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

Nadpisanie przez administratora

@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;
}

Administratorzy mogą modyfikować dowolny zasób, ale tylko administratorzy mogą usuwać.

Następne kroki