PermissionCore
PermissionCore 是运行时最主要的入口。你平时会用到的初始化、关闭、权限判断、行级范围、字段过滤、资源读取和缓存失效,都从这里开始。
最简单使用示例
最重要的使用前提只有一条:所有公共 API 都必须在 await pc.init() 之后调用。未初始化时会抛 NOT_INITIALIZED,而不是悄悄返回一个默认结果。
构造器
常用选项
完整 API 一览
按接入路径怎么用
HTTP-only常用assert()、can()和getResources()DB-only常用can()、assert()、getRowScope()、filterRows()和filterFields()Full standard stack会同时使用接口权限、数据权限、行级范围、缓存失效和管理 API
必须单独记住的约束
匿名请求约定
公开 API 的 userId 约定保持为字符串。未登录请求应由调用方在中间件或 Service 入口直接当作无权限处理,而不是把 null 或 undefined 传进 PermissionCore。
filterFields() 的 action 不能省略
filterFields(userId, action, resource, data) 的第二个参数必须显式表达当前读写动作。这样才能和 can(userId, action, resource) 使用同一套判断逻辑。
write 在请求侧是 AND 语义
如果你调用:
它会按 create && update 去判断,往往会比预期更严格。写入过滤通常更推荐明确使用 create 或 update。
行级权限和字段过滤是两层能力
can() / assert() 负责集合门禁。
如果规则里还带了 where,你通常会继续用:
getRowScope():在查库前拿到范围canRow()/assertRow():对单条记录继续判断filterRows():对结果列表做收口
最后才轮到 filterFields() 去处理字段级收口。
字段过滤还有两个容易忽略的点:
- 字段规则仍然依赖集合权限;只有
db:orders:amount但没有db:orders时,字段不会单独放行 - 字段级
where求值时,运行时会把整条对象继续作为 row 传入,这样字段规则可以引用同一行里的其他字段
context 只补充变量,不覆盖当前 userId
getRowScope()、canRow()、assertRow()、filterRows()、filterFields() 都允许你传 context,供 valueFrom 读取额外变量。
但运行时始终以 API 参数里的 userId 作为当前主体;即使你在 context 里也传了 userId,最终参与求值的仍然是外层那个 userId。
getPermissions() 和 getResources() 的区别
需要特别注意:getResources() 适合做入口显隐,但它不是最终鉴权结果。存在通配 allow 配合精确 deny 时,前端仍应以 can() 为最终判断依据。
在 strict 模式下,getResources() 还会主动剔除“已经被 deny 覆盖”的 allow 资源,所以它天然偏保守,更适合 UI 预显隐而不是最终放行判定。
常见返回结果示例
can() / cannot()
返回结果就是布尔值:
assert()
成功时没有返回 payload:
失败时抛出带 code 的错误:
filterFields()
返回结果仍然是对象,但只保留有权限的字段:
getRowScope()
返回结果是标准化后的范围结构:
canRow() / cannotRow()
返回结果仍然是布尔值:
assertRow()
成功时仍然没有返回 payload:
filterRows()
返回结果仍然是数组,只保留当前用户有权看到的记录。
getPermissions()
返回的是完整规则数组:
getResources()
返回结构是纯字符串数组,不是对象数组:
这里最好直接记住两点:
- 每一项就是资源路径字符串
- 返回值只说明“这个 action 下可先参考的资源列表”,不是最终放行结果
invalidate() / invalidateAll()
这两个方法成功时同样没有返回 payload:
一个最常见的用法
这个顺序更接近推荐用法:
- 接口入口先判断接口权限
- 进入业务后再判断数据权限
- 然后收口记录范围
- 最后对返回对象做字段过滤