@jeff-bao/rbac-cache
v0.2.9
Published
RBAC permission cache and data scope control for Prisma-based applications
Downloads
1,864
Maintainers
Readme
rbac-cache
基于 Prisma 的 RBAC 权限缓存与数据范围控制。
安装
npm install @jeff-bao/rbac-cache快速上手
import { PrismaClient } from '@prisma/client';
import { createRbac, createPrismaAdapter } from '@jeff-bao/rbac-cache';
const prisma = new PrismaClient();
const rbac = createRbac({
adapter: createPrismaAdapter(prisma),
ttl: 300_000, // 5 分钟,可选
});
// 缓存角色权限
rbac.setRolePermissions('admin', {
permissions: ['GET /api/v1/admin/users'],
permissionCodes: ['user:list', 'user:create'],
dataScope: 'all',
});
// 读取缓存权限(零 DB 查询)
const entry = rbac.getRolePermissions('admin');
// 获取部门及其所有子部门(BFS,含自身,缓存优先)
const deptIds = await rbac.getDescendantIds(5);
// [5, 6, 7, 8]
// 获取自身及所有下属(BFS,含自身,缓存优先)
const userIds = await rbac.getSubordinateIds(1);
// 多角色取最宽数据范围
const widest = rbac.getWidestDataScope(['personal', 'department_tree']);
// 'department_tree'
// 构建 Prisma where 条件
const where = rbac.buildDataScopeWhere(
'department_tree',
{ userId: 1, departmentId: 5 },
{ descendantDepartmentIds: [6, 7, 8] },
);
// { departmentId: { in: [5, 6, 7, 8] } }
// 缓存失效
rbac.invalidateRole('admin');
rbac.invalidateAllRoles();
rbac.invalidateDescendantCache(5); // 失效单个部门子树
rbac.invalidateDescendantCache(); // 失效全部部门子树
rbac.invalidateSubordinateCache(1); // 失效单个用户下属树
rbac.invalidateSubordinateCache(); // 失效全部用户下属树API
createRbac(options)
创建 RBAC 缓存实例,返回 RbacCache。
| 参数 | 类型 | 必填 | 说明 |
|--------|------|----------|-------------|
| adapter | DataSourceAdapter | 是 | 数据源适配器 |
| ttl | number | 否 | 缓存过期时间(毫秒),默认不过期 |
DataSourceAdapter
实现此接口或使用内置的 createPrismaAdapter(prisma)。
interface DataSourceAdapter {
findRolesWithPermissionsByCodes(codes: string[]): Promise<RolePermissionEntry[]>;
fetchAllUsers(): Promise<{ id: number; supervisorId: number | null }[]>;
fetchAllDepartments(): Promise<{ id: number; parentId: number | null }[]>;
}createPrismaAdapter(prisma)
创建基于 Prisma 的 DataSourceAdapter。prisma 参数只需满足 PrismaLike 接口(任意 Prisma 客户端均可)。
super_admin 特殊处理: 当查询的角色编码中包含 'super_admin' 时,跳过角色-权限关联表查询,直接返回数据库中全部权限,dataScope 设为 'all'。同批次的其他角色正常查询。
RbacCache 方法
权限缓存(同步)
| 方法 | 签名 | 说明 |
|--------|-----------|-------------|
| getRolePermissions | (code: string) => RolePermissionEntry \| undefined | 读取缓存角色,未缓存或已过期返回 undefined |
| setRolePermissions | (code: string, entry: RolePermissionEntry) => void | 写入缓存(遵循 TTL) |
| invalidateRole | (code: string) => void | 移除单个角色缓存 |
| invalidateAllRoles | () => void | 清空全部角色权限缓存 |
数据范围缓存(异步)
| 方法 | 签名 | 说明 |
|--------|-----------|-------------|
| getDescendantIds | (departmentId: number) => Promise<number[]> | BFS 获取部门自身及所有后代部门 ID。缓存优先,未命中时从 adapter 加载全量部门 |
| getSubordinateIds | (userId: number) => Promise<number[]> | BFS 获取用户自身及所有下属用户 ID。缓存优先,未命中时从 adapter 加载全量用户 |
| invalidateDescendantCache | (departmentId?: number) => void | 失效单个部门子树缓存,不传参则清空全部 |
| invalidateSubordinateCache | (userId?: number) => void | 失效单个用户下属树缓存,不传参则清空全部 |
纯函数工具
| 方法 | 签名 | 说明 |
|--------|-----------|-------------|
| getWidestDataScope | (scopes: DataScope[]) => DataScope | 从多个数据范围中取最宽的(all > department_tree > department > personal) |
| buildDataScopeWhere | (dataScope, user, context?, options?) => Record<string, unknown> \| undefined | 构建 Prisma where 条件片段,all 范围返回 undefined(无需过滤) |
buildDataScopeWhere 详解
buildDataScopeWhere(
dataScope: DataScope,
user: { departmentId?: number | null; userId: number },
context?: {
descendantDepartmentIds?: number[];
subordinateIds?: number[];
},
options?: {
departmentField?: string; // 默认:'departmentId'
ownerField?: string; // 默认:'createdBy'
},
): Record<string, unknown> | undefined数据范围行为:
| 范围 | 过滤条件 |
|-------|---------------|
| all | undefined — 无过滤 |
| department_tree | { departmentId: { in: [user.departmentId, ...descendantIds] } } |
| department | { departmentId: user.departmentId } |
| personal | { createdBy: { in: [user.userId, ...subordinateIds] } } |
当 user.departmentId 为 null/undefined 且范围为 department_tree 或 department 时,自动回退为按 createdBy 过滤。
RolePermissionEntry
interface RolePermissionEntry {
permissions: string[]; // 如:['GET /api/v1/admin/users']
permissionCodes: string[]; // 如:['user:list', 'user:create']
dataScope: DataScope; // 'all' | 'department_tree' | 'department' | 'personal'
}数据范围说明
| 范围 | 含义 |
|-------|---------|
| all | 全部数据,无过滤 |
| department_tree | 本部门及所有子部门 |
| department | 仅本部门 |
| personal | 本人及下属 |
Prisma Schema 约定
内置 createPrismaAdapter 要求以下表和字段:
role
| 字段 | 类型 | 说明 |
|--------|------|-------|
| code | String @unique | 如:'admin'、'operator' |
| dataScope | 枚举 | all / department_tree / department / personal |
permission
| 字段 | 类型 | 说明 |
|--------|------|-------|
| code | String | 如:'user:list' |
| path | String? | 如:'GET /api/v1/admin/users' |
role_permissions(关联表)
| 字段 | 类型 |
|--------|------|
| role_id | FK → role |
| permission_id | FK → permission |
user
| 字段 | 类型 | 说明 |
|--------|------|-------|
| id | Int | |
| supervisor_id | Int? | FK → user,可为空 |
department
| 字段 | 类型 | 说明 |
|--------|------|-------|
| id | Int | |
| parent_id | Int? | FK → department,可为空 |
开源协议
MIT
