3. 启用访问控制

MongoDB 默认安装后并不启用访问控制,任何能连到 27017 端口的客户端都可以直接读写数据库,这在生产环境中是不可接受的。启用访问控制包含三件必须按顺序完成的事:先创建管理员用户,再以认证模式重启实例,最后验证未认证连接被拒绝、认证连接可正常操作。顺序不能颠倒——如果先开启认证再创建用户,本地登录也会被拒绝,只能借助 localhost exception 补救。

一、理解 localhost exception 与创建用户的时机

MongoDB 提供了一条特殊规则:当实例启用了访问控制但还没有任何用户时,允许从本机(localhost)建立一条不受认证限制的连接,用于创建第一个用户。这条连接只能创建用户,不能执行其他数据操作,且一旦第一个用户创建成功,该例外立即失效。因此正确的做法是:先在未启用认证的状态下创建管理员,或者启用认证后利用 localhost exception 创建管理员。前者更直观,推荐初学者采用。

二、创建首个管理员用户

管理员用户应创建在 admin 数据库中,并授予 userAdminAnyDatabase 与 readWriteAnyDatabase(或更严格的 root)角色。userAdminAnyDatabase 负责管理用户与角色,readWriteAnyDatabase 负责跨库读写,二者组合足以完成日常运维。以下示例在未启用认证的实例上执行:

use admin

db.createUser({
  user: "adminUser",
  pwd: "Str0ng_P@ssw0rd!",
  roles: [
    { role: "userAdminAnyDatabase", db: "admin" },
    { role: "readWriteAnyDatabase", db: "admin" }
  ]
})

执行成功会返回 { ok: 1 }。此时用户已写入 admin.system.users 集合,但实例仍未要求认证,任何人都还能匿名连接。密码应满足复杂度要求,避免使用示例中的明文口令直接上线。

三、通过命令行开启认证

最直接的方式是在启动 mongod 时加上 --auth 参数。若实例正在运行,先正常关闭,再以认证模式启动:

mongod --dbpath /var/lib/mongodb --auth --port 27017 --bind_ip 127.0.0.1

启动后,未携带凭据的连接虽然能建立,但执行 show dbs、db.stats() 等命令会返回 Unauthorized 错误。这正是认证生效的直接信号。

四、通过配置文件开启认证

生产环境更推荐使用配置文件,便于集中管理端口、路径、日志与安全选项。编辑 /etc/mongod.conf:

storage:
  dbPath: /var/lib/mongodb
net:
  port: 27017
  bindIp: 127.0.0.1
security:
  authorization: enabled

关键字段是 security.authorization,取值 enabled 表示开启访问控制,disabled 表示关闭。修改后重启服务:

sudo systemctl restart mongod

命令行 --auth 与配置文件 authorization: enabled 等价,二者只需其一。若同时存在,以配置文件为准。使用配置文件的好处是重启后参数不会丢失,且可与副本集、TLS 等选项统一维护。

五、验证认证是否真正生效

验证要覆盖“拒绝”和“放行”两个方向,缺一不可。第一步,不认证直接连接并尝试操作:

mongosh --port 27017
> show dbs
MongoServerError: command listDatabases requires authentication

出现该错误说明匿名访问已被拦截。第二步,携带凭据登录并执行同样的命令:

mongosh --port 27017 -u adminUser -p 'Str0ng_P@ssw0rd!' --authenticationDatabase admin
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

能正常列出数据库,说明认证链路完整可用。也可以在已连接的会话中手动认证:

> use admin
> db.auth("adminUser", "Str0ng_P@ssw0rd!")
{ ok: 1 }

返回 { ok: 1 } 表示认证成功,返回 { ok: 0 } 则说明用户名、密码或认证库不匹配。注意 --authenticationDatabase 必须指向创建用户时所在的库,本例为 admin,否则会认证失败。

验证时建议同时检查 db.runCommand({connectionStatus: 1}) 的输出,其中 authenticatedUsers 会列出当前已认证用户,ok: 1 表示会话处于已认证状态,这是比单条命令更可靠的判断依据。

六、常见问题与排查

  • 开启认证后无法登录:确认用户创建在 admin 库,且登录时指定了 --authenticationDatabase admin。
  • 忘记管理员密码:可临时以 --noauth 启动,重置密码后再恢复认证模式,操作期间应限制网络访问。
  • 配置文件不生效:检查 YAML 缩进是否为两个空格,security 与 net 是否同级,重启后查看日志中是否加载了该配置。
  • localhost exception 失效:只要已存在任意用户,该例外就不再可用,必须使用已有凭据登录。
启用访问控制:配置路径与认证验证 ① 创建首个管理员 use admin db.createUser({ user:"adminUser", roles:[userAdminAnyDatabase, readWriteAnyDatabase] }) ② 开启认证(二选一) 命令行方式 mongod --auth 配置文件方式 security.authorization: enabled ③ 验证认证生效 未认证 → 应被拒绝 Unauthorized 已认证 → 应可操作 db.auth(...) → { ok: 1 } show dbs → 正常列出 认证连接判定:authenticationDatabase 与角色决定结果 mongosh 客户端 -u adminUser -p *** 认证库 --authenticationDatabase admin 认证成功 { ok: 1 } → 可读写授权库 认证失败 { ok: 0 } → 检查库/密码/角色 判断依据:connectionStatus.authenticatedUsers 非空且 ok=1,才说明会话已通过认证