db.createRole() 必须在 admin 数据库中执行,角色定义需显式指定资源范围与合法动作,继承内置角色时 db 字段不可省略,创建后须验证权限是否生效。

db.createRole() 必须在 admin 数据库中执行
自定义角色定义操作只能在 admin 数据库上下文中运行,哪怕你最终想让角色作用于 testdb 或其他业务库。直接在非 admin 库里调用 db.createRole() 会报错:not authorized on 。
常见错误是切到目标库后就立刻建角色,正确做法是:
- 先
use admin - 再执行
db.createRole(),并在roles字段中显式指定继承来源(如{ role: "read", db: "testdb" }) - 权限声明中的
resource字段可跨库,但角色本身注册位置必须是admin
权限粒度控制:resource 和 actions 要配对写准
MongoDB 的自定义角色不是“开箱即用”的模板,privileges 数组里每个对象都需同时满足两个条件:资源范围明确、动作合法。漏掉任一都会导致权限无效或命令拒绝。
比如只允许用户对 orders 集合执行 find 和 update,但禁止删除:
db.createRole({
role: "ordersReaderUpdater",
privileges: [{
resource: { db: "sales", collection: "orders" },
actions: ["find", "update"]
}],
roles: [] // 不继承其他角色
})
注意点:
-
collection: ""(空字符串)表示整个数据库,不是通配符;要覆盖所有集合,得写{ db: "sales", collection: "" } -
actions必须来自 MongoDB 允许的白名单,比如"drop"不能用于普通数据库角色,仅限admin库中定义的集群级角色 - 若想限制到某个字段更新(如只允许改
status),MongoDB 原生不支持字段级权限,需靠应用层或文档验证规则兜底
继承内置角色时,db 字段不能省略
很多人以为 { role: "readWrite", db: "testdb" } 可以简写成 { role: "readWrite" },实际会失败——MongoDB 要求所有继承角色都带明确的 db 值,否则报错:role field must be a string, and db field must be a string。
正确继承示例(在 admin 库中):
db.createRole({
role: "appWriter",
privileges: [],
roles: [
{ role: "readWrite", db: "appdb" },
{ role: "dbAdmin", db: "appdb" }
]
})
关键细节:
- 即使
readWrite是内置角色,也必须写全{ role: "...", db: "..." }结构 - 继承的角色
db值可以和当前角色所属库不同,但必须存在且已启用访问控制 - 如果继承了
userAdmin,它只赋予管理当前db下用户的权限,无法跨库删其他库的用户
创建后立即测试权限,别信“看起来成功了”
db.createRole() 返回成功不代表权限生效。常见陷阱是:角色创建成功,但没给用户分配,或用户认证时用了错误的 --authenticationDatabase。
验证步骤建议:
- 用新用户连接:
mongo -u appUser -p pwd --authenticationDatabase admin - 切换到目标库:
use appdb - 执行
db.orders.find().limit(1),看是否被拒绝;若拒绝,检查rolesInfo是否返回空特权列表 - 查角色定义:
db.runCommand({ rolesInfo: { role: "appWriter", db: "admin" } }),确认showPrivileges: true下有预期的actions
最容易被忽略的是:自定义角色默认不包含 listCollections 这类元数据操作权限,用户连 show collections 都会失败,得手动加进 privileges。











