ThinkPHP5.1 对接 MongoDB7.0 踩坑实录:认证失败 + Python 服务连接超时连环问题

4 阅读4分钟

前言

最近在做 Excel 数据入库 MongoDB 的功能,整套架构是 ThinkPHP5.1 作为业务入口,调用 Python 服务解析 Excel 并写入 Mongo。上线联调遇到两个连续的坑:先是 PHP 侧报 Mongo 认证失败,改完配置后,又出现 Python 服务连接 Mongo 超时。踩坑过程有一定代表性,记录下来供遇到同类问题的同学参考。

环境简述

  • MongoDB:7.0.43
  • PHP 框架:ThinkPHP5.1,使用官方 think-mongo 驱动
  • Python:pymongo 作为 Mongo 客户端
  • 架构:PHP 业务层调用独立 Python 服务完成 Excel 解析入库

问题一:ThinkPHP 报 Authentication failed 认证失败

报错现象

AuthenticationException in Connection.php line 308
Authentication failed.

直接提示 Mongo 认证失败。

排查过程

  1. 先登录 Mongo 服务器,使用mongosh手工测试账号登录,确认账号、密码本身无误。
  2. 查看用户定义:Mongo 用户创建在admin认证库,账号拥有业务库读写权限。
use admin
db.getUsers()

关键点:MongoDB 用户是绑定在认证库的。很多人新建用户时,在 admin 库创建账号,连接时却没有指定authSource=admin,就会认证报错。

  1. 配置坑:ThinkPHP5.1 的老版think-mongo驱动不识别配置顶层直接写的 authSource。 ❌ 错误写法(很多人会这么写,不生效)
'mongo' => [
    'type'        => '\think\mongo\Connection',
    'hostname'    => 'xxx.xxx.xxx',
    'database'    => '业务库名',
    'username'    => 'mongo账号',
    'password'    => '账号密码',
    'hostport'    => '27017',
    'authSource'  => 'admin', // 放在顶层,老驱动读取不到!
],

✅ 正确写法:把认证参数放到params数组内

'mongo' => [
    'type'           => '\think\mongo\Connection',
    'query'          => '\think\mongo\Query',
    'hostname'       => '远程Mongo域名',
    'database'       => '业务库名',
    'username'       => 'mongo账号',
    'password'       => '账号密码',
    'hostport'       => '27017',
    'params' => [
        'authSource' => 'admin'
    ],
],
  1. 修改完成后,必须重启 php-fpm,PHP 配置存在缓存,不重启配置不生效。重启后 PHP 侧认证报错解决。

补充:Mongo7.0 默认使用 SCRAM-SHA-256 认证机制。如果后续还遇到认证异常,可以在 params 追加认证机制参数:

'params' => [
    'authSource' => 'admin',
    'authMechanism' => 'SCRAM-SHA-256'
],

问题二:PHP 侧修复后,Python 服务抛出连接超时

报错现象

调用导入接口返回 500,底层 Python 日志:

pymongo.errors.ServerSelectionTimeoutError: 127.0.0.1:27017

问题定位

这个坑很容易被忽略:ThinkPHP 只是 HTTP 调用方,500 错误根源在 Python 后端。 Python 代码里面 Mongo 连接地址硬编码写死了127.0.0.1:27017,尝试访问 Python 服务器本机的 Mongo。 但是 Python 服务器并没有部署 Mongo 实例,本地端口没有服务,直接连接超时。

修复方案

修改 pymongo 连接串,指向远程 Mongo 实例,并且带上认证参数。 Mongo 连接 URI 模板:

mongodb://账号:密码@Mongo域名:27017/业务库?authSource=admin

Python 示例代码:

from pymongo import MongoClient

# 远程Mongo连接串,指定认证库
client = MongoClient("mongodb://账号:密码@Mongo域名:27017/业务库?authSource=admin")
db = client["业务库名"]

修改代码后,重启 Python 服务进程(uwsgi/gunicorn 等) 。

上线前网络校验

在 Python 服务器上,先测试端口连通性,确认网络策略放行 27017 端口:

nc -zv Mongo域名 27017

完整验证流程

  1. 调用 Excel 导入接口,传递文件地址参数;
  2. 观察 Python 服务日志,确认成功建立 Mongo 连接;
  3. 进入 Mongo 业务库,校验集合内数据是否正常写入。

踩坑总结

  1. MongoDB 认证核心规则:用户在哪一个库创建,authSource 就必须指定为哪个库,宝塔 / 云数据库默认在 admin 创建账号,极易踩坑。
  2. ThinkPHP5.1 think-mongo 老驱动限制:authSource不能写在配置顶层,必须放到params数组,这个属于框架扩展的隐藏坑。
  3. 多服务架构联调,遇到接口 500,不要只看入口服务日志,要顺着调用链路,查看下游服务内部报错。本次一开始误判问题在 PHP,实际故障卡点在 Python 硬编码地址。
  4. 数据库连接信息不要硬编码写死在业务代码,推荐放到环境变量或者独立配置文件,方便多环境切换,同时降低信息泄露风险。

优化建议

  1. 安全层面:Mongo 安全组不要全开,只放行业务服务器的 IP 访问 27017 端口,缩小攻击面。
  2. 日志增强:Python 增加 Mongo 连接异常的详细日志,快速定位网络、认证类故障。
  3. 驱动版本:Mongo7.0 属于较新版本,PHP/Python 的 Mongo 客户端驱动尽量保持新版本,规避 SCRAM 认证兼容问题。

本文记录项目实战踩坑,希望帮你避开同样的坑。如果对你有帮助,欢迎点赞收藏,有问题评论区交流。