authSource这几个字母,看着不起眼,位置也就挤在连接串末尾一堆参数中间,前后都是要写的东西。可偏偏就是它,能让一个密码完全正确的账号连着失败一整晚。MongoDB认证库authSource填错就连不上,这个坑我踩过不止一次,最气人的不是连不上,是报错永远只有一句 Authentication failed,不说密码错、不说库错、也不说认证机制不对,全靠自己猜。

MongoDB认证库authSource填错就连不上,报错却省得可怜
接手一个连不上的库,常规流程大家都熟:先把密码从头核一遍,怀疑有不可见字符,复制粘贴重输;再看看 bindIp 是不是只放了 127.0.0.1;接着翻安全组、白名单、端口有没有开;最后连防火墙策略都查了。等这一圈绕完,人才会想起来打开连接串,看末尾到底有没有这一小段参数。有个特别快的判断办法:同一个账号,mongosh 命令行能进,程序里怎么都连不上,那基本就是这个位置的问题,别再去折腾网络和密码了。
同事发来截图,说账号刚建的、权限也给了、密码绝对没错,我让他把连接串发过来,一眼就看见路径写的是业务库,末尾干干净净什么参数都没有。账号是建在 admin 里的,客户端就跑业务库找这个用户,那儿压根没有,回得来才怪。
认证库和业务库,本来就是两件事
拆开说就通了。authSource 管的是“去哪儿验身份”,URL 路径那一段管的是“登录之后默认进哪个库”。两个值在绝大多数时候能撞上,所以很多人从建库到上线都没注意过它,一换环境就翻车。超管账号建在 admin,authSource 就得是 admin;某个业务库自己建的应用账号如果就建在业务库里,写不写通常都能通,默认跟着路径走。
还有一种写法特别普遍,也特别容易只写一半:账号建在 admin,权限 grant 到业务库上。这种连法是路径写业务库、authSource 写 admin,两个值本来就不一样。有人在测试环境图省事只写了路径,跑得好好的,上了生产换了账号体系,立刻就不认了。
这几种情况,必须把authSource写死
超管账号算一种;账号在 admin、实际读写却不在 admin 算一种;副本集和分片集群里用 SCRAM 认证的多节点环境算一种,节点一多,几份配置文件里漏一段的概率直线上升;再有就是驱动大版本升级后,老代码突然连不上,默认行为不完全是同一套。拿不准的时候,显式写上永远比赌默认值靠谱。各个驱动对默认值到底怎么定义的,以官方文档或服务商页面说明为准,别照抄别人博客里的老参数。
连接串、命令行、框架里,写法都不一样
原生连接串长这样:mongodb://user:pass@host:27017/db?authSource=admin。要带多个参数就往后接,&authSource=admin&replicaSet=rs0 这种,注意这个 & 写在 YAML 或 XML 配置文件里要转义,不转义解析出来参数就断在半路,看着写了其实没生效。mongosh 命令行是另一个写法,–authenticationDatabase admin。Java 驱动里是 MongoCredential.createCredential(user, “admin”, pwd),第二个参数就是认证库,很多人顺手就把业务库名填进去了。Spring Boot 项目里是 spring.data.mongodb.authentication-database,或者干脆全塞进一个 uri 里。PHP 那套扩展走查询参数。写法五花八门,指向的是同一件事。
密码里的特殊字符,会伪装成认证问题
有些密码带着 @ : / ? # 这些字符,直接塞进连接串里必须做 URL 编码,不做的话整个串从那个字符开始就被解析错位,用户名和密码一起乱,表现和 authSource 填错几乎是同一个样子。所以排查的时候别只盯着认证库,顺便看一眼密码有没有编码过。还有一种情况要分清:认证过了但没有授权,报出来的错不一样,读业务库照样失败,那问题在角色和权限上,跟认证库没关系。
排查顺序,从最便宜的地方开始
我的习惯是先把成本最低的排掉。打开连接串,看有没有 authSource;有的话看它的值跟账号实际建在哪个库对不对得上;然后拿 mongosh 带上 –authenticationDatabase 手动试一次,能过就是应用配置的问题,过不了再往下查;接着让对方在库里跑一下 db.getUsers(),确认这个用户名到底挂在哪个库下面;最后才去怀疑网络、白名单和驱动版本。顺序反了,时间全浪费在跟防火墙较劲上。
收尾给几条可以直接对着改的:超管账号一律显式写 authSource=admin;账号建在 admin、数据在业务库的,路径写业务库、参数写 admin,两个位置都别省;换驱动、换环境、换配置文件格式之后,第一件事是把连接串里的参数逐个对一遍;密码带特殊字符的先编码再说。改完还是不行,就把连接串里的密码临时换成已知的简单密码测一次,能通就说明是编码问题,不是认证库的锅。
【版权声明】:本站内容若无意侵犯到您的权利,请及时与我们联系将尽快删除相关内容!