MongoEngine连接MongoDB认证失败,PyMongo正常,如何解决?
我来帮你梳理下遇到的问题,其实核心是MongoEngine处理连接参数的逻辑和PyMongo有细微差别,咱们一步步解决:
一、为什么mongoengine.connect()会抛出command createRole requires authentication?
你用PyMongo的MongoClient直接传URI时,PyMongo会在连接阶段就完成指定数据库的认证;但当你用MongoEngine分开传db、username、password等参数时,默认情况下MongoEngine会先建立和服务器的连接,再尝试对指定的db进行认证。如果你的操作(比如创建角色)需要更高权限,而此时认证还没完成,就会抛出这个权限错误。
另外你注意到的read_preference=Primary()并不是问题根源,这只是MongoEngine默认的读取偏好设置,不会影响连接和认证能力。
二、为什么用URI方式会错误连接localhost?
这是一个参数传递的小坑:mongoengine.connect()的第一个位置参数是db,不是host!你直接把URI传给第一个参数,相当于把整个URI当作了数据库名,MongoEngine就会使用默认的localhost:27017作为连接地址,自然会连接失败。
三、正确的解决方案
方案1:正确使用URI连接(推荐)
把URI传给host参数,而不是位置参数:
user_admin_client = mongoengine.connect( host=f'mongodb://{usern}:{pswd}@x.x.x.x/my_db', alias='init' )
这样MongoEngine会正确解析URI中的主机地址、认证信息和目标数据库,和PyMongo的行为一致。
方案2:分开传参数时指定认证源
如果你的数据库用户是在admin库下创建的(这是MongoDB的常见场景),需要显式指定authentication_source参数,确保认证在正确的数据库上完成:
user_admin_client = mongoengine.connect( db='my_db', username=usern, password=pswd, host='x.x.x.x', authentication_source='admin', # 关键:指定认证用的数据库 alias='init' )
默认情况下MongoEngine会用你指定的db作为认证源,但如果用户是在admin库创建的,必须显式设置这个参数才能完成正确认证。
验证修改效果
修改后再次打印user_admin_client,你会看到MongoClient的host已经是你的远程IPx.x.x.x:27017,而不是localhost,同时执行需要权限的操作时也不会再抛出认证错误了。
内容的提问来源于stack exchange,提问作者Craig

