当前位置:首页 > 问答 > 正文

教你用熟悉的MySQL思路慢慢摸索MongoDB里的权限那些事儿

(引用来源:MongoDB官方文档、MySQL DBA的常见类比思路)

很多从MySQL转过来的朋友,一提到MongoDB的权限,头就大了,MySQL里多简单啊,GRANT SELECT ON database.* TO 'user'@'host'; 一句搞定,清晰明了,但到了MongoDB,看到readWritedbAdmin,还有什么clusterManager,直接就懵了,感觉像在学一门新外语。

别急,我们今天就用你熟悉的MySQL思路,来慢慢捋一捋MongoDB里的权限那些事儿,你会发现,核心思想是相通的,只是表达方式不一样。

第一步:先找到“服务器”和“数据库”

在MySQL里,你首先得连接到MySQL服务器实例,然后才能操作里面的各个数据库(比如db1, db2),MongoDB也一样,你得先连接到MongoDB服务实例(一个mongodmongos进程)。

最大的一个区别来了:MySQL的权限,用户是和“从哪个IP来”('user'@'host')强绑定的,MongoDB没这个概念,它只认用户名和密码,认证是在整个服务层面完成的,用户信息存在哪个数据库里,我们待会儿再说。

第二步:理解“权限”的核心:谁,在什么地方,能做什么

这和MySQL一模一样,任何权限系统的三要素都是:

  • 谁(Who):用户。
  • 在什么地方(Where):权限的作用范围,在MySQL里是数据库和表,在MongoDB里是数据库、集合(Collection,相当于表)、甚至是集群。
  • 能做什么(What):具体的操作权限,比如SELECT、INSERT。

我们就从这三点,用MySQL的思维去类比。

“谁”的存储位置:从mysql.user到admin数据库

在MySQL里,用户账户信息存在mysql.user这个系统表里,不管你当前在用哪个数据库,SELECT * FROM mysql.user;都能看到所有用户。

MongoDB里,也有一个类似的核心地方,叫做admin数据库,你可以把它想象成MongoDB的“mysql数据库”。所有用户,不管他最终权限是管理哪个数据库的,其账户信息都存储在admin数据库下(具体是在admin.system.users这个集合里),这是和MySQL非常不同的一个关键点,当你创建一个用户时,你必须先切换到admin数据库(use admin),然后再创建。

“在什么地方”:从Database到“资源”(Resource)

MySQL的权限作用域很清晰:全局()、某个数据库(db_name.*)、某张表(db_name.table_name)。

MongoDB更灵活一点,它把权限的作用范围叫做“资源”(Resource),最常见的资源就是数据库,你给一个用户db1数据库的读权限,他就能读db1里的所有集合(相当于MySQL里db1.*的SELECT权限)。

但它还可以更细,比如指定到某个具体的集合(db1.collection1),或者更广,比如整个集群(cluster)的资源,对于刚入门的我们,先记住“数据库”这个级别就够了,这已经能覆盖80%的场景。

“能做什么”:从Privilege到Role(角色)——这是关键!

在MySQL里,你直接给用户赋权(Privilege),比如GRANT SELECT, INSERT, UPDATE ...

MongoDB不推荐直接给用户赋权,而是引入了一个“角色”(Role)的概念,这就像公司里不直接定义“张三可以报销1000元”,而是定义了一个“部门经理”的角色,这个角色天然拥有“审批1000元以内报销”的权限,然后把张三赋予“部门经理”的角色。

MongoDB内置了很多常用的角色,对应MySQL里的各种权限:

  • read:相当于MySQL的SELECT,只能查数据,不能改。
  • readWrite:相当于MySQL的SELECT, INSERT, UPDATE, DELETE,最常用的应用账号角色。
  • dbAdmin:相当于MySQL里对某个数据库的CREATE TABLE, INDEX等DDL操作权限,注意,它不能读用户数据,只能管理数据库结构(集合、索引等),这和MySQL的db_owner有点像但又不完全一样。
  • dbOwner:这个角色厉害了,它结合了readWritedbAdmin,还多了一些权限,相当于对这个数据库有完全控制权,类似于MySQL里对一个数据库拥有所有权限。
  • userAdmin:这个角色是管理当前数据库的用户的,注意!它只能管理用户,没有读写的权限,这有点像MySQL里对你授予了mysql数据库下user表的部分管理权,但只限于某个数据库关联的用户。

超级用户在哪里?

MySQL里有GRANT ALL PRIVILEGES ON *.* TO 'superuser' ...

MongoDB里,对应的超级用户角色有两个,都必须在admin数据库下授予

  • userAdminAnyDatabase:管理所有数据库的用户,这是“用户的超级管理员”,但自己不一定有读写数据的权限。
  • dbAdminAnyDatabase:管理所有数据库的结构。
  • readWriteAnyDatabase:读写所有数据库的数据。
  • root这才是真正的超级管理员,它包含了上面所有权限,相当于MySQL的ALL PRIVILEGES,我们一般就用这个。

来,动手类比一下

假设我们在MySQL里要干两件事:

  1. 创建一个应用账号app_user,让它对app_db数据库有完全的读写权限。
  2. 创建一个管理员账号dba_user,让它能管理整个MySQL实例。
  • MySQL做法:

    -- 1. 创建应用账号
    CREATE USER 'app_user'@'%' IDENTIFIED BY 'password';
    GRANT ALL PRIVILEGES ON app_db.* TO 'app_user'@'%';
    -- 2. 创建DBA账号
    CREATE USER 'dba_user'@'localhost' IDENTIFIED BY 'password';
    GRANT ALL PRIVILEGES ON *.* TO 'dba_user'@'localhost' WITH GRANT OPTION;
  • MongoDB做法:

    // 用最高权限账号(比如刚启动时没有--auth的账号)连接到MongoDB
    // 切换到admin数据库,因为用户信息都存在这里
    use admin
    // 1. 创建应用账号,作用域在app_db数据库,角色是dbOwner(拥有该数据库所有权限)
    db.createUser({
      user: "app_user",
      pwd: "password",
      roles: [ { role: "dbOwner", db: "app_db" } ] // 注意这里,角色和数据库是分开指定的
    })
    // 2. 创建DBA账号,作用域是整个集群(在admin数据库下授予root角色)
    db.createUser({
      user: "dba_user",
      pwd: "password",
      roles: [ "root" ] // 在admin库下给root角色,就是超级管理员
    })

看到区别了吗?MongoDB创建用户时,需要明确指定这个角色的生效数据库app_userdbOwner角色是生效于app_db的,而dba_userroot角色是内置的全局角色,不需要指定db。

帮你记忆:

  1. 用户老家在admin:别管用户管哪个库,创建和管理用户时,先use admin
  2. 权限打包成角色:别想一个个权限,先找MongoDB内置的角色(readWrite, dbAdmin, dbOwner),它们就是为你熟悉的MySQL权限场景准备好的“套餐”。
  3. 授权时指明地盘:给用户角色时,一定要说清楚这个角色是在哪个数据库上生效的{role: "readWrite", db: "your_db"})。

先用这个思路去理解,你会发现MongoDB的权限没那么神秘了,更复杂的自定义角色、集群权限,都是在这些基础概念上扩展的,先把这些基础吃透,就能解决大部分日常权限管理问题了。

教你用熟悉的MySQL思路慢慢摸索MongoDB里的权限那些事儿