mongodb不支持原生集合级角色,需用db.createrole()自定义角色并精确指定{db:"mydb",collection:"orders"}及具体操作权限,再通过db.createuser()绑定;权限验证须换用户测试,注意大小写敏感、resource严格匹配、连接池权限缓存等问题。

创建用户时直接绑定集合级角色
MongoDB 不支持“只给某个集合读写权限”这种粒度的原生角色,但能通过 db.createRole() 自定义角色,再把角色赋给用户。关键不是靠用户创建时选内置角色,而是自己造一个只对特定集合生效的角色。
常见错误是直接用 read 或 readWrite 内置角色——它们作用于整个数据库,哪怕只给 mydb,用户也能读写 mydb.users、mydb.logs 所有集合。
- 先用管理员账号连进
admin数据库 - 运行
db.createRole(),在resources里精确指定{ db: "mydb", collection: "orders" } - 赋予
"actions": ["find", "insert", "update", "remove"]等具体动作(别偷懒写["*"]) - 再用
db.createUser(),把刚建的角色加进roles数组,且db字段必须填角色所在的数据库(通常是mydb)
验证权限是否真的被限制住了
权限配置完不验证,等于没配。最直接的方式是换用户登录,手动试几个典型操作,看是不是真拦住了。
容易踩的坑:用 mongo shell 连接时没带 --authenticationDatabase admin,导致认证失败或降级到无权限上下文;或者误以为 show collections 能列出所有集合——其实它只显示当前用户有 listCollections 权限的集合,而这个权限默认不包含在集合级角色里。
- 连接命令示例:
mongo --username order_user --password xxx --authenticationDatabase admin mydb - 执行
db.orders.find().limit(1)应该成功 - 执行
db.users.find().limit(1)应该报错:not authorized on mydb to execute command { find: "users", ... } - 执行
show collections可能只显示orders,也可能啥都不显示——这取决于你有没有单独授予listCollections
内置角色不够用?小心 resource 匹配规则
MongoDB 的 resource 匹配是严格字符串匹配,collection: "orders" 不会覆盖 orders_archived,也不会匹配正则或前缀。想管多个集合,得一个个列,或者用通配符角色(4.4+ 支持 collection: "*",但仅限于 read/readWrite 内置角色,自定义角色不认)。
另一个坑是数据库名大小写敏感,{ db: "MyDB", collection: "orders" } 和实际的 mydb 完全不匹配,权限直接失效。
- resource 必须写对大小写,建议全小写
- 如果要覆盖
orders_2023和orders_2024,只能分别声明两个 resource - 避免用
collection: ""(空字符串)——它不表示“所有集合”,而是匹配名为空的集合,基本不存在 - 测试时删掉旧角色再重建,因为
db.updateRole()不会自动刷新已登录用户的权限缓存
权限变更后连接池里的旧连接还有效吗
有效。MongoDB 的权限检查发生在每次命令执行时,不是连接建立时。所以改了角色、删了用户、甚至改了密码,只要连接没断,老连接还能继续干活——直到下一次发命令被服务器拒绝。
这意味着上线新权限策略后,不能指望“重启应用就生效”。如果应用用了长连接池(比如 Node.js 的 mongodb 驱动默认开启),得主动触发重连,或者等连接自然超时/断开。
- 驱动层通常提供
close()+connect()方式强制刷新 - 临时验证可以用
db.runCommand({ connectionStatus: 1 })查当前连接的认证信息 - 生产环境切权限前,最好先停写流量,避免权限更新中途出现部分请求成功、部分失败的混乱状态
集合级权限看着简单,但 resource 写错、大小写不一致、连接复用、角色未刷新——这几个点串起来,足够让权限策略静默失效好几天。动手前先在测试库跑通完整链路,比事后查日志快得多。










