bknd-assign-permissions
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAssign Permissions
分配权限
Configure detailed permissions for roles using simple strings, extended format with effects, and conditional policies.
使用简单字符串、带效果的扩展格式和条件策略为角色配置详细权限。
Prerequisites
前提条件
- Bknd project with code-first configuration
- Auth enabled ()
auth: { enabled: true } - Guard enabled ()
guard: { enabled: true } - At least one role defined (see bknd-create-role)
- 采用代码优先配置的Bknd项目
- 已启用认证()
auth: { enabled: true } - 已启用Guard()
guard: { enabled: true } - 至少已定义一个角色(参见bknd-create-role)
When to Use UI Mode
何时使用UI模式
- Viewing current role permissions
- Quick permission checks
UI steps: Admin Panel > Auth > Roles > Select role
Note: Permission assignment requires code mode. UI is read-only.
- 查看当前角色权限
- 快速检查权限
UI操作步骤: 管理面板 > 认证 > 角色 > 选择角色
注意: 权限分配需要使用代码模式,UI仅支持只读查看。
When to Use Code Mode
何时使用代码模式
- Assigning permissions to roles
- Adding permission effects (allow/deny)
- Creating conditional policies
- Entity-specific permission rules
- 为角色分配权限
- 添加权限效果(允许/拒绝)
- 创建条件策略
- 配置实体特定权限规则
Code Approach
代码实现方式
Step 1: Simple Permission Strings
步骤1:简单权限字符串
Assign basic permissions as string array:
typescript
import { serve } from "bknd/adapter/bun";
import { em, entity, text } from "bknd";
const schema = em({
posts: entity("posts", { title: text().required() }),
});
serve({
connection: { url: "file:data.db" },
config: {
data: schema.toJSON(),
auth: {
enabled: true,
guard: { enabled: true },
roles: {
editor: {
implicit_allow: false,
permissions: [
"data.entity.read", // Read any entity
"data.entity.create", // Create in any entity
"data.entity.update", // Update any entity
// No delete permission
],
},
},
},
},
});以字符串数组形式分配基础权限:
typescript
import { serve } from "bknd/adapter/bun";
import { em, entity, text } from "bknd";
const schema = em({
posts: entity("posts", { title: text().required() }),
});
serve({
connection: { url: "file:data.db" },
config: {
data: schema.toJSON(),
auth: {
enabled: true,
guard: { enabled: true },
roles: {
editor: {
implicit_allow: false,
permissions: [
"data.entity.read", // 读取任意实体
"data.entity.create", // 在任意实体中创建记录
"data.entity.update", // 更新任意实体记录
// 无删除权限
],
},
},
},
},
});Available Permissions
可用权限列表
| Permission | Filterable | Description |
|---|---|---|
| Yes | Read entity records |
| Yes | Create new records |
| Yes | Update existing records |
| Yes | Delete records |
| No | Sync database schema |
| No | Execute raw SELECT |
| No | Execute raw INSERT/UPDATE/DELETE |
Filterable means you can add conditions/filters via policies.
| 权限 | 可过滤 | 描述 |
|---|---|---|
| 是 | 读取实体记录 |
| 是 | 创建新记录 |
| 是 | 更新现有记录 |
| 是 | 删除记录 |
| 否 | 同步数据库 schema |
| 否 | 执行原生SELECT语句 |
| 否 | 执行原生INSERT/UPDATE/DELETE语句 |
可过滤表示你可以通过策略添加条件/过滤规则。
Step 2: Extended Permission Format
步骤2:扩展权限格式
Use objects for explicit allow/deny effects:
typescript
{
roles: {
moderator: {
implicit_allow: false,
permissions: [
{ permission: "data.entity.read", effect: "allow" },
{ permission: "data.entity.update", effect: "allow" },
{ permission: "data.entity.delete", effect: "deny" }, // Explicit deny
],
},
},
}使用对象形式定义明确的允许/拒绝效果:
typescript
{
roles: {
moderator: {
implicit_allow: false,
permissions: [
{ permission: "data.entity.read", effect: "allow" },
{ permission: "data.entity.update", effect: "allow" },
{ permission: "data.entity.delete", effect: "deny" }, // 明确拒绝
],
},
},
}Permission Effects
权限效果说明
| Effect | Description |
|---|---|
| Grant the permission (default) |
| Explicitly block the permission |
Deny overrides allow - useful when but you want to block specific actions.
implicit_allow: true| 效果 | 描述 |
|---|---|
| 授予权限(默认值) |
| 明确阻止权限 |
拒绝会覆盖允许 - 当但你想阻止特定操作时非常有用。
implicit_allow: trueStep 3: Conditional Policies
步骤3:条件策略
Add policies for fine-grained control:
typescript
{
roles: {
content_editor: {
implicit_allow: false,
permissions: [
{
permission: "data.entity.read",
effect: "allow",
policies: [
{
description: "Only read posts and comments",
condition: { entity: { $in: ["posts", "comments"] } },
effect: "allow",
},
],
},
{
permission: "data.entity.create",
effect: "allow",
policies: [
{
condition: { entity: { $in: ["posts", "comments"] } },
effect: "allow",
},
],
},
],
},
},
}添加策略实现细粒度控制:
typescript
{
roles: {
content_editor: {
implicit_allow: false,
permissions: [
{
permission: "data.entity.read",
effect: "allow",
policies: [
{
description: "仅读取文章和评论",
condition: { entity: { $in: ["posts", "comments"] } },
effect: "allow",
},
],
},
{
permission: "data.entity.create",
effect: "allow",
policies: [
{
condition: { entity: { $in: ["posts", "comments"] } },
effect: "allow",
},
],
},
],
},
},
}Policy Structure
策略结构
typescript
{
description?: string, // Human-readable (optional)
condition?: ObjectQuery, // When policy applies
effect: "allow" | "deny" | "filter",
filter?: ObjectQuery, // Row filter (for effect: "filter")
}typescript
{
description?: string, // 人类可读描述(可选)
condition?: ObjectQuery, // 策略适用条件
effect: "allow" | "deny" | "filter",
filter?: ObjectQuery, // 行级过滤规则(当effect为"filter"时使用)
}Policy Effects
策略效果说明
| Effect | Purpose |
|---|---|
| Grant when condition met |
| Block when condition met |
| Apply row-level filter to results |
| 效果 | 用途 |
|---|---|
| 当条件满足时授予权限 |
| 当条件满足时阻止权限 |
| 对结果应用行级过滤 |
Condition Operators
条件运算符
| Operator | Description | Example |
|---|---|---|
| Equal | |
| Not equal | |
| In array | |
| Not in array | |
| Greater than | |
| Greater or equal | |
| Less than | |
| Less or equal | |
| 运算符 | 描述 | 示例 |
|---|---|---|
| 等于 | |
| 不等于 | |
| 在数组中 | |
| 不在数组中 | |
| 大于 | |
| 大于等于 | |
| 小于 | |
| 小于等于 | |
Step 4: Variable Placeholders
步骤4:变量占位符
Reference runtime context with :
@variable| Placeholder | Description |
|---|---|
| Current user's ID |
| Current user's email |
| Current user's role |
| Current entity name |
| Current record ID |
Example - user can only update their own profile:
typescript
{
permissions: [
{
permission: "data.entity.update",
effect: "allow",
policies: [
{
condition: { entity: "users", "@id": "@user.id" },
effect: "allow",
},
],
},
],
}使用引用运行时上下文:
@variable| 占位符 | 描述 |
|---|---|
| 当前用户ID |
| 当前用户邮箱 |
| 当前用户角色 |
| 当前实体名称 |
| 当前记录ID |
示例 - 用户仅能更新自己的资料:
typescript
{
permissions: [
{
permission: "data.entity.update",
effect: "allow",
policies: [
{
condition: { entity: "users", "@id": "@user.id" },
effect: "allow",
},
],
},
],
}Step 5: Entity-Specific Permissions
步骤5:实体特定权限
Grant different permissions per entity:
typescript
{
roles: {
blog_author: {
implicit_allow: false,
permissions: [
// Full CRUD on posts
{
permission: "data.entity.read",
effect: "allow",
policies: [{ condition: { entity: "posts" }, effect: "allow" }],
},
{
permission: "data.entity.create",
effect: "allow",
policies: [{ condition: { entity: "posts" }, effect: "allow" }],
},
{
permission: "data.entity.update",
effect: "allow",
policies: [{ condition: { entity: "posts" }, effect: "allow" }],
},
{
permission: "data.entity.delete",
effect: "allow",
policies: [{ condition: { entity: "posts" }, effect: "allow" }],
},
// Read-only on categories
{
permission: "data.entity.read",
effect: "allow",
policies: [{ condition: { entity: "categories" }, effect: "allow" }],
},
],
},
},
}为不同实体授予不同权限:
typescript
{
roles: {
blog_author: {
implicit_allow: false,
permissions: [
// 对文章拥有完整CRUD权限
{
permission: "data.entity.read",
effect: "allow",
policies: [{ condition: { entity: "posts" }, effect: "allow" }],
},
{
permission: "data.entity.create",
effect: "allow",
policies: [{ condition: { entity: "posts" }, effect: "allow" }],
},
{
permission: "data.entity.update",
effect: "allow",
policies: [{ condition: { entity: "posts" }, effect: "allow" }],
},
{
permission: "data.entity.delete",
effect: "allow",
policies: [{ condition: { entity: "posts" }, effect: "allow" }],
},
// 对分类仅拥有只读权限
{
permission: "data.entity.read",
effect: "allow",
policies: [{ condition: { entity: "categories" }, effect: "allow" }],
},
],
},
},
}Common Patterns
常见模式
Read-Only Role
只读角色
typescript
{
roles: {
viewer: {
implicit_allow: false,
permissions: ["data.entity.read"],
},
},
}typescript
{
roles: {
viewer: {
implicit_allow: false,
permissions: ["data.entity.read"],
},
},
}CRUD Without Delete
拥有CRUD权限但无删除权限
typescript
{
roles: {
contributor: {
implicit_allow: false,
permissions: [
"data.entity.read",
"data.entity.create",
"data.entity.update",
{ permission: "data.entity.delete", effect: "deny" },
],
},
},
}typescript
{
roles: {
contributor: {
implicit_allow: false,
permissions: [
"data.entity.read",
"data.entity.create",
"data.entity.update",
{ permission: "data.entity.delete", effect: "deny" },
],
},
},
}Admin with Restricted Raw Access
受限的管理员角色(无原生数据库访问权限)
typescript
{
roles: {
admin: {
implicit_allow: true, // Allow all by default
permissions: [
// But deny raw database access
{ permission: "data.raw.query", effect: "deny" },
{ permission: "data.raw.mutate", effect: "deny" },
],
},
},
}typescript
{
roles: {
admin: {
implicit_allow: true, // 默认允许所有操作
permissions: [
// 但拒绝原生数据库访问权限
{ permission: "data.raw.query", effect: "deny" },
{ permission: "data.raw.mutate", effect: "deny" },
],
},
},
}Multi-Entity Role
多实体角色
typescript
{
roles: {
content_manager: {
implicit_allow: false,
permissions: [
// Content entities: full CRUD
{
permission: "data.entity.read",
effect: "allow",
policies: [{
condition: { entity: { $in: ["posts", "pages", "comments", "media"] } },
effect: "allow",
}],
},
{
permission: "data.entity.create",
effect: "allow",
policies: [{
condition: { entity: { $in: ["posts", "pages", "comments", "media"] } },
effect: "allow",
}],
},
{
permission: "data.entity.update",
effect: "allow",
policies: [{
condition: { entity: { $in: ["posts", "pages", "comments", "media"] } },
effect: "allow",
}],
},
{
permission: "data.entity.delete",
effect: "allow",
policies: [{
condition: { entity: { $in: ["posts", "pages", "comments"] } }, // No media delete
effect: "allow",
}],
},
],
},
},
}typescript
{
roles: {
content_manager: {
implicit_allow: false,
permissions: [
// 内容实体:拥有完整CRUD权限
{
permission: "data.entity.read",
effect: "allow",
policies: [{
condition: { entity: { $in: ["posts", "pages", "comments", "media"] } },
effect: "allow",
}],
},
{
permission: "data.entity.create",
effect: "allow",
policies: [{
condition: { entity: { $in: ["posts", "pages", "comments", "media"] } },
effect: "allow",
}],
},
{
permission: "data.entity.update",
effect: "allow",
policies: [{
condition: { entity: { $in: ["posts", "pages", "comments", "media"] } },
effect: "allow",
}],
},
{
permission: "data.entity.delete",
effect: "allow",
policies: [{
condition: { entity: { $in: ["posts", "pages", "comments"] } }, // 无媒体删除权限
effect: "allow",
}],
},
],
},
},
}Deny Specific Entity
拒绝访问特定实体
typescript
{
roles: {
user: {
implicit_allow: false,
permissions: [
// Can read most entities
"data.entity.read",
// But never access secrets entity
{
permission: "data.entity.read",
effect: "deny",
policies: [{
condition: { entity: "secrets" },
effect: "deny",
}],
},
],
},
},
}typescript
{
roles: {
user: {
implicit_allow: false,
permissions: [
// 可读取大多数实体
"data.entity.read",
// 但永远无法访问secrets实体
{
permission: "data.entity.read",
effect: "deny",
policies: [{
condition: { entity: "secrets" },
effect: "deny",
}],
},
],
},
},
}Create Helper Function
创建辅助函数
For complex role definitions:
typescript
// helpers/permissions.ts
type EntityPermission = "read" | "create" | "update" | "delete";
function entityPermissions(
entities: string[],
actions: EntityPermission[]
) {
const permMap: Record<EntityPermission, string> = {
read: "data.entity.read",
create: "data.entity.create",
update: "data.entity.update",
delete: "data.entity.delete",
};
return actions.map((action) => ({
permission: permMap[action],
effect: "allow" as const,
policies: [{
condition: { entity: { $in: entities } },
effect: "allow" as const,
}],
}));
}
// Usage
{
roles: {
blog_author: {
implicit_allow: false,
permissions: [
...entityPermissions(["posts", "comments"], ["read", "create", "update"]),
...entityPermissions(["categories", "tags"], ["read"]),
],
},
},
}针对复杂的角色定义:
typescript
// helpers/permissions.ts
type EntityPermission = "read" | "create" | "update" | "delete";
function entityPermissions(
entities: string[],
actions: EntityPermission[]
) {
const permMap: Record<EntityPermission, string> = {
read: "data.entity.read",
create: "data.entity.create",
update: "data.entity.update",
delete: "data.entity.delete",
};
return actions.map((action) => ({
permission: permMap[action],
effect: "allow" as const,
policies: [{
condition: { entity: { $in: entities } },
effect: "allow" as const,
}],
}));
}
// 使用示例
{
roles: {
blog_author: {
implicit_allow: false,
permissions: [
...entityPermissions(["posts", "comments"], ["read", "create", "update"]),
...entityPermissions(["categories", "tags"], ["read"]),
],
},
},
}Verification
验证方法
Test permission assignments:
1. Login as user with role:
bash
curl -X POST http://localhost:7654/api/auth/password/login \
-H "Content-Type: application/json" \
-d '{"email": "editor@example.com", "password": "password123"}'2. Test allowed permission:
bash
curl http://localhost:7654/api/data/posts \
-H "Authorization: Bearer <token>"测试权限分配效果:
1. 使用对应角色的用户登录:
bash
curl -X POST http://localhost:7654/api/auth/password/login \
-H "Content-Type: application/json" \
-d '{"email": "editor@example.com", "password": "password123"}'2. 测试允许的权限:
bash
curl http://localhost:7654/api/data/posts \
-H "Authorization: Bearer <token>"Should return 200 with data
应返回200状态码及数据
**3. Test denied permission:**
```bash
curl -X DELETE http://localhost:7654/api/data/posts/1 \
-H "Authorization: Bearer <token>"
**3. 测试拒绝的权限:**
```bash
curl -X DELETE http://localhost:7654/api/data/posts/1 \
-H "Authorization: Bearer <token>"Should return 403 Forbidden
应返回403禁止访问
**4. Test entity-specific permission:**
```bash
**4. 测试实体特定权限:**
```bashIf only posts/comments allowed:
如果仅允许访问文章/评论:
curl http://localhost:7654/api/data/users
-H "Authorization: Bearer <token>"
-H "Authorization: Bearer <token>"
curl http://localhost:7654/api/data/users
-H "Authorization: Bearer <token>"
-H "Authorization: Bearer <token>"
Should return 403 if users entity not in allowed list
若用户实体不在允许列表中,应返回403
undefinedundefinedCommon Pitfalls
常见问题
Permission Not Taking Effect
权限未生效
Problem: Changed permissions but old behavior persists
Fix: Restart server - role config is loaded at startup:
bash
undefined问题: 修改权限后,旧的行为仍然存在
解决方法: 重启服务器 - 角色配置在启动时加载:
bash
undefinedStop and restart
停止并重启
bknd run
undefinedbknd run
undefinedDeny Not Overriding
拒绝效果未生效
Problem: Deny effect not blocking access
Fix: Check policy condition - deny only applies when condition matches:
typescript
// WRONG - no condition, may not match
{ permission: "data.entity.delete", effect: "deny" }
// CORRECT - simple deny at permission level
{
permissions: [
"data.entity.read",
"data.entity.create",
// Don't include delete at all
],
}问题: 拒绝效果未阻止访问
解决方法: 检查策略条件 - 仅当条件匹配时拒绝才会生效:
typescript
// 错误示例 - 无条件,可能不匹配
{ permission: "data.entity.delete", effect: "deny" }
// 正确示例 - 在权限级别直接拒绝
{
permissions: [
"data.entity.read",
"data.entity.create",
// 完全不包含delete权限
],
}Entity Condition Not Matching
实体条件不匹配
Problem: Entity-specific permission not working
Fix: Verify entity name matches exactly:
typescript
// WRONG - entity name case matters
{ condition: { entity: "Posts" } }
// CORRECT - use exact entity name
{ condition: { entity: "posts" } }问题: 实体特定权限未生效
解决方法: 验证实体名称完全匹配:
typescript
// 错误示例 - 实体名称大小写敏感
{ condition: { entity: "Posts" } }
// 正确示例 - 使用精确的实体名称
{ condition: { entity: "posts" } }Multiple Policies Conflict
多个策略冲突
Problem: Confusing behavior with multiple policies
Fix: Understand evaluation order - first matching policy wins:
typescript
{
policies: [
// More specific first
{ condition: { entity: "secrets" }, effect: "deny" },
// General fallback last
{ effect: "allow" },
],
}问题: 多个策略导致行为混乱
解决方法: 理解策略评估顺序 - 第一个匹配的策略生效:
typescript
{
policies: [
// 更具体的策略放在前面
{ condition: { entity: "secrets" }, effect: "deny" },
// 通用回退策略放在最后
{ effect: "allow" },
],
}Variable Placeholder Not Resolving
变量占位符未解析
Problem: appearing literally in filter
@user.idFix: Variables only work in and fields:
filterconditiontypescript
// CORRECT usage
{
condition: { "@id": "@user.id" }, // Works
filter: { user_id: "@user.id" }, // Works
}问题: 在过滤规则中以字面量形式出现
@user.id解决方法: 变量仅在和字段中生效:
filterconditiontypescript
// 正确用法
{
condition: { "@id": "@user.id" }, // 生效
filter: { user_id: "@user.id" }, // 生效
}DOs and DON'Ts
注意事项
DO:
- Start with minimal permissions, add as needed
- Use operator for multiple entities
$in - Test each permission after adding
- Use descriptive policy descriptions
- Prefer explicit permissions over
implicit_allow
DON'T:
- Grant to non-admin roles (SQL injection risk)
data.raw.* - Use with deny policies (confusing)
implicit_allow: true - Forget to restart server after config changes
- Mix simple strings and extended format unnecessarily
- Over-complicate with too many nested policies
建议:
- 从最小权限开始,根据需要逐步添加
- 对多个实体使用运算符
$in - 添加权限后逐一测试
- 使用描述性的策略说明
- 优先使用明确的权限而非
implicit_allow
禁止:
- 为非管理员角色授予权限(存在SQL注入风险)
data.raw.* - 在使用拒绝策略时启用(易混淆)
implicit_allow: true - 修改配置后忘记重启服务器
- 不必要地混合使用简单字符串和扩展格式
- 使用过多嵌套策略导致过于复杂
Related Skills
相关技能
- bknd-create-role - Define new roles
- bknd-row-level-security - Filter data by user ownership
- bknd-protect-endpoint - Secure specific endpoints
- bknd-public-vs-auth - Configure public vs authenticated access
- bknd-setup-auth - Initialize authentication system
- bknd-create-role - 定义新角色
- bknd-row-level-security - 按用户所有权过滤数据
- bknd-protect-endpoint - 保护特定端点
- bknd-public-vs-auth - 配置公开与认证访问
- bknd-setup-auth - 初始化认证系统