name: bknd-create-role description: 用于在Bknd授权系统中定义新角色。涵盖角色属性(implicit_allow、is_default、permissions)、权限分配、角色层次结构以及常见角色模式(管理员、编辑者、查看者、匿名用户)。
创建角色
在Bknd的授权系统中定义新角色以控制用户访问。
先决条件
- Bknd项目已初始化,采用代码优先配置
- 已启用认证(
auth: { enabled: true }) - 已启用授权守卫(
guard: { enabled: true })
何时使用UI模式
- 查看现有角色
- 快速切换角色设置
UI步骤: 管理面板 > 认证 > 角色
注意: 角色创建需要代码模式。UI仅显示现有角色。
何时使用代码模式
- 创建新角色
- 设置角色权限
- 配置默认角色
- 设置角色层次结构
代码方法
步骤1:启用守卫
角色需要启用守卫系统:
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: {
// 在此定义角色
},
},
},
});
步骤2:定义基本角色
创建具有明确权限的角色:
{
auth: {
enabled: true,
guard: { enabled: true },
roles: {
viewer: {
implicit_allow: false, // 默认拒绝
permissions: [
"data.entity.read", // 仅授予读取权限
],
},
},
},
}
角色属性
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
implicit_allow |
布尔值 | false |
除非拒绝,否则允许所有操作 |
is_default |
布尔值 | false |
当用户无角色时使用 |
permissions |
数组 | [] |
授予角色的权限 |
步骤3:创建管理员角色(完全访问)
使用 implicit_allow 授予完全访问:
{
roles: {
admin: {
implicit_allow: true, // 可执行所有操作
},
},
}
警告: implicit_allow: true 授予所有权限。仅用于管理员角色。
步骤4:创建编辑者角色(部分访问)
授予特定CRUD权限:
{
roles: {
editor: {
implicit_allow: false,
permissions: [
"data.entity.read",
"data.entity.create",
"data.entity.update",
// 无删除权限
],
},
},
}
步骤5:创建默认角色
为未分配角色的用户设置角色:
{
roles: {
anonymous: {
is_default: true, // 当无角色时应用
implicit_allow: false,
permissions: [
"data.entity.read", // 只读访问
],
},
},
}
注意: 只能有一个角色设置 is_default: true。
步骤6:设置注册角色
为新注册用户分配角色:
{
auth: {
enabled: true,
default_role_register: "user", // 新注册用户的角色
roles: {
user: {
implicit_allow: false,
permissions: ["data.entity.read"],
},
},
},
}
可用权限
| 权限 | 描述 |
|---|---|
data.entity.read |
读取任何实体记录 |
data.entity.create |
在任何实体中创建记录 |
data.entity.update |
在任何实体中更新记录 |
data.entity.delete |
从任何实体删除记录 |
data.database.sync |
同步数据库架构 |
data.raw.query |
执行原始SELECT查询 |
data.raw.mutate |
执行原始INSERT/UPDATE/DELETE操作 |
常见角色模式
多层访问系统
{
auth: {
enabled: true,
guard: { enabled: true },
default_role_register: "user",
roles: {
// 完全访问
admin: {
implicit_allow: true,
},
// 内容管理
editor: {
implicit_allow: false,
permissions: [
"data.entity.read",
"data.entity.create",
"data.entity.update",
"data.entity.delete",
],
},
// 创建和读取
contributor: {
implicit_allow: false,
permissions: [
"data.entity.read",
"data.entity.create",
],
},
// 认证用户只读
user: {
implicit_allow: false,
permissions: [
"data.entity.read",
],
},
// 未认证/访客用户
anonymous: {
is_default: true,
implicit_allow: false,
permissions: [
"data.entity.read",
],
},
},
},
}
封闭系统(无公共访问)
{
auth: {
enabled: true,
guard: { enabled: true },
allow_register: false, // 禁用自注册
roles: {
admin: {
implicit_allow: true,
},
member: {
implicit_allow: false,
permissions: [
"data.entity.read",
"data.entity.create",
"data.entity.update",
],
},
// 无默认角色 - 未认证用户无访问权限
},
},
}
API消费者角色
{
roles: {
api_client: {
implicit_allow: false,
permissions: [
"data.entity.read",
"data.entity.create",
// 无更新/删除 - API客户端仅创建数据
],
},
},
}
权限效果
使用扩展格式设置允许/拒绝效果:
{
roles: {
moderator: {
implicit_allow: false,
permissions: [
{ permission: "data.entity.read", effect: "allow" },
{ permission: "data.entity.update", effect: "allow" },
{ permission: "data.entity.delete", effect: "deny" }, // 明确拒绝
],
},
},
}
角色分配
用户创建时分配(种子数据)
{
options: {
seed: async (ctx) => {
await ctx.app.module.auth.createUser({
email: "admin@example.com",
password: "secure-password",
role: "admin", // 分配管理员角色
});
},
},
}
注册时分配
{
auth: {
default_role_register: "user", // 所有注册用户获得“user”角色
},
}
更新用户角色(API)
const api = getApi(app);
// 更新用户角色
await api.data.updateOne("users", userId, {
role: "editor",
});
验证
测试角色权限:
1. 创建带角色的用户:
curl -X POST http://localhost:7654/api/auth/password/register \
-H "Content-Type: application/json" \
-d '{"email": "test@example.com", "password": "password123"}'
2. 登录并获取令牌:
curl -X POST http://localhost:7654/api/auth/password/login \
-H "Content-Type: application/json" \
-d '{"email": "test@example.com", "password": "password123"}'
3. 测试权限(读取应成功):
curl http://localhost:7654/api/data/posts \
-H "Authorization: Bearer <token>"
4. 测试被拒绝的权限(删除不允许时应失败):
curl -X DELETE http://localhost:7654/api/data/posts/1 \
-H "Authorization: Bearer <token>"
# 如果删除不在权限中,返回403
常见陷阱
无默认角色
问题: 未认证用户出现“用户无角色”错误
修复: 设置默认角色:
{
roles: {
anonymous: {
is_default: true,
permissions: ["data.entity.read"],
},
},
}
多个默认角色
问题: 多个 is_default: true 导致不可预测行为
修复: 只能有一个默认角色:
{
roles: {
user: { is_default: true }, // 只有一个!
guest: { /* 无 is_default */ },
},
}
角色未找到
问题: 分配时出现“角色‘admin’未找到”错误
修复: 在引用前定义角色:
{
auth: {
roles: {
admin: { implicit_allow: true }, // 先定义
},
default_role_register: "admin", // 然后引用
},
}
守卫未启用
问题: 定义了角色但权限未强制执行
修复: 启用守卫:
{
auth: {
enabled: true,
guard: { enabled: true }, // 必需!
roles: { /* ... */ },
},
}
隐式允许过度使用
问题: 在非管理员角色上使用 implicit_allow: true
修复: 明确指定权限:
// 错误 - 过于宽松
{
roles: {
editor: { implicit_allow: true },
},
}
// 正确 - 明确权限
{
roles: {
editor: {
implicit_allow: false,
permissions: [
"data.entity.read",
"data.entity.create",
"data.entity.update",
],
},
},
}
注意事项
应做:
- 使用角色时启用守卫
- 非管理员角色使用
implicit_allow: false - 为未认证访问设置一个默认角色
- 在引用前定义角色
- 创建后测试每个角色的权限
不应做:
- 非管理员角色使用
implicit_allow: true - 设置多个默认角色
- 忘记启用守卫
- 向不受信任角色授予
data.raw.*权限 - 假设未启用守卫时角色有效
相关技能
- bknd-setup-auth - 初始化认证系统
- bknd-assign-permissions - 配置详细权限和策略
- bknd-row-level-security - 实现行级访问控制
- bknd-protect-endpoint - 保护特定端点
- bknd-public-vs-auth - 配置公共与认证访问