Cerbos + Drizzle ORM 适应器
一个适配器库 赛博斯 查询计划( E)计划资源 API)反应并将其转换为 滴入外科手术 SQL 表达式. 这使得您可以直接使用 Cerbos 查询计划 .
特征
- 支持逻辑运算符 :
and, (中文(简体) ),or, (中文(简体) ),not - 支持比较运算符 :
eq, (中文(简体) ),ne, (中文(简体) ),lt, (中文(简体) ),gt, (中文(简体) ),le, (中文(简体) ),ge, (中文(简体) ),in - 支持字符串运算符 :
contains, (中文(简体) ),startsWith, (中文(简体) ),endsWith - 支持通过
isSet运算符 - 支持设置意识运算符,例如
hasIntersection, (中文(简体) ),exists, (中文(简体) ),exists_one,以及all - 支持了解关系映射,包括嵌入式关系和多人加入
- 与 Drizzle SQLite, PostgreSQL, MySQL 和 Planet Scale 驱动程序合作
如何运作
Cerbos 能够响应 a PlanResources 请求有三种计划类型之一。 适配器镜像 API:
PlanKind.ALWAYS_ALLOWED:用户可以在不进行额外过滤的情况下访问资源.PlanKind.ALWAYS_DENIED:用户完全无法访问资源.PlanKind.CONDITIONAL: Cerbos 返回一个在读取数据时必须应用的表达式树. 适配器将这个表达式转换为 Drizzle SQL 过滤器.
queryPlanToDrizzle 将 Cerbos 表达式行走,通过映射器解决每个属性引用,并生成 Drizzle SQL 碎片。 然后,该碎片可以与您的查询构建链的其余部分组成(db.select().from(table).where(result.filter)) (中文(简体) ).
安装
npm install @cerbos/orm-drizzle
使用量
import { queryPlanToDrizzle, PlanKind } from "@cerbos/orm-drizzle";
import { eq, and } from "drizzle-orm";
import { resources } from "./schema";
const plan = await cerbos.planResources({
principal,
resource,
action,
});
const result = queryPlanToDrizzle({
queryPlan: plan,
mapper: {
"request.resource.attr.status": resources.status,
"request.resource.attr.owner": resources.ownerId,
},
});
if (result.kind === PlanKind.CONDITIONAL) {
const rows = await db
.select()
.from(resources)
.where(and(eq(resources.deleted, false), result.filter));
}
处理不同的计划类型
const evaluation = queryPlanToDrizzle({ queryPlan: plan, mapper });
switch (evaluation.kind) {
case PlanKind.ALWAYS_ALLOWED:
// run the query without extra filters
break;
case PlanKind.ALWAYS_DENIED:
// return an empty result immediately
break;
case PlanKind.CONDITIONAL:
const rows = await db
.select()
.from(resources)
.where(evaluation.filter);
break;
}
Cerbos计划参考两种资源(request.resource.attr.*)和校长(request.principal.attr.*),所以在映射器中包含您政策发出的路径.
映射选项
地图员将 Cerbos 属性引用与 Drizzle 列。 这可能是:
- 键为 Cerbos 属性引用和值的平面对象为 Drizzle 列或 SQL 表达式.
- 接收属性引用并返回列/表达式的函数.
- 带有
column属性和可选transform函数可以自定义运算符/值对如何转换为 SQL .
const result = queryPlanToDrizzle({
queryPlan,
mapper: {
"request.resource.attr.custom": {
column: sql`lower(${resources.title})`,
transform: ({ operator, value }) => {
if (operator !== "eq") throw new Error("Unsupported");
return eq(sql`lower(${resources.title})`, value.toLowerCase());
},
},
},
});
属性参考和函数
- 平面值:映射
request.resource.attr.field改为一栏(resources.field) (中文(简体) ). - 嵌入属性: 映射更长的路径, 如
request.resource.attr.owner.email。 。 。 . - 主要属性:地图
request.principal.attr.role或类似的路径 当政策检查呼叫者. - 动态分辨率: 通过映射函数
(reference) => ...在运行时计算映射.
每个映射器条目可以是:
- 列或 SQL 碎片 .
- 对象为
column和(或)transform以自定义每个运算符的翻译方式. - 为嵌入式资源结构绘制关系映射(下文叙述).
绘制关系图
关系可以使用 relation 选项,以镜像 Prisma 适配器的结构。 适配器会包起来
比较 EXISTS 子编辑,并在匹配相关表格中的列名时自动推断关系字段.
const result = queryPlanToDrizzle({
queryPlan,
mapper: {
"request.resource.attr.owner": {
relation: {
type: "one",
table: owners,
sourceColumn: resources.ownerId,
targetColumn: owners.id,
fields: {
email: owners.email,
},
},
},
"request.resource.attr.tags": {
relation: {
type: "many",
table: resourceTags,
sourceColumn: resources.id,
targetColumn: resourceTags.resourceId,
fields: {
name: {
relation: {
type: "one",
table: tags,
sourceColumn: resourceTags.tagId,
targetColumn: tags.id,
field: tags.name,
},
},
},
},
},
},
});
使用上面的映射器,查询计划参考文献有: request.resource.attr.owner.email 财务报告和审定财务报表 request.resource.attr.tags.name
已译成 EXISTS 加入 owners 财务报告和审定财务报表 tags 分别是表格.
处理收藏
hasIntersection: 用于标签等多值属性. 当 Cerbos 发出时hasIntersection(map(resource.tags, lambda t => t.name), ["tag"])映射器向上看被嵌入的球场 适配器将它转换成一个column IN (...)条件.exists, (中文(简体) ),exists_one,以及all: 当政策参考数组属性(例如,request.resource.attr.tags,将映射器条目标为关系。 适配器瞄准羊肉达变量,生成EXISTS,并自动将其与母表格相链接.filter: Cerbos 使用filter在计划建设期间。 适配器丢弃了这些羊肉,因为整个滤波器在德利兹地被重新运行.
测试
项目船装有一套综合测试套件,使用一个模拟SQLite数据库和官方的Drizzle ORM查询器,对所有支持的运营商进行操作.