Fabric应用使用 @role 修饰器将授权规则直接附加到数据模型。 权限具有类型安全性,便于重构,并会自动编译到底层数据访问配置中。
在您开始之前
内置角色
Fabric 应用识别内置的 authenticated 角色。 还可以根据需要在策略中定义自定义角色。
| 角色 | 说明 | 用例 |
|---|---|---|
authenticated |
需要具有Fabric身份验证的有效用户会话 | 用户特定的数据,受保护的资源 |
@role修饰器
在类级别应用 @role 以控制哪些角色可以对实体执行哪些操作:
@role(roleName, actions, options?)
Parameters
| 参数 | 类型 | 说明 |
|---|---|---|
roleName |
string |
角色名称,例如 'authenticated' 或自定义应用程序角色 |
actions |
string \| string[] |
单个操作或操作数组:'create'、'read'、'update'、'delete',或全部使用 '*' |
options |
object |
具有 check、include 和 exclude 属性的可选对象 |
基本示例
将已通过身份验证的用户的访问权限限制为仅访问其自己的数据:
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声明匹配的subTodo 项。
类型安全的策略表达式
policy 回调提供对声明和实体字段的类型化访问。 TypeScript 从修饰类推断实体类型,从而提供自动完成和重构安全性:
policy: (claims, item) => claims.sub.eq(item.userId)
支持的声明
| 索赔 | 说明 | 示例值 |
|---|---|---|
claims.sub |
使用者标识符(用户 ID) | 00000000-0000-0000-0000-000000000001 |
claims.email |
用户电子邮件地址 | user@contoso.com |
claims.role |
用户角色(如果由标识提供者提供) | admin |
表达式运算符
| Operator | 例子 | 说明 |
|---|---|---|
.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;
}
此配置:
-
创建:只有创建者可以创建,并且只允许
title和content字段。 - 读取:只有创建者可以读取自己的文档。
-
更新:只有创建者才能更新,但不能修改
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;
}
管理员可以修改任何资源,但只有管理员可以删除。
后续步骤
- 配置身份验证,以设置身份提供商
- 使用 GraphQL 查询数据 以测试受权限保护的查询
- 用于架构生成命令的 CLI 命令参考