MongoDB内置角色权限过宽,不支持集合级细粒度控制;必须通过admin库中createRole定义精确到集合+动作的自定义角色,显式声明resource和actions,且无法继承内置角色权限。

内置角色太粗,readWrite 会放行所有集合操作
当你给应用用户只配 readWrite,它就能对 system.* 集合执行 find,甚至删掉 users 或 roles 这类元数据集合——这不是权限不足,是权限过宽。内置角色按“数据库粒度”划分,不支持“仅允许读 orders、写 logs、禁止碰 system.indexes”这种组合。
常见错误现象:db.getCollectionNames() 返回一堆系统集合,但用户本不该看到;或者应用误调用 db.runCommand({ dropDatabase: 1 }) 被静默放行(取决于是否在 admin 库授权)。
- 所有内置角色都不限制具体集合的
actions组合,比如不能只开find+aggregate,关掉count和distinct -
readAnyDatabase这类跨库角色更危险,一旦泄露,等于交出整个集群的只读钥匙 - 无法排除特定资源:比如允许所有集合读,但显式拒绝
config和local库
用 createRole 定义精确到集合+动作的权限
自定义角色必须在 admin 数据库中创建,否则无法跨库引用;权限声明里每个 privilege 必须带完整 resource 描述,不能省略 db 或留空。
实操建议:
- 先用
db.runCommand({ connectionStatus: 1 })确认当前连接身份和已生效角色,避免在错误数据库下执行createRole - 资源对象必须写全:
{ db: "appDB", collection: "orders" }才有效;{ db: "appDB", collection: "" }不代表“所有集合”,而是匹配空集合名,基本无用 - 动作列表要显式枚举:
["find", "insert", "update"],别写["*"]—— MongoDB 不支持通配符动作 - 示例:只允许聚合销售数据,且只能查客户基础信息
use admin
db.createRole({
role: "salesAnalyst",
privileges: [
{ resource: { db: "appDB", collection: "orders" }, actions: ["find", "aggregate"] },
{ resource: { db: "appDB", collection: "customers" }, actions: ["find"] }
],
roles: [] // 不继承其他角色
})
grantRolesToUser 后权限不生效的典型原因
执行完 db.grantRolesToUser("userA", [{ role: "salesAnalyst", db: "admin" }]) 却仍被拒,问题往往不在角色定义本身。
- 用户是在
appDB创建的,但角色是在admin创建的,授权时db:字段必须填"admin",不能填"appDB" - 客户端连接未指定
--authenticationDatabase admin,导致认证走错库,权限上下文丢失 - 用户已有冲突角色:比如同时拥有
readWrite(允许删集合)和你刚授的salesAnalyst(禁止删),MongoDB 按“并集”合并权限,删操作依然可用 - 没重启连接:已有 shell 会话缓存旧权限,必须重新
mongosh连接或执行db.logout()再db.auth()
自定义角色无法继承内置角色?这是设计使然
MongoDB 的角色继承只发生在同级角色之间,createRole 定义的角色不能自动获得 dbAdmin 的 listCollections 权限——即使你在 roles 数组里写了 { role: "dbAdmin", db: "appDB" },也只会在创建时校验该角色是否存在,不会把它的权限“展开合并”进你的新角色。
这意味着:
- 如果需要
listCollections,必须手动加一条 privilege:{ resource: { db: "appDB", collection: "" }, actions: ["listCollections"] }(注意 collection 为空字符串) -
dbOwner包含的dropCollection、createIndex等权限,也得逐条列进自定义角色,不能靠继承偷懒 - 最易忽略的点:
system集合操作(如system.users)需要单独授权,内置角色默认不开放这些路径


















