MongoDB使用者和身份驗證
MongoDB是一個介於關係資料庫和非關係資料庫之間的產品,是非關係資料庫當中功能最豐富,最像關係資料庫的。這裡推薦一個快速入門教程 - 8天學通 MongoDB,寫的很全面。這裡討論的是 MongoDB 的使用者和身份驗證。
在預設情況下,MongoDB 不會進行身份驗證,也沒有賬號,只要能連線上服務就可以對資料庫進行各種操作,如果你在一個面向公眾的伺服器上使用它,那麼這的確是一個問題。
作為資料庫軟體,我們肯定不想誰都可以訪問,為了確保資料的安全,MongoDB 也會像其他的資料庫軟體一樣可以採用使用者驗證的方法,那麼該怎麼做呢?其實很簡單,MongoDB 提供了 addUser 方法,該方法包含三個引數:
-
user - 字串,表示使用者名稱
-
password - 字串,對應的密碼
-
readOnly - boolean,可選引數,預設值為
false
,表示是否是隻讀使用者
新增使用者:db.addUser("guest", "pass", true)
修改使用者密碼: db.addUser("guest", "newpass")
刪除使用者: db.removeUser("guest")
更復雜的使用方式請參考官方文件。
可以將 MongoDB 的使用者分為兩類:超級使用者和資料庫使用者。超級使用者擁有最大許可權,可以對所有資料庫進行任意操作,超級使用者儲存在 admin 資料庫中,剛安裝的 MongoDB 中 admin 資料庫是空的;資料庫使用者儲存在單個數據庫中,只能訪問對應的資料庫。另外,使用者資訊儲存在 db.system.users 中。
關於使用者和許可權有以下特性:
- 資料庫是由超級使用者來建立的,一個數據庫可以包含多個使用者,一個使用者只能在一個數據庫下,不同資料庫中的使用者可以同名
- 如果在 admin 資料庫中不存在使用者,即使 mongod 啟動時添加了 –auth 引數,此時不進行任何認證還是可以做任何操作
- 在 admin 資料庫建立的使用者具有超級許可權,可以對 MongoDB 系統內的任何資料庫的資料物件進行操作
- 特定資料庫比如 test1 下的使用者 test_user1,不能夠訪問其他資料庫 test2,但是可以訪問本資料庫下其他使用者建立的資料
- 不同資料庫中同名的使用者不能夠登入其他資料庫。比如資料庫 test1 和 test2 都有使用者 test_user,以 test_user 登入 test1 後,不能夠登入到 test2 進行資料庫操作
實驗驗證
開始之前,說明以下我的檔案目錄結構:
─mongodb-2.4.8
├─bin // MongoDB 的二進位制檔案
├─data // MongoDB 資料庫存放目錄
└─log // MongoDB 日誌存放目錄
以普通的方式啟動 MongoDB首次安裝 MongoDB 後,admin 資料庫中沒有使用者,此時不管是否以 –auth 方式啟動資料庫,其他資料庫(比如 test1 資料庫)中的使用者都可以對另外的資料庫(比如 test2 資料庫)中的資料進行操作。
D:\MongoDB\mongodb-2.4.8>.\bin\mongod --dbpath=.\data --logpath=.\log\log.log
開啟另一個命令提示符視窗,進入 MongoDB Shell,預設直接連線 test 資料庫,並且此時使用者擁有超級許可權,可以操作任何資料庫物件。
D:\MongoDB\mongodb-2.4.8\bin>mongo
MongoDB shell version: 2.4.8
connecting to: test
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
http://docs.mongodb.org/
Questions? Try the support group
http://groups.google.com/group/mongodb-user
顯示所有資料庫,預設只有 local 資料庫。
> show dbs
local 0.078125GB
檢視 admin 資料庫中的使用者資訊,因為是剛建立的資料庫所以 user 為空
> use admin
switched to db admin
> db.system.users.find(); # 預設 admin 資料庫中不存在使用者
操作 test 資料庫,插入測試資料,並建立使用者 test_user,密碼為 password
> use test
switched to db test
> db.system.users.find(); # 預設 test 資料庫中也不存在使用者
> db.test_data.insert({"id":1,"info":"I am in test"})
> db.test_data.insert({"id":2,"info":"I am in test"})
> db.test_data.insert({"id":3,"info":"I am in test"})
> db.test_data.find()
{ "_id" : ObjectId("52f5922125d9e18cd51581b6"), "id" : 1, "info" : "I am in test" }
{ "_id" : ObjectId("52f5926d25d9e18cd51581b7"), "id" : 2, "info" : "I am in test" }
{ "_id" : ObjectId("52f5927125d9e18cd51581b8"), "id" : 3, "info" : "I am in test" }
# 建立使用者
> db.addUser("test_user","password")
{
"user" : "test_user",
"readOnly" : false,
"pwd" : "bf7a0adf9822a3379d6dfb1ebd38b92e",
"_id" : ObjectId("52f5928625d9e18cd51581b9")
}
> db.system.users.find()
{ "_id" : ObjectId("52f5928625d9e18cd51581b9"), "user" : "test_user", "readOnly" : false,
pwd" : "bf7a0adf9822a3379d6dfb1ebd38b92e" }
# 驗證函式,驗證資料庫中是否存在對應的使用者
> db.auth("test_user","password")
1
建立 test1 資料庫,並建立物件 test1_data,插入資料:
> use test1
switched to db test1
> db.test1_data.insert({"id":1,"info":"I am in test1"})
> db.test1_data.insert({"id":2,"info":"I am in test1"})
> db.test1_data.insert({"id":3,"info":"I am in test1"})
> db.test1_data.find()
{ "_id" : ObjectId("52f593e925d9e18cd51581ba"), "id" : 1, "info" : "I am in test1" }
{ "_id" : ObjectId("52f593ef25d9e18cd51581bb"), "id" : 2, "info" : "I am in test1" }
{ "_id" : ObjectId("52f593f425d9e18cd51581bc"), "id" : 3, "info" : "I am in test1" }
建立 test2 資料庫,並建立物件 test2_data,插入資料:
> use test2
switched to db test2
> db.test2_data.insert({"id":1,"info":"I am in test2"})
> db.test2_data.insert({"id":2,"info":"I am in test2"})
> db.test2_data.insert({"id":3,"info":"I am in test2"})
> db.test2_data.find()
{ "_id" : ObjectId("52f5947725d9e18cd51581bd"), "id" : 1, "info" : "I am in test2" }
{ "_id" : ObjectId("52f5947c25d9e18cd51581be"), "id" : 2, "info" : "I am in test2" }
{ "_id" : ObjectId("52f5948125d9e18cd51581bf"), "id" : 3, "info" : "I am in test2" }
重新以認證的方式啟動資料庫,啟動時新增 –auth 引數:
D:\MongoDB\mongodb-2.4.8>.\bin\mongod --dbpath=.\data --logpath=.\log\log.log --auth
再次登入,雖然在 test 中建立了使用者,但是沒有在 admin 資料庫中建立使用者,所以以預設方式登入的使用者依然具有超級許可權。
D:\MongoDB\mongodb-2.4.8\bin>mongo
MongoDB shell version: 2.4.8
connecting to: test
預設具有超級許可權,可以進行所有操作。
> show dbs
admin (empty)
local 0.078125GB
test 0.203125GB
test1 0.203125GB
test2 0.203125GB
> use test
switched to db test
> db.system.users.find()
{ "_id" : ObjectId("52f5928625d9e18cd51581b9"), "user" : "test_user", "readOnly"
: false, "pwd" : "bf7a0adf9822a3379d6dfb1ebd38b92e" }
> use test1
switched to db test1
> db.test1_data.find()
{ "_id" : ObjectId("52f593e925d9e18cd51581ba"), "id" : 1, "info" : "I am in test1" }
{ "_id" : ObjectId("52f593ef25d9e18cd51581bb"), "id" : 2, "info" : "I am in test1" }
{ "_id" : ObjectId("52f593f425d9e18cd51581bc"), "id" : 3, "info" : "I am in test1" }
# 插入資料
> db.test1_data.insert({"id":4,"info":"I am in test1"})
> db.test1_data.find()
{ "_id" : ObjectId("52f593e925d9e18cd51581ba"), "id" : 1, "info" : "I am in test1" }
{ "_id" : ObjectId("52f593ef25d9e18cd51581bb"), "id" : 2, "info" : "I am in test1" }
{ "_id" : ObjectId("52f593f425d9e18cd51581bc"), "id" : 3, "info" : "I am in test1" }
{ "_id" : ObjectId("52f5ae44bee8a41e4b495370"), "id" : 4, "info" : "I am in test1" }
# 建立資料庫 test3,並插入資料
> use test3
switched to db test3
> db.test3_data.insert({"id":1,"info":"I am in test3"})
> db.test3_data.insert({"id":2,"info":"I am in test3"})
> db.test3_data.insert({"id":3,"info":"I am in test3"})
> db.test3_data.find()
{ "_id" : ObjectId("52f5aee9bee8a41e4b495371"), "id" : 1, "info" : "I am in test3" }
{ "_id" : ObjectId("52f5af28bee8a41e4b495372"), "id" : 2, "info" : "I am in test3" }
{ "_id" : ObjectId("52f5af2cbee8a41e4b495373"), "id" : 3, "info" : "I am in test3" }
使用特定使用者登入資料庫,也可以訪問其他的資料庫。下面的例子中,使用 test 資料庫中的使用者 test_user 登入,但是由於 admin 資料庫中不存在使用者,所以任然具有超級許可權。
D:\MongoDB\mongodb-2.4.8\bin>mongo -utest_user -ppassword
MongoDB shell version: 2.4.8
connecting to: test
> show dbs
admin (empty)
local 0.078125GB
test 0.203125GB
test1 0.203125GB
test2 0.203125GB
test3 0.203125GB
> use test
switched to db test
> db.test_data.find()
{ "_id" : ObjectId("52f5922125d9e18cd51581b6"), "id" : 1, "info" : "I am in test" }
{ "_id" : ObjectId("52f5926d25d9e18cd51581b7"), "id" : 2, "info" : "I am in test" }
{ "_id" : ObjectId("52f5927125d9e18cd51581b8"), "id" : 3, "info" : "I am in test" }
> use test4
switched to db test4
> db.test4_data.insert({"id":1,"info":"I am in test4"})
> db.test4_data.insert({"id":2,"info":"I am in test4"})
> db.test4_data.insert({"id":3,"info":"I am in test4"})
> db.test4_data.find()
{ "_id" : ObjectId("52f5bce439a90d49d27742d2"), "id" : 1, "info" : "I am in test4" }
{ "_id" : ObjectId("52f5bce839a90d49d27742d3"), "id" : 2, "info" : "I am in test4" }
{ "_id" : ObjectId("52f5bcec39a90d49d27742d4"), "id" : 3, "info" : "I am in test4" }
在 admin.system.users 中新增使用者,使 MongoDB 的認證授權服務生效。
# 在 admin 資料庫中建立使用者 supper,密碼為 password
> use admin
switched to db admin
> db.addUser("supper","password")
{
"user" : "supper",
"readOnly" : false,
"pwd" : "0d345bf64f4c1e8bc3e3bbb04c46b4d3",
"_id" : ObjectId("52f5bdf439a90d49d27742d5")
}
# 認證
> db.auth("supper","password")
1
>
以預設方式登入,即以無認證使用者登入,查詢的時候會顯示無許可權:
D:\MongoDB\mongodb-2.4.8\bin>mongo
MongoDB shell version: 2.4.8
connecting to: test
> db.system.users.find()
error: { "$err" : "not authorized for query on test.system.users", "code" : 16550 }
> show dbs
Sat Feb 08 13:20:27.831 listDatabases failed:{ "ok" : 0, "errmsg" : "unauthorized" } at src/mongo/shell/mongo.js:46
在 admin 資料庫建立使用者後,使用認證方式登入,可進行對應資料庫的查詢操作且僅僅能夠查詢對應的資料庫中的資訊,不能夠查詢其他 MongoDB 系統的其他資料庫資訊:
# 使用 test 資料庫中的使用者可以查詢 test 的資料,但是不能檢視其他的資料庫的資料
D:\MongoDB\mongodb-2.4.8\bin>mongo -utest_user -ppassword
MongoDB shell version: 2.4.8
connecting to: test
> db.system.users.find()
{ "_id" : ObjectId("52f5928625d9e18cd51581b9"), "user" : "test_user", "readOnly"
: false, "pwd" : "bf7a0adf9822a3379d6dfb1ebd38b92e" }
> db.test_data.find()
{ "_id" : ObjectId("52f5922125d9e18cd51581b6"), "id" : 1, "info" : "I am in test" }
{ "_id" : ObjectId("52f5926d25d9e18cd51581b7"), "id" : 2, "info" : "I am in test" }
{ "_id" : ObjectId("52f5927125d9e18cd51581b8"), "id" : 3, "info" : "I am in test" }
# 查詢系統資料庫資訊,報錯
> show dbs
Sat Feb 08 13:23:03.423 listDatabases failed:{ "ok" : 0, "errmsg" : "unauthorized" } at src/mongo/shell/mongo.js:46
# 查詢 test1 資料庫,報錯
> use test1
switched to db test1
> db.test1_data.find()
error: { "$err" : "not authorized for query on test1.test1_data", "code" : 16550 }
# 查詢 test2 資料庫,報錯
> use test2
switched to db test2
> db.test2_data.find()
error: { "$err" : "not authorized for query on test2.test2_data", "code" : 16550 }
使用 supper 使用者登入,可以對 MongoDB 系統內的所有資料庫進行操作:
D:\MongoDB\mongodb-2.4.8\bin>mongo 127.0.0.1/admin -usupper -ppassword
MongoDB shell version: 2.4.8
connecting to: 127.0.0.1/admin
> show dbs
admin 0.203125GB
local 0.078125GB
test 0.203125GB
test1 0.203125GB
test2 0.203125GB
test3 0.203125GB
test4 0.203125GB
> use test
switched to db test
> db.addUser("test_user1","password")
{
"user" : "test_user1",
"readOnly" : false,
"pwd" : "af20fbd43eb73735b7fc7271f0d18ce4",
"_id" : ObjectId("52f5c0c01caaf8492f79da16")
}
> db.test_data.find()
{ "_id" : ObjectId("52f5922125d9e18cd51581b6"), "id" : 1, "info" : "I am in test" }
{ "_id" : ObjectId("52f5926d25d9e18cd51581b7"), "id" : 2, "info" : "I am in test" }
{ "_id" : ObjectId("52f5927125d9e18cd51581b8"), "id" : 3, "info" : "I am in test" }
> db.test_data.insert({"id":4,"info":"I am in test"})
> db.test_data.find()
{ "_id" : ObjectId("52f5922125d9e18cd51581b6"), "id" : 1, "info" : "I am in test" }
{ "_id" : ObjectId("52f5926d25d9e18cd51581b7"), "id" : 2, "info" : "I am in test" }
{ "_id" : ObjectId("52f5927125d9e18cd51581b8"), "id" : 3, "info" : "I am in test" }
{ "_id" : ObjectId("52f5c10e1caaf8492f79da17"), "id" : 4, "info" : "I am in test" }
特定資料庫比如 test 下的使用者 test_user,是可以訪問本資料庫下其他使用者建立的資料:
用 test_user1 登入 test 資料庫,並插入資料。
D:\MongoDB\mongodb-2.4.8\bin>mongo 127.0.0.1/test -utest_user1 -ppassword
MongoDB shell version: 2.4.8
connecting to: 127.0.0.1/test
> db.test_data.insert({"id":5,"info":"I am created by test_user1"})
> db.test_data.insert({"id":6,"info":"I am created by test_user1"})
> db.test_data.find()
{ "_id" : ObjectId("52f5922125d9e18cd51581b6"), "id" : 1, "info" : "I am in test" }
{ "_id" : ObjectId("52f5926d25d9e18cd51581b7"), "id" : 2, "info" : "I am in test" }
{ "_id" : ObjectId("52f5927125d9e18cd51581b8"), "id" : 3, "info" : "I am in test" }
{ "_id" : ObjectId("52f5c10e1caaf8492f79da17"), "id" : 4, "info" : "I am in test" }
{ "_id" : ObjectId("52f5c1eb15944f80880dfb1f"), "id" : 5, "info" : "I am created by test_user1" }
{ "_id" : ObjectId("52f5c1f015944f80880dfb20"), "id" : 6, "info" : "I am created by test_user1" }
用 test_user 重新登入 test 資料庫,可以查詢到 test_user1 建立的資料:
D:\MongoDB\mongodb-2.4.8\bin>mongo 127.0.0.1/test -utest_user -ppassword
MongoDB shell version: 2.4.8
connecting to: 127.0.0.1/test
> db.test_data.find()
{ "_id" : ObjectId("52f5922125d9e18cd51581b6"), "id" : 1, "info" : "I am in test" }
{ "_id" : ObjectId("52f5926d25d9e18cd51581b7"), "id" : 2, "info" : "I am in test" }
{ "_id" : ObjectId("52f5927125d9e18cd51581b8"), "id" : 3, "info" : "I am in test" }
{ "_id" : ObjectId("52f5c10e1caaf8492f79da17"), "id" : 4, "info" : "I am in test" }
{ "_id" : ObjectId("52f5c1eb15944f80880dfb1f"), "id" : 5, "info" : "I am created by test_user1" }
{ "_id" : ObjectId("52f5c1f015944f80880dfb20"), "id" : 6, "info" : "I am created by test_user1" }
不同資料庫中的使用者可以同名,不同資料庫中同名的使用者不能登入其他資料庫。例如 test1 和 test2 中都有 some_user,以 some_user 登入 test1 後,不能夠登入到 test2 進行資料庫操作
首先,在 test1 和 test2 中建立同名使用者 some_user,密碼都為 password:
# 建立使用者需要超級許可權,用 supper 使用者登入 admin 資料庫
D:\MongoDB\mongodb-2.4.8\bin>mongo 127.0.0.1/admin -usupper -ppassword
MongoDB shell version: 2.4.8
connecting to: 127.0.0.1/admin
> use test1
switched to db test1
> db.addUser("some_user","password")
{
"user" : "some_user",
"readOnly" : false,
"pwd" : "ed235c1f49990c04775a33e58ede9f99",
"_id" : ObjectId("52f5c385daeb9d6bbdf0a741")
}
> use test2
switched to db test2
> db.addUser("some_user","password")
{
"user" : "some_user",
"readOnly" : false,
"pwd" : "ed235c1f49990c04775a33e58ede9f99",
"_id" : ObjectId("52f5c3a1daeb9d6bbdf0a742")
}
然後,以 some_user 登入 test1,並嘗試對 test2 進行操作:
D:\MongoDB\mongodb-2.4.8\bin>mongo 127.0.0.1/test1 -usome_user -ppassword
MongoDB shell version: 2.4.8
connecting to: 127.0.0.1/test1
# 查詢資料庫 test2,出錯
> use test2
switched to db test2
> db.test2_data.find()
error: { "$err" : "not authorized for query on test2.test2_data", "code" : 16550 }
使用 db.auth() 可以對資料庫中的使用者進行驗證,如果驗證成功則返回 1,否則返回 0。db.auth() 只能針對登入使用者所屬的資料庫的使用者資訊進行驗證,不能驗證其他資料庫的使用者資訊。
D:\MongoDB\mongodb-2.4.8\bin>mongo 127.0.0.1/test -utest_user -ppassword
MongoDB shell version: 2.4.8
connecting to: 127.0.0.1/test
> db.auth("test_user1","password")
1
> db.auth("some_user","password")
Error: 18 { code: 18, ok: 0.0, errmsg: "auth fails" }
0
總結
啟用 MongoDB 使用者認證的步驟:
- 在要啟用認證的資料庫中建立對應的使用者
- 如果 admin 中沒有使用者,則必須在 admin 中新增使用者,否則即使使用 –auth 的方式啟動 MongoDB,認證方式也無效,預設會擁有超級許可權
- 以認證方式,即 –auth 引數的方式啟動 MongoDB 資料庫
- 用資料庫對應的使用者登入資料庫,比如:mongo 127.0.0.1/test -utest_user -ppasword