概述
本节通过 Quokka 实验环境,逐步实践 CASL 库的核心功能。从最基础的 defineAbility 用法开始,到结合用户角色的条件权限,再到基于类实例的复杂判断,最后实现字段级别的访问控制。每种场景都配有可直接运行的代码示例。
基础用法:defineAbility
权限定义与判断
import { defineAbility } from '@casl/ability';
const ability = defineAbility((can, cannot) => {
can('read', 'all'); // 允许读取所有资源
cannot('update', 'Post'); // 禁止更新 Post
});
// 权限判断
ability.can('read', 'Post'); // true
ability.can('update', 'Post'); // false
ability.can('delete', 'Post'); // false(未声明 can delete)
typescript
核心机制:can/cannot 定义权限规则,ability.can() 查询判断结果。
权限判断逻辑
can('read', 'Post') → 查找是否存在允许 read Post 的规则 → true
cannot('update', 'Post') → 查找是否存在禁止 update Post 的规则 → false
can('delete', 'Post') → 未定义相关规则 → false(默认拒绝)
text
角色关联:条件权限
将权限定义与用户角色绑定:
import { defineAbility, AbilityBuilder, createMongoAbility } from '@casl/ability';
const user = { id: 1, isAdmin: true };
const { can, cannot, build } = new AbilityBuilder(createMongoAbility);
// 管理员拥有所有权限
if (user.isAdmin) {
can('manage', 'all');
} else {
can('read', 'Post');
}
const ability = build();
ability.can('delete', 'Post'); // true(isAdmin = true)
ability.can('update', 'Post'); // true
typescript
当 isAdmin 为 false 时,以上判断结果全部变为 false,权限随角色动态变化。
类实例判断:对象条件权限
定义 Post 实体类
class Post {
constructor(attrs: Record<string, any>) {
Object.assign(this, attrs);
}
id!: number;
author!: number;
isPublished!: boolean;
}
typescript
结合实例的权限规则
const { can, cannot, build } = new AbilityBuilder(createMongoAbility);
can('read', 'Post');
can('update', 'Post', { author: user.id }); // 只有作者可更新
cannot('update', 'Post', { isPublished: true }); // 已发布的不可更新
can('update', 'Post', { isPublished: true }, 'force'); // 管理员可强制更新
typescript
判断流程
const somePost = new Post({ author: 1, isPublished: false });
ability.can('update', somePost); // true - 作者匹配且未发布
typescript
判断 ability.can('update', somePost)
├── 规则1: can update Post { author: 1 } → author 匹配 → 通过
├── 规则2: cannot update Post { isPublished: true } → isPublished=false → 不适用
└── 结果: true
text
当 isPublished 改为 true 时:
const publishedPost = new Post({ author: 1, isPublished: true });
ability.can('update', publishedPost); // false - cannot 规则生效
typescript
条件匹配规则
| 场景 | author | isPublished | 结果 |
|---|---|---|---|
| 作者 + 未发布 | 匹配 | false | true |
| 作者 + 已发布 | 匹配 | true | false |
| 非作者 + 未发布 | 不匹配 | false | false |
| 非作者 + 管理员 | - | - | true |
字段级别控制
限制用户只能操作特定字段:
const { can, build } = new AbilityBuilder(createMongoAbility);
can('update', 'Post', ['content'], { author: user.id });
// 只有 content 字段可以被 author 更新
typescript
字段权限判断
const post = new Post({ author: 1, isPublished: false, content: 'hello' });
ability.can('update', post, 'content'); // true - 有 content 的更新权限
ability.can('update', post, 'title'); // false - 未授权 title 字段
ability.can('update', post, 'id'); // false - id 不在授权列表中
typescript
管理员字段权限
如果用户是管理员,则可以操作所有字段:
if (user.isAdmin) {
can('manage', 'all');
}
ability.can('update', post, 'content'); // true
ability.can('update', post, 'title'); // true
ability.can('update', post, 'author'); // true - 管理员无字段限制
typescript
CASL 权限定义方式对比
| 方式 | 适用场景 | 特点 |
|---|---|---|
defineAbility() | 简单场景 | 函数式,一行定义 |
AbilityBuilder | 复杂场景 | 支持条件逻辑,可组合 |
createMongoAbility | 需要条件查询 | 支持 MongoDB 查询语法 |
PureAbility | 自定义匹配 | 完全自定义条件匹配逻辑 |
完整示例代码
import { AbilityBuilder, createMongoAbility } from '@casl/ability';
// 用户定义
const user = { id: 1, isAdmin: false };
// Post 实体
class Post {
constructor(attrs: Record<string, any>) {
Object.assign(this, attrs);
}
}
// 权限定义
const { can, cannot, build } = new AbilityBuilder(createMongoAbility);
can('read', 'Post');
can('update', 'Post', { author: user.id });
cannot('update', 'Post', { isPublished: true });
if (user.isAdmin) {
can('manage', 'all');
}
const ability = build();
// 测试
const myPost = new Post({ author: 1, isPublished: false });
const otherPost = new Post({ author: 2, isPublished: false });
const publishedPost = new Post({ author: 1, isPublished: true });
console.log(ability.can('update', myPost)); // true
console.log(ability.can('update', otherPost)); // false
console.log(ability.can('update', publishedPost)); // false
typescript
关键知识点总结
| 知识点 | 说明 |
|---|---|
defineAbility | 函数式快速定义权限 |
AbilityBuilder | 构建器模式,支持条件逻辑 |
| 条件权限 | { author: user.id } 匹配实例属性 |
| 字段控制 | can('update', 'Post', ['content']) 限制字段 |
| 实例判断 | ability.can('update', postInstance) 传入类实例 |
manage / all | 特殊关键字,管理员的万能规则 |
↑