选择数据库后进行身份验证
Posted
技术标签:
【中文标题】选择数据库后进行身份验证【英文标题】:Authenticate After Picking the Database 【发布时间】:2018-04-25 12:01:26 【问题描述】:我的 MongoDB 服务器中有 3 个数据库。我正在使用 pymongo 用 Python3 编写一些脚本。
我想使用最新的版本和做法。一旦我打开客户端并选择数据库, pymongo.MongoClient.['mydatabase'].authenticate 的 API 将被弃用。 https://api.mongodb.com/python/current/api/pymongo/database.html
选择数据库之前的身份验证(在拨打客户端时)似乎不会向下流向数据库。不仅适用于 pymongo,还适用于我使用 mongo shell 时。所以我觉得这就是问题所在。
脚本.py
import pymongo
from pymongo import MongoClient
u = getUser() # function which prompts for username
p = getPassword() # getpass.getpass('Password')
uri = formatUri(u, p) # formats 'mongodb://%s:%s@%s'.format(user, password, host)
client = MongoClient(uri)
db = client['mydb']
col = db.mycollection
for doc in col.find():
print(doc)
我收到我没有获得数据库授权的错误。我知道我的帐户在 shell 中工作,但我必须先拨打客户端,然后使用数据库,然后再使用身份验证。
这是一个 mongo shell 示例:
$ mongo
MongoDB shell version: v3.4.10
Connecting to: mongodb://127.0.0.1:port
MongoDB server version: v3.4.10
> use mydb
switched to mydb
> db.auth("user", "pass")
1
知道如何在,或者在使用数据库后它会记住我拨打的上下文吗?
【问题讨论】:
其意图是所有身份验证都存储在"admin"
中,并简单地标识帐户具有可用权限的数据库命名空间。因此,您可以为"mydb"
的用户分配特权,但没有要求您单独“登录”该数据库。它只是意味着如果您切换到没有分配权限的"foo"
数据库命名空间,那么您“无法做任何事情”。如果您拥有“两个”数据库命名空间的权限,那么您就可以访问事物而无需再次“验证”。是不是更清楚一些?
我最初认为它是这样工作的。例如,在不使用数据库的情况下,我创建了具有 admin 中所有权限的 mongo 用户,具有几乎所有可能的访问权限,而另一个用户仅具有读取权限。然后我将使用该主帐户进行身份验证(仍在管理员中)。然后切换并使用“mydb”,当我在 mydb 中“显示用户”时,什么都没有显示。所以我想我必须在 mydb 中重新创建帐户并授予访问权限。
您认为提供的答案中是否有某些内容无法解决您的问题?如果是这样,那么请对答案发表评论,以澄清究竟需要解决哪些尚未解决的问题。如果它确实回答了您提出的问题,请注意Accept your Answers您提出的问题
确实如此。这对我来说很有意义,因为这是我第一次期望它工作的方式,并且我意识到我在同一个数据库中创建了单独的用户。但是,当我尝试在 admin
中创建新用户时,我仍然无法使用 d.auth() 登录我正在使用的数据库。 (此时我只使用 shell,因为我意识到问题从来不是 pymongo)。我相信我可能不得不重新安装 mongo 并开始清理,因为我一直在搞乱用户、配置等。
您将获得一个干净的案例,其中显示了干净的数据库的启动和可重现的步骤,以便您可以运行和复制并查看正确的过程是什么。一旦您可以看到正确的流程是什么并且答案解决了实际询问的内容,那么这里的流程就是"accept the answer",以便向查看问题及其答案的其他人表明它的正确性。
【参考方案1】:
您似乎在这里遗漏了一些概念,所以我基本上会作为您应该做什么的“指南”来回答。因此,“身份验证”实际上并不是您“在”连接后执行的操作,而是在您实际尝试进行身份验证时需要“在正确的地方寻找”。
我们可以通过基本上遵循核心文档中Enable Auth 中概述的过程来开始此操作,但需要进行特殊更改,因为您希望在自己的用户帐户和本地目录下运行此“测试”。
修订步骤 - 直接来自文档
所以首先会想要选择一个本地工作目录并为该目录下的数据库存储文件创建一个路径。在基于 *nix 的系统上,您可以执行以下操作:
mkdir -p scratch/data/db
cd scratch
然后我们想在没有任何其他选项的情况下启动一个单独的 MongoDB 实例。确保端口不与任何其他正在运行的实例冲突:
mongod --port 37017 --dbpath data/db
在新的终端或命令行窗口中,您可以连接到 shell:
mongo --port 37017
您总是希望至少有一个具有管理权限的帐户至少可以“创建帐户”并在遇到麻烦时对其进行更改,因此请创建一个:
use admin
db.createUser(
user: "admin",
pwd: "admin",
roles: [ role: "userAdminAnyDatabase", db: "admin" ]
)
现在退出 shell 并关闭在另一个终端或命令提示符下运行的现有 mongod
实例,然后使用 --auth
再次启动它:
mongod --auth --port 37017 --dbpath data/db
特定用户 - 确保您遵循这些
现在您实际上想要创建一个“由您的应用程序使用”的用户。因此,这些步骤对于确保您做对很重要。
使用您的“管理员用户”登录到 shell:
mongo -u admin -p admin --port 37017 --authenticationDatabase 'admin'
您可以交替执行问题中所示的db.auth()
方法,但如前所述,此必须在"admin"
命名空间上获得授权。
接下来要做的是创建一个可以访问"mydb"
的用户作为具有readWrite
角色的命名空间。为了好玩,我们还将让该用户拥有readAnyDatabase
,允许他们“列出”所有数据库命名空间,如果实际上不能对它们做任何其他事情。
重要提示:您在
"admin"
命名空间中创建所有用户。这在未来的版本中将非常重要:
use admin
db.createUser(
"user": "myuser",
"pwd": "password",
"roles": [
"role": "readWrite", "db": "mydb" ,
"readAnyDatabase"
]
)
只是为了额外的输出,我们来看看当前创建的用户:
db.getUsers()
[
"_id" : "admin.admin",
"user" : "admin",
"db" : "admin",
"roles" : [
"role" : "userAdminAnyDatabase",
"db" : "admin"
]
,
"_id" : "admin.myuser",
"user" : "myuser",
"db" : "admin",
"roles" : [
"role" : "readWrite",
"db" : "mydb"
,
"role" : "readAnyDatabase",
"db" : "admin"
]
]
看看这些在命名方面是如何扩展的,尤其是分配给每个用户的各种"db"
键的值。这应该让您更深入地了解 MongoDB 如何查找此内容以及原因。
Python 连接
最后我们只想从 python 连接。所以假设你已经安装了 python 和 pymongo,那么它只是一个简单的验证清单:
import pymongo
from pymongo import MongoClient
client = MongoClient('mongodb://myuser:password@localhost:37017');
db = client['mydb']
col = db.test
col.remove()
col.insert_one( "a": 1 )
for doc in col.find():
print(doc)
这表明创建和列出的文档没有问题:
u'a': 1, u'_id': ObjectId('5a08e5e0760108251722a737')
请注意,我们实际上不需要在此处提及"admin"
,因为这是驱动程序“期望帐户”以及您真正“应该”这样做的默认位置。
但我做错了
假设您最初很困惑并在"mydb"
下创建了用户:
use mydb
db.createUser( "user": "bert", "pwd": "password", "roles": ["readWrite"] )
如果您查看"admin"
,该用户不存在。但是如果你看"mydb"
:
use mydb
db.getUsers()
[
"_id" : "mydb.bert",
"user" : "bert",
"db" : "mydb",
"roles" : [
"role" : "readWrite",
"db" : "mydb"
]
]
因此您可以看到实际用户数据现在保存在哪里以及如何记录。
这里的简单情况是您“必须”告诉 MongoDB 从哪里获取该用户的身份验证:
client = MongoClient('mongodb://bert:password@localhost:37017/mydb');
看看我们如何将"mydb"
添加到连接字符串中。这就是它的完成方式。
这实际上是在“进行中”,以与所有驱动程序在连接方式、身份验证发生位置以及您选择数据库的位置保持一致。但有一些基本规则:
如果没有为其他数据库命名空间提供身份验证凭据的连接详细信息,则将"admin"
视为默认值。
如果连接字符串上提供了数据库命名空间,这将用于身份验证,这是连接字符串上数据库命名空间的实际意图。
尽管“目前”其他驱动程序在连接字符串上数据库命名空间的角色方面有所不同,但其用法正在更改为与所有驱动程序一致,即“使用”数据库命名空间实际上是一个 API 调用,而不是从连接字符串分配。
因此,您需要在哪里进行身份验证取决于“您创建用户的位置”。但是您确实应该注意到"admin"
是您“应该”执行此操作的地方,而不是其他任何地方。
连接后不推荐使用 Authenticate
虽然所有驱动程序实际上都具有与
authenticate()
类似的方法,其用法与问题中的 shell 示例非常相似,但该方法现在被视为已弃用,正如在整个内容中提到的那样回答“有意”将用户实际存储在"admin"
命名空间中:“在 3.5 版中更改:已弃用。验证多个用户与 MongoDB 3.6 中对逻辑会话的支持冲突。要作为多个用户进行验证,请创建多个 MongoClient 实例。”
这就是为什么这里的整个答案基于 不 使用该方法,因为您打算创建新的连接实例,或者使用 MongoDB 3.6 提供的“会话”功能。
【讨论】:
以上是关于选择数据库后进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章
使用 Firebase 身份验证进行身份验证后检索 Google 访问令牌
在依赖 Auth0 进行 Facebook 身份验证的应用程序中选择用户 ID?