
认证鉴权【免费下载链接】caslCASL is an isomorphic authorization JavaScript library which restricts what resources a given user is allowed to access项目地址https://gitcode.com/gh_mirrors/ca/casl点击查看免费下载casl/ability是 CASL 权限库的核心包提供了权限规则的定义、存储、检索与判断的一整套运行时 API。本文以官方 API 参考文档docs-src/src/content/pages/api/casl-ability/en.md为骨架结合仓库内 packages/casl-ability/src 的实际源码实现逐项讲解Ability、MongoAbility、AbilityBuilder、defineAbility、ForbiddenError以及各 matcher 与工具函数的签名、参数、返回值与典型用法。读完本文你将能够独立使用这套 API 构建类型安全的权限模型、编写可测试的授权逻辑并在前端框架或后端服务中正确集成动态权限更新。包结构与模块划分casl/ability从入口packages/casl-ability/src/index.ts对外暴露两个模块core 模块提供Ability及其他核心类通过import * as core from casl/ability引入extra 模块提供额外的辅助函数如packRules、permittedFieldsOf、rulesToFields等通过import * as extra from casl/ability/extra引入。import * as core from casl/ability; import * as extra from casl/ability/extra;本文只讲解 core 包的内容extra 包的辅助函数说明见 casl/ability/extra API。文中所有示例均使用 TypeScript。Ability权限检查的基类Ability是权限检查功能的基类定义见 packages/casl-ability/src/Ability.ts它继承自RuleIndex见 packages/casl-ability/src/RuleIndex.ts负责对规则做索引、合并与匹配。它是一个泛型类接受 2 个类型参数Abilities要么是一个字符串字面量类型代表所有可能的 action要么是一个由两个元素组成的元组代表所有可能的 action 与 subject 组合。默认值为[string, Subject]Conditions条件的形状没有类型限制可以是任意类型。import { Ability, Abilities } from casl/ability; type ClaimAbility Abilitystring; type AppAbility Ability[string, string];可以看到ClaimAbility只关心 action适合做“声明式权限”场景例如 API 能力标记而AppAbility同时约束 action 与 subject适合常规的基于资源的授权。Ability 构造函数new AbilityA, Conditions(rules, options)下文用A简写Abilitiesrules: RawRuleFromA, Conditions[] []初始规则数组默认为空。每条规则的结构定义在 packages/casl-ability/src/RawRule.tsaction必填可以是单个 action 或数组、subject可选单个 subject 类型或数组、fields字段白名单、conditions条件对象、inverted是否为否定规则、reason规则不允许时的原因说明。options: AbilityOptionsA, Conditions {}可选配置项各选项含义如下detectSubjectType?: (subject?: Subject) string自定义 subject 类型检测逻辑参见 subject 类型检测指南conditionsMatcher?: ConditionsMatcherConditions自定义条件匹配语言参见 自定义 AbilityfieldMatcher?: FieldMatcher自定义字段匹配逻辑参见 自定义字段匹配器resolveAction?: ResolveActionNormalizeA[0]传入一个把别名解析为真实 action 的函数参见 定义 action 别名。基础用法const ability new Ability[read | update, Article]([ { action: read, subject: Article }, { action: update, subject: Article }, ]);在 packages/casl-ability/src/RuleIndex.ts 中可以看到构造函数还会读取两个隐含默认值anyAction默认为manage通配 actionanySubjectType默认为all通配 subject。因此{ action: manage, subject: all }表示“对任意 subject 拥有任意权限”。更完整的规则定义方式参见 定义规则指南。update整体替换规则update(rules)方法会完全替换实例上之前定义的所有规则参数rules: RawRuleFromA, Conditions[]返回值this便于链式调用触发事件更新前触发update更新后触发updated。典型场景是登录、登出或用户权限变更时刷新权限。从 RuleIndex 源码 可见其实现先发出update事件重置字段级规则标记保存新规则并重建索引最后发出updated事件import { Ability } from casl/ability; const ability new Ability([{ action: manage, subject: all }]); ability.update([]); // 收回所有权限入门用法可参见 CASL 指南。can权限正向判断can(...)检查给定的 action 与 subject 是否满足权限。根据Abilities泛型的不同它接受 1 个参数当Abilities是字符串时只传 action或 23 个参数当Abilities是元组时参数action: string要检查的 actionsubject: Subject要检查的 subjectfield?: string要检查的字段可选返回值boolean。import { Ability } from casl/ability; const claimAbility new Abilityread | update(); // 第 1 个泛型是字符串因此该方法只接受一个参数 claimAbility.can(read); const ability new Ability[read | update, Article](); // 第 1 个泛型是元组因此该方法接受 2~3 个参数 ability.can(read, Article);从 Ability.ts 源码 看can的核心逻辑是调用relevantRuleFor(action, subject, field)找到匹配的规则返回!!rule !rule.inverted即“存在规则且该规则不是否定规则”才为true。这保证了cannot规则可以否决can规则同时允许多条规则按优先级合并后取最先匹配者。cannot权限反向判断cannot(...)与can行为完全一致只是返回取反的结果。其源码实现Ability.ts就是return !this.can(...)。relevantRuleFor命中规则的调试查询relevantRuleFor(...)返回与给定 action、subject 和 field 匹配的那一条规则找不到时返回null可用于调试。参数与can完全相同返回值RuleAbilities, Conditions | null。其实现Ability.ts先通过detectSubjectType得到 subject 类型再调用rulesFor取出候选规则列表按规则优先级顺序逐一调用matchesConditions(subject)进行条件匹配返回第一个匹配的规则。相关调试技巧见 调试与测试指南。rulesFor查询指定类型的全部规则rulesFor(...)返回给定 action、subject 类型和 field 下注册的所有规则适合调试和扩展。与relevantRuleFor不同它的第二个参数接收的是subject 类型字符串或类而非 subject 实例参数action: stringsubjectType: SubjectType当Abilities是字符串字面量类型时可省略field?: string返回值RuleAbilities, Conditions[]。其实现RuleIndex.ts先调用possibleRulesFor取全部候选规则再在存在字段级规则时用matchesField(field)做字段过滤。注意第三个参数必须是字符串否则会抛出明确错误。possibleRulesFor忽略字段限制的规则查询possibleRulesFor(...)与rulesFor类似但最多接受 2 个参数取决于第一个泛型参数的类型返回忽略字段级限制的所有可能规则适合调试和扩展参数action: stringsubjectType: SubjectType返回值RuleAbilities, Conditions[]。在 RuleIndex.ts 的实现中它会合并三部分规则该 subject 类型下的 action 规则、该 subject 类型下的通配 actionmanage规则以及all通配 subject 下的规则合并结果会按优先级排序并被Object.freeze缓存避免重复计算。规则优先级由注册顺序决定——从 RuleIndex.ts 可以看到priority rawRules.length - i - 1即规则数组中越靠后的规则优先级越高这正是“先声明宽泛规则、后声明具体规则”能生效的底层原因。on订阅实例更新事件on(event, handler)允许注册事件处理器。目前仅支持两个事件update在实例被更新之前触发updated在实例被更新之后触发。参数event: update | updatedhandler: (event: Event) void返回值一个用于移除事件处理器的函数Unsubscribe。该能力对前端框架集成非常有用——通常应用里只有一个Ability实例而很多组件在规则变化后需要重新检查权限。事件底层使用链表结构存储处理器见 RuleIndex.ts并且在派发前先把处理器收集进数组避免处理器在回调中自我退订导致的问题。UpdateEvent会携带rules新规则数组、ability实例与target实例字段。rules 属性ability.rules返回传入Ability构造函数的RawRule[]数组即原始规则未做索引化处理。它在 RuleIndex.ts 中定义为一个 getter。detectSubjectType 方法实例上的detectSubjectType(subject)方法用于检测对象的 subject 类型对 subject 类型本身字符串/类和 subject 实例都有效参数subject: Subject返回值string。MongoAbility 与 createMongoAbility原文档中第二个Ability小节实际描述的是MongoAbility它继承自Ability并为两个选项设置了默认值conditionsMatcher默认设为mongoQueryMatcherfieldMatcher默认设为fieldPatternMatcher。同时它把Conditions泛型参数约束为MongoQuery默认即AbilityAbilities, MongoQuery。createMongoAbility(rules?, options?)是一个工厂函数用于创建“带 Mongo 风格条件”的Ability实例。从 packages/casl-ability/src/createMongoAbility.ts 的实现可以看到它本质上就是new Ability(rules, { conditionsMatcher: mongoQueryMatcher, fieldMatcher: fieldPatternMatcher, ...options })import { createMongoAbility } from casl/ability; const ability createMongoAbility([ { action: read, subject: Article, conditions: { private: false } }, ]);这意味着在多数业务项目中你并不需要直接new Ability(...)而是通过createMongoAbility获得开箱即用的 Mongo 查询条件匹配能力例如配合 casl-mongoose 或 casl-prisma 将权限直接翻译成数据库查询。AbilityBuilder声明式规则构建AbilityBuilderTAbility实现见 packages/casl-ability/src/AbilityBuilder.ts允许用声明式的方式构造Ability实例。它只接受一个泛型参数T extends AnyAbility。通常无需显式传入——只要在构造函数中传入Ability的类TypeScript 会自动推断。AbilityBuilder 构造函数参数AbilityType: AbilityClassTAbility既可以是Ability的类也可以是createMongoAbility这样的工厂函数源码通过isAbilityClass区分后分别走new或函数调用见 AbilityBuilder.ts。import { AbilityBuilder, createMongoAbility } from casl/ability; const { can, build } new AbilityBuilder(createMongoAbility);规则定义见 定义规则指南。AbilityBuilder 的 can 方法can(...)在rules数组中注册一条RawRule。根据Ability的Abilities泛型它接受 1 个参数字符串 action或 3 个参数action subject 条件/字段总体上接受 14 个参数有两个重载can(action, subjectType, fields, conditions)can(action, subjectType, conditions)其中action: string | string[]、subjectType: string | Function、fields: string[]、conditions: Conditions。返回值RuleBuilder——一个允许进一步修改已构造RawRule的类例如通过because(reason)为否定规则添加“被禁止的原因”说明见 AbilityBuilder.ts。从 AbilityBuilder.ts 的_addRule实现可以看到参数分派规则当第三、四个参数存在且第三个是字符串/数组时被解释为fields第四个参数作为conditions否则第三个参数作为conditions。示例import { AbilityBuilder, Ability, createMongoAbility, AbilityClass } from casl/ability; // 仅 action 的 Ability 类型 type ClaimAbility Abilityread | update; const ClaimAbility Ability as AbilityClassClaimAbility; const { can, build } new AbilityBuilder(ClaimAbility); can(read); can(update); // 或者 action subject 的 Ability 类型 const { can, build } new AbilityBuilder(createMongoAbility); can(read, Article, { private: true }); can(read, User, [firstName, lastName]); const ability build();AbilityBuilder 的 cannot 方法cannot(...)在AbilityBuilder内注册一条inverted否定规则接受与can相同的参数、具有相同的行为区别是内部为规则打上inverted: true标记。build 方法build(options?)构建一个指定Ability类型的实例参数options?: AbilityOptionsOfTAbility返回值一个新的TAbility实例。AbilityBuilder 的 rules 属性builder.rules保存由can和cannot注册的RawRule[]数组AbilityBuilder.ts在build()时会原样传给Ability构造函数。defineAbility紧凑的函数式定义defineAbility(define, options?)允许以紧凑的函数形式定义一个MongoAbility实例。它不能用来创建普通Ability实例非常适用于编写测试与文档。签名T为TAbilityT extends AnyAbility(define: DSLT, void, options?: AbilityOptionsOfT) TT extends AnyAbility(define: DSLT, Promisevoid, options?: AbilityOptionsOfT) PromiseT从 AbilityBuilder.ts 的实现可见它内部创建了一个基于createMongoAbility的AbilityBuilder把builder.can与builder.cannot作为回调参数传入define若define返回 Promise 则等待其完成后调用build(options)。这使defineAbility天然支持异步规则初始化import { defineAbility } from casl/ability; const ability defineAbility((can, cannot) { can(read, Article, { private: false }); cannot(delete, Article, { authorId: 1 }); });ForbiddenError权限不足时中断执行ForbiddenErrorTAbility实现见 packages/casl-ability/src/ForbiddenError.ts用于在用户没有权限时停止后续代码执行。它的构造函数是私有的因此不能用new实例化在 TypeScript 中。它是一个接受TAbility泛型的错误类同时暴露action、subject、field、subjectType等只读字段便于在错误处理中输出诊断信息。import { ForbiddenError, defineAbility } from casl/ability; const ability defineAbility((can) { can(read, User) }); ForbiddenError.from(ability).throwUnlessCan(read, Article); // fetch article from database // 上述代码若用户无权 read Article会在此处抛出 ForbiddenError后续代码不会执行static fromForbiddenError.from(ability)从给定的Ability实例创建ForbiddenError参数ability: TAbility返回值ForbiddenError实例。static setDefaultMessageForbiddenError.setDefaultMessage(messageOrFn)修改所有ForbiddenError的默认错误消息。默认消息为Cannot execute ${error.action} on ${error.subjectType}参数messageOrFn: string | GetErrorMessage可以是字符串或返回字符串的函数error string返回值void。import { ForbiddenError } from casl/ability; ForbiddenError.setDefaultMessage(Not authorized); // 或者更详细的函数形式 ForbiddenError.setDefaultMessage(error You are not allowed to ${error.action} on ${error.subjectType});从 ForbiddenError.ts 的实现可以看到字符串会被包装成返回该字符串的函数存入静态字段_defaultErrorMessage。setMessagesetMessage(message)修改某一个ForbiddenError实例的消息参数message: string返回值this链式调用。import { ForbiddenError } from casl/ability; import ability from ./appAbility; ForbiddenError.from(ability) .setMessage(You cannot update posts) .throwUnlessCan(update, Post);throwUnlessCanthrowUnlessCan(...)接受与Ability.can相同的参数若用户无法对给定 subject 执行给定 action则抛出ForbiddenError。其内部先调用unlessCan进行判定ForbiddenError.ts若找到正向规则则直接返回否则填充action、subject、subjectType、field字段并按“自定义 message → 规则的reason→ 全局默认消息”的优先级确定错误文本this.message || reason || _defaultErrorMessage(this)。这意味着通过AbilityBuilder的because(reason)设置的规则原因会优先于全局默认消息呈现给用户。getDefaultErrorMessagegetDefaultErrorMessage()返回ForbiddenError的默认错误消息。在调用ForbiddenError.setDefaultMessage之后可以用它恢复默认消息源码中默认消息函数保存在ForbiddenError._defaultErrorMessage。fieldPatternMatcher通配符字段匹配器fieldPatternMatcher(fields)是一个工厂函数接受字段数组返回一个使用通配符*按模式匹配字段的函数。它是MongoAbility的默认fieldMatcher选项。工厂参数fields: string[]工厂返回值MatchField匹配器参数field: string匹配器返回值boolean。import { fieldPatternMatcher } from casl/ability; const matchField fieldPatternMatcher([name, email, address.**]); console.log(matchField(name)); // true console.log(matchField(address.street)); // true从 packages/casl-ability/src/matchers/field.ts 的源码实现可以看到*匹配单段字段名不跨.**匹配跨层级的任意路径当字段数组不含任何*时会退化为精确的indexOf查找避免不必要的正则编译开销惰性求值首次调用才编译正则并缓存。相关主题Ability API、限制字段访问、自定义 Ability。mongoQueryMatcherMongoDB 查询条件匹配器mongoQueryMatcher(conditions)是一个工厂函数基于 MongoDB 查询语言 创建匹配 subject 的函数。它是MongoAbility的默认conditionsMatcher选项。工厂参数conditions: MongoQuery工厂返回值ConditionsMatcherMongoQuery匹配器参数object: RecordPropertyKey, any匹配器返回值boolean。import { mongoQueryMatcher } from casl/ability; const matchConditions mongoQueryMatcher({ authorId: 1, private: true }); console.log(matchConditions({ authorId: 2 })); // false console.log(matchConditions({ authorId: 1, private: true })); // true从 packages/casl-ability/src/matchers/conditions.ts 的源码可以看到它基于ucast/mongo2js实现内置了$eq、$ne、$lt、$lte、$gt、$gte、$in、$nin、$all、$size、$regex、$options、$elemMatch、$exists等字段级操作符以及eq、ne、within、and等解释器还支持and逻辑组合。该匹配器可作为conditionsMatcher选项传给Ability类。相关主题Ability API、条件深入、自定义 Ability。buildMongoQueryMatcher扩展 Mongo 操作符buildMongoQueryMatcher(parsingInstructions, interpreters)是一个“工厂的工厂”它允许用自定义 Mongo 操作符扩展mongoQueryMatcher。工厂参数parsingInstructions: Recordstring, ParsingInstructioninterpreters: Recordstring, JsOperator工厂返回值扩展后的mongoQueryMatcher。源码实现conditions.ts就是把自定义的解析指令和解释器分别合并到默认集合{ ...defaultInstructions, ...instructions }与{ ...defaultInterpreters, ...interpreters }后再创建工厂。结果同样可以作为conditionsMatcher选项传给Ability类。相关主题mongoQueryMatcher API、自定义 Ability。createAliasResolveraction 别名解析器createAliasResolver(aliasMap)创建一个把别名解析为真实 action 的函数可作为resolveAction选项传给Ability类。参数aliasMap: AliasMap返回值(action: string | string[]) string | string[]。从 packages/casl-ability/src/utils.ts 的实现看createAliasResolver在创建时默认会校验别名表不允许把保留 actionmanage用作别名、不允许出现循环别名否则抛出明确错误随后返回一个把别名逐层展开合并为真实 action 数组的函数。例如可以定义readable别名指向[read, list]之后规则里写readable时会被自动展开。详见 定义 action 别名。detectSubjectType默认 subject 类型检测detectSubjectType(subject)是默认的 subject 类型检测逻辑可作为detectSubjectType选项传给Ability类也可在其基础上扩展。检测顺序如下若subject为undefined返回all对应RuleIndex中的anySubjectType默认值见 RuleIndex.ts若subject是ForcedSubject通过subject()强制标记过类型返回其强制类型若subject是对象返回constructor.modelName || constructor.name。参数subject?: {}返回值字符串subject 类型。从 utils.ts 的源码实现可以看到modelName优先于name这为 Mongoose 等 ORM 的模型类型检测提供了挂载点且仅当对象自身而非原型链带有__caslSubjectType__标记时才会返回该标记值。另外RuleIndex.ts 会在建索引时根据 subject 类型是字符串还是类来自动优化检测策略DETECT_SUBJECT_TYPE_STRATEGY无需每次调用都走通用检测路径。相关主题subject 类型检测指南。subject为普通对象强制标记 subject 类型subject(subjectType, object)为普通对象设置 subject 类型。如果你使用类或自定义了detectSubjectType算法则不需要使用它。它接受两个泛型参数TSubjectType和TObject参数subjectType: TSubjectTypeobject: TObject返回值TObject ForcesSubjectTSubjectType带有__caslSubjectType__标记的交叉类型。底层实现是 utils.ts 中的setSubjectType通过入口导出为subject用Object.defineProperty定义不可枚举的__caslSubjectType__属性如果对象已被标记为其他类型再重新标记会抛出错误以避免类型冲突。import { subject } from casl/ability; const post subject(Post, { id: 1, title: Hello }); // 之后 can(read, post) 会按 Post 类型进行规则匹配相关主题subject 类型检测指南。与周边生态的衔接core 包的这些 API 是整个 CASL 体系的地基casl-mongoosepackages/casl-mongoose的accessibleBy将MongoAbility的规则翻译成 Mongoose 查询casl-prismapackages/casl-prisma通过createPrismaAbility把条件转译为 Prisma 查询casl-reactpackages/casl-react与casl-vuepackages/casl-vue则依赖Ability.update与on(updated)事件实现响应式的权限 UI 更新。理解本文的 core API 是深入使用这些框架集成包的前提。赞分享认证鉴权【免费下载链接】caslCASL is an isomorphic authorization JavaScript library which restricts what resources a given user is allowed to access项目地址https://gitcode.com/gh_mirrors/ca/casl点击查看免费下载相关推荐CASL 的 casl/ability/extra API 实战指南rulesToQuery、rulesToAST、rulesToFields、permittedFieldsOf 与规则打包CASL 的 casl/ability/extra API 实战指南rulesToQuery、rulesToAST、rulesToFields、permit认证鉴权最强权限控制CASL casl/ability 2025实战全解析最强权限控制CASL casl/ability 2025实战全解析 还在手动编写复杂的权限验证逻辑每次新增功能都要重新设计权限系统一文解决你所有权限管理认证鉴权CASL 入门指南使用 casl/ability 实现同构 JavaScript 权限控制CASL 入门指南使用 casl/ability 实现同构 JavaScript 权限控制 CASL读作 /ˈkæsəl/如 castle 是一个同构认证鉴权上一篇LiteRT-LM让手机端和树莓派本地跑 Gemma/Qwen 的跨平台 LLM 推理运行时下一篇Telegraf 依赖许可证全景解读读懂 LICENSE_OF_DEPENDENCIES.md 与自动化合规校验创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考