Authentication memverifikasi identitas, tetapi identitas itu sendiri harus diciptakan lebih dulu: sebuah user dengan nama, kredensial, dan daftar role. Kebiasaan yang benar adalah satu user per aplikasi atau per orang — bukan satu user super yang dipakai semua orang. Chapter ini membahas siklus hidup user di MongoDB: membuat, memeriksa, mengubah role dan password, hingga menghapus.
Peta materi Chapter ini:
db.createUser()dan anatomi field-nya:user,pwd,roles,mechanisms,passwordDigestor.- Membaca daftar user dengan
db.getUsers()danusersInfo. - Mengubah hak secara bertahap (
grantRolesToUser,revokeRolesFromUser) versus total (updateUser). - Mengganti password dengan
changeUserPassword, lalu membersihkan user dengandropUser.
Server latihan kita menjalankan authorization mati, tetapi penyimpanan user dan seluruh perintah manajemennya tetap berfungsi nyata — semua blok di chapter ini dieksekusi sungguhan pada database latihan_uji.
Membuat User Baru #
Perintah pembuat user adalah db.createUser(), dijalankan pada database tempat user itu akan hidup (authentication database). Kita buat user untuk sebuah aplikasi pelaporan:
use latihan_uji
// hapus sisa percobaan sebelumnya bila ada
try { db.dropUser("siti_operator") } catch (e) { print("user belum ada — buat baru") }
db.createUser({
user: "siti_operator",
pwd: "sandiSiti123",
roles: [
{ role: "readWrite", db: "latihan_uji" },
{ role: "read", db: "latihan_rapor" }
]
})
db.getUsers()Output yang Dihasilkan:
switched to db latihan_uji
user belum ada — buat baru
{
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1792261745, i: 1 }),
signature: {
hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
keyId: Long('0')
}
},
operationTime: Timestamp({ t: 1792261745, i: 1 })
}
{
users: [
{
_id: 'latihan_uji.siti_operator',
userId: UUID('99ac7376-534f-4473-aedc-cf91d1dbf773'),
user: 'siti_operator',
db: 'latihan_uji',
roles: [
{ role: 'readWrite', db: 'latihan_uji' },
{ role: 'read', db: 'latihan_rapor' }
],
mechanisms: [ 'SCRAM-SHA-1', 'SCRAM-SHA-256' ]
}
],
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1792261745, i: 1 }),
signature: {
hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
keyId: Long('0')
}
},
operationTime: Timestamp({ t: 1792261745, i: 1 })
}Mari kita bedah field-field pentingnya:
userdanpwd: nama user dan password-nya dalam bentuk teks biasa. Nama lengkap user hasilnya adalahsiti_operator@latihan_uji.roles: daftar role yang diberikan — setiap entri memadukan nama role dan database tempat role berlaku. RolereadWritedilatihan_ujimemberi hak baca-tulis di sana, sedangkanreaddilatihan_raporhanya memberi hak baca.mechanismspada output: MongoDB menyimpan kredensial untukSCRAM-SHA-1danSCRAM-SHA-256sekaligus — persis seperti yang kita lihat lewatsaslSupportedMechsdi Chapter Authentication.
db.getUsers() adalah pembungkus dari perintah usersInfo — db.runCommand({ usersInfo: 1 }) menghasilkan data yang sama. Untuk satu user, gunakan db.getUser("siti_operator") bentuk tepatnya.
passwordDigestor: Server atau Client #
Secara default, passwordDigestor: "server" membuat mongosh mengirim password apa adanya dan server yang melakukan hashing. Opsi "client" membalik pembagian kerja: mongosh meng-hash password di sisi klien dan hanya mengirim hasilnya. Opsi "client" hanya kompatibel dengan SCRAM-SHA-1, karena SCRAM-SHA-256 menuntut digest di server:
db.createUser({
user: "dewi_sha1",
pwd: "sandiDewi123",
roles: [],
mechanisms: ["SCRAM-SHA-1"],
passwordDigestor: "client"
})
db.getUser("dewi_sha1")Output yang Dihasilkan:
{
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1792261745, i: 2 }),
signature: {
hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
keyId: Long('0')
}
},
operationTime: Timestamp({ t: 1792261745, i: 2 })
}
{
_id: 'latihan_uji.dewi_sha1',
userId: UUID('ed2cf8c6-f44e-498a-8496-dc36d4670d97'),
user: 'dewi_sha1',
db: 'latihan_uji',
roles: [],
mechanisms: [ 'SCRAM-SHA-1' ]
}User dewi_sha1 tercatat hanya dengan mekanisme SCRAM-SHA-1 — itulah akibat membatasi field mechanisms. Mode "client" sesungguhnya warisan dari server-server lawas; untuk deployment modern, biarkan default "server" dan lindungi pengiriman password dengan TLS sebagaimana dibahas di Chapter TLS dan Enkripsi.
Mengubah Role: Bertahap vs Total #
Dua keluarga perintah mengubah role sebuah user, dengan semantik yang berbeda penting. grantRolesToUser dan revokeRolesFromUser bekerja bertahap — menambah atau melepas satu role tanpa menyentuh yang lain:
db.grantRolesToUser("siti_operator", [{ role: "dbAdmin", db: "latihan_uji" }])
db.revokeRolesFromUser("siti_operator", [{ role: "read", db: "latihan_rapor" }])
db.getUser("siti_operator")Output yang Dihasilkan (bagian $clusterTime dan operationTime yang berulang diringkas):
{ ok: 1 }
{ ok: 1 }
{
_id: 'latihan_uji.siti_operator',
userId: UUID('99ac7376-534f-4473-aedc-cf91d1dbf773'),
user: 'siti_operator',
db: 'latihan_uji',
roles: [
{ role: 'readWrite', db: 'latihan_uji' },
{ role: 'dbAdmin', db: 'latihan_uji' }
],
mechanisms: [ 'SCRAM-SHA-1', 'SCRAM-SHA-256' ]
}Setelah dua perintah itu, siti_operator memiliki readWrite dan dbAdmin di latihan_uji; role read di latihan_rapor sudah dilepas. Sebaliknya, db.updateUser() bekerja total — field roles yang diberikan menggantikan seluruh role lama:
db.updateUser("siti_operator", {
roles: [{ role: "readWrite", db: "latihan_uji" }]
})
db.getUser("siti_operator")Output yang Dihasilkan (diringkas serupa):
{ ok: 1 }
{
_id: 'latihan_uji.siti_operator',
userId: UUID('99ac7376-534f-4473-aedc-cf91d1dbf773'),
user: 'siti_operator',
db: 'latihan_uji',
roles: [ { role: 'readWrite', db: 'latihan_uji' } ],
mechanisms: [ 'SCRAM-SHA-1', 'SCRAM-SHA-256' ]
}Daftar role kini berisi tepat satu entri readWrite — dbAdmin hilang tanpa perlu revoke manual. Pilih alat sesuai maksud: operasi bertahap untuk penyesuaian kecil, operasi total untuk menyatakan “hak user ini harus persis seperti ini”.
Mengganti Password #
db.changeUserPassword() mengganti kredensial sebuah user dalam satu perintah. Password lama langsung tidak berlaku — kita buktikan dengan mencoba keduanya:
db.changeUserPassword("siti_operator", "sandiBaru789")
db.auth("siti_operator", "sandiSiti123")Output yang Dihasilkan (diringkas serupa):
{ ok: 1 }
Uncaught
MongoServerError[AuthenticationFailed]: Authentication failed.Password lama ditolak dengan AuthenticationFailed. Lanjut dengan password baru:
db.auth("siti_operator", "sandiBaru789")
db.logout()Output yang Dihasilkan (diringkas serupa):
{ ok: 1 }
{ ok: 1 }Baris { ok: 1 } pertama berasal dari db.auth() — password baru diterima — dan baris kedua dari db.logout() yang melepas identitas dari koneksi. Dalam operasional nyata, ganti password saat ada indikasi kredensial bocor dan saat rotasi berkala — topik yang kita dalami di Chapter Credential Management.
Menghapus User #
Penghapusan memakai db.dropUser(). Sebuah aplikasi yang pensiun harus meninggalkan user yang sudah tidak terpakai — user menganggur adalah pintu masuk yang terlupakan. Kita bersihkan kedua user percobaan:
db.dropUser("siti_operator")
db.dropUser("dewi_sha1")
db.getUsers()Output yang Dihasilkan (diringkas serupa):
{ ok: 1 }
{ ok: 1 }
{
users: [],
ok: 1
}Daftar user di latihan_uji kembali kosong. Untuk membersihkan sekaligus semua user pada satu database, jalankan perintah db.runCommand({ dropAllUsersFromDatabase: 1 }) — dan ada satu jebakan yang penting diketahui:
Rangkuman #
db.createUser()memadukan identitas (user), kredensial (pwd), dan otorisasi awal (roles) dalam satu perintah pada authentication database.passwordDigestor: "server"(default) mengirim password untuk di-hash server;"client"hanya untukSCRAM-SHA-1dan praktis hanya relevan bagi server lawas.grantRolesToUser/revokeRolesFromUsermengubah role secara bertahap;updateUsermengganti seluruh daftar role sekaligus.changeUserPasswordlangsung mematikan password lama; verifikasi dengandb.auth()sebelum dan sesudah.dropUsermenghapus satu user;dropDatabasejustru tidak menghapus user di database itu.