Implementasi Node Js Server Dan Basic Authentication
Dalam setiap tutorial, saya selalu kesulitan memahami bagian otentikasi itu. Rasanya seperti penulis memberikan panduan tentang cara menyalin dari dokumen, daripada menjelaskan mekanisme yang sebenarnya dan apa yang terjadi. Tujuan dari penjelasan ini adalah untuk memandu Anda melalui proses otentikasi yang sebenarnya dan menjelaskan setiap mekanisme.
Tutorial ini mengasumsikan beberapa keakraban dengan terminal atau Command Line Interface (CLI) dan Javascript atau Node.js.
Langkah 1 Mengatur struktur file
Pertama, buat folder tingkat atas yang disebut "authTut" hanya untuk menampung dua sisi project, server dan client. Dalam hal ini, gunakan cURL sebagai antarmuka client instead browser. Saya pikir ini membantu Anda memahami apa yang sebenarnya terjadi di dalam browser.
Untuk meniru penyimpanan browser, buat folder/client di/authTuts dan juga buat folder /server untuk membangun server.
Jalankan perintah berikut di terminal:
workspace $ mkdir authTut
workspace $ cd authTut
authTut $ mkdir server
authTut $ mkdir client
Langkah 2 Inisialisasi npm dan instal express di folder /server
Pertama, buka folder /server lalu inisialisasi npm sehingga Anda dapat melacak dependensi server. Kemudian instal express sebagai dependensi dan kemudian buat file server.js.
authTut $ cd server
server $ npm init -y
server $ npm install express --save
server $ touch server.js
Perhatikan bahwa meneruskan flag "-y" ke "npm init" akan secara otomatis menerima default yang npm menginisialisasi project. Memanggil fungsi ini menampilkan opsi default yang log pada console.
Pada titik ini, Anda harus memiliki struktur folder/file yang terlihat seperti ini:
- /authTuts
- /server
- /node_modules
- server.js
- package.json
- /client
Langkah 3 Buat dan jalankan server
Buka folder /authTuts di editor teks favorit Anda dan buka file authTuts/server/server.js.
Pertama Anda memerlukan modul Express, lalu Anda memanggil fungsi express() untuk membuat aplikasi Anda, dan terakhir memberi tahu Express port mana yang harus dijalankan.
//npm modules
const express = require('express');
// create the server
const app = express();
// tell the server what port to listen on
app.listen(3000, () => {
console.log('Listening on localhost:3000')
})
Kemudian panggil "nodeserver.js" dari terminal. Ini akan memulai server. Anda akan melihat respons "localhost:listening on 3000". (Anda dapat menjalankan file Javascript menggunakan perintah "node" terminal).
server $ node server.js
Listening on localhost:3000
Saya membuat server. Ketika saya membuka "http://localhost:3000/" sekarang, saya mendapatkan pesan kesalahan "Tidak dapat GET /", yang jauh lebih baik dari pada kesalahan "Tidak dapat mengakses situs ini".
Langkah 4 Tambahkan rute beranda ke "/"
Perbarui file server.js untuk menambahkan metode GET ke route "/". Ketika client (browser atau cURL (dibahas nanti)) memanggil metode GET, server merespons dengan data. Dalam hal ini, berikan metode GET "/" dengan fungsi callback yang memberi tahu server untuk merespons dengan "cukup kunjungi halaman beranda".
//npm modules
const express = require('express');
// create the server
const app = express();
// create the homepage route at '/'
app.get('/', (req, res) => {
res.send('you just hit the home page\n')
})
// tell the server what port to listen on
app.listen(3000, () => {
console.log('Listening on localhost:3000')
})
Parameter "req" dan "res" yang diteruskan ke fungsi callback app.get ('/') adalah objek "request" dan "response" yang dihasilkan dari header request yang diterima.
Jika sekarang Anda mengakses http://localhost:3000/, Anda akan mendapatkan error "Cannot GET /" karena file lama masih berfungsi sebagai server. Setelah menyimpan perubahan, Anda harus melanjutkan dan memulai ulang server. Untuk melakukan ini, tekan "control C" di terminal dan kemudian jalankan "nodeserver.js" lagi.
Listening on localhost:3000
^C
server $ node server.js
Listening on localhost:3000
Sekarang, ketika saya mengakses http://localhost:3000/ lagi, dikatakan "Saya baru saja mengunjungi halaman beranda". Buka tab atau jendela baru di terminal Anda dan buka folder / client. Kemudian panggil perintah cURL dan berikan beberapa opsi untuk mendapatkan endpoints halaman beranda. Sebuah respon harus dikembalikan.
server $ cd ..
authTut $ cd client
client $ cURL -X GET http://localhost:3000/
you just hit the home page
Di atas, Anda dapat menggunakan opsi "-X" untuk meneruskan curl ke GET atau POST ke endpoints. Di sini, kita "memperoleh" endpoints "/".
Langkah 5 Tambahkan nodemon
Ini bisa sangat mengganggu jika Anda harus me-restart server setiap kali Anda melakukan perubahan pada file server.js. Mari kita gunakan modul nodemon. Modul ini secara otomatis me-restart server setiap kali Anda menyimpan perubahan Anda ke file server.js. Pertama, instal paket nodedemon secara global.
$ npm install -g nodemon
Meneruskan opsi -g ke penginstal modul npm akan menginstal paket secara global sehingga Anda dapat mengaksesnya dari mana saja di sistem file saat Anda berada di terminal. Tidak masalah folder mana di atas Anda memanggil, karena itu tidak masalah. Sekarang mari kita matikan server dan gunakan nodemon untuk memulainya.
^C
server $ nodemon server.js
Kemudian ubah teks respons di jalur beranda menjadi sesuatu yang lain dan console.log() request object untuk melihat seperti apa tampilannya. Setelah menyimpan file, tab Terminal Server akan menampilkan server restart.
//npm modules
const express = require('express');
// create the server
const app = express();
// create the homepage route at '/'
app.get('/', (req, res) => {
console.log(req)
res.send('You hit the home page without restarting the server automatically\n')
})
// tell the server what port to listen on
app.listen(3000, () => {
console.log('Listening on localhost:3000')
})
Sekarang mari kita panggil curl lagi. Namun, kali ini kita juga melewati flag -v (untuk "verbose").
client $ curl -X GET http://localhost:3000 -v
Note: Unnecessary use of -X or --request, GET is already inferred.
* Rebuilt URL to: http://localhost:3000/
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3000 (#0)
> GET / HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: text/html; charset=utf-8
< Content-Length: 66
< ETag: W/"42-Ybeup68SVZ+Id3fqVh25rCkXfno"
< Date: Sun, 29 Oct 2017 19:58:38 GMT
< Connection: keep-alive
<
You hit the home page without restarting the server automatically
request kedua mendapatkan informasi tentang request curl. Mari kita lihat itu.
- cURL menunjukkan bahwa Anda tidak perlu melewati -X GET. Ini adalah default untuk cURL. Namun, saya ingin mengklarifikasi dalam tutorial ini.
- "Rebuild URL ..." menunjukkan bahwa cURL telah menambahkan garis miring ke akhir URL.
- "Mencoba :: 1 ..." adalah alamat IP tempat URL diselesaikan.
- Baris berikutnya adalah port yang terhubung. Ini adalah port yang Anda tentukan saat membuat server.
- > Menunjukkan data yang dikirim cURL ke server.
- < Menunjukkan data yang diterima cURL dari server.
- Akhirnya, teks respons yang dikirim oleh server ditampilkan
Jika Anda beralih ke tab terminal tempat server berjalan, Anda akan melihat output yang sangat panjang. Ini adalah objek "request" yang dibuat server dari data yang dikirim ke server.
Langkah 6 Instal uuid untuk secara otomatis menghasilkan string unik
Kemudian buka tab atau jendela terminal ketiga di folder server Anda dan instal modul uuid. Ini memungkinkan Anda untuk menghasilkan string acak. (Membuka tab ketiga memungkinkan Anda untuk menginstal paket server tanpa menghentikan proses server saat ini. Jika Anda menyertakan modul baru di file server.js, nodemon akan secara otomatis memulai ulang dan modul ini Dapat diimpor.)
server $ npm install --save uuid
Kemudian tambahkan ke file server, perbarui teks respons dan kirimkan ke client. Perhatikan bahwa kita menggunakan interpolasi string di bawah ini. Untuk melakukan ini, Anda perlu menggunakan "back ticks" alih-alih tanda kutip. Ini (``), bukan ini (''). (Mungkin di dekat kiri atas keyboard.)
//npm modules
const express = require('express');
const uuid = require('uuid').v4
// create the server
const app = express();
// create the homepage route at '/'
app.get('/', (req, res) => {
console.log(req)
const uniqueId = uuid()
res.send(`Hit home page. Received the unique id: ${uniqueId}\n`)
})
// tell the server what port to listen on
app.listen(3000, () => {
console.log('Listening on localhost:3000')
})
Sekarang panggil cURL lagi.
client $ curl -X GET http://localhost:3000
Hit home page. Received the unique id: 044e0263-58b7-4c7f-a032-056cd81069e3
Langkah 7 Tambahkan dan konfigurasikan express-session
Instal express-session. Express tidak melakukan ini secara otomatis, jadi middleware ini menangani pembuatan session.
server $ npm install express-session --save
Setelah terinstal, ubah file server.js sebagai berikut:
- express-session
- Tambahkan atau konfigurasikan aplikasi Anda untuk menggunakan middleware session dengan sessionID unik yang Anda buat. log object request.sessionID sebelum dan sesudah middleware digunakan.
- Hapus ID yang dibuat atau dikirim ke client
Perhatikan bahwa dalam konfigurasi session di bawah ini, kami meninggalkan "secret" sebagai "keyboard cat". Namun, dalam environtment production, ganti ini dengan string yang dihasilkan secara acak yang diperoleh dari variabel environtment.
//npm modules
const express = require('express');
const uuid = require('uuid/v4')
const session = require('express-session')
// create the server
const app = express();
// add & configure middleware
app.use(session({
genid: (req) => {
console.log('Inside the session middleware')
console.log(req.sessionID)
return uuid() // use UUIDs for sessionIDs
},
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
// create the homepage route at '/'
app.get('/', (req, res) => {
console.log('Inside the homepage callback function')
console.log(req.sessionID)
res.send(`You hit home page!\n`)
})
// tell the server what port to listen on
app.listen(3000, () => {
console.log('Listening on localhost:3000')
})
Sekarang mari kita panggil request curl lagi dengan flag -v.
curl -X GET http://localhost:3000 -v
...
< set-cookie: connect.sid=s%3A5199f3ed-3f5a-4478-aed7-fab9ce6ca378.DjQlJ%2F1t%2F00RAfIs5yW6CEsVUXM25aMclq7VGzxVnoY; Path=/; HttpOnly
...
Setelah menghilangkan respons di atas, tetapi Anda dapat melihat dalam data yang dikembalikan oleh server (ditunjukkan dengan < simbol) bahwa sessionID disetel ke string acak. Saat Anda beralih ke log server, Anda akan melihat sesuatu seperti ini:
Inside the session middleware
undefined
Inside the homepage callback function
5199f3ed-3f5a-4478-aed7-fab9ce6ca378
Ketika saya mencatat req.sessionID di middleware session, saya tidak menambahkan sessionID ke request object karena session belum dipakai. Namun, ketika callback dicapai dari request GET, middleware session dieksekusi dan sessionID ditambahkan ke request object.
Coba panggil fungsi cURL beberapa kali lagi. Anda dapat melihat bahwa sessionID baru dibuat setiap kali. Browser secara otomatis menyimpan/mengirim sessionID dan mengirimkannya ke server pada setiap request. Namun, cURL secara otomatis menyimpan sessionID dan tidak mengirimkannya di header request. Mari kita perbaiki. Gunakan cURL lagi. Namun, berikan tanda "-c" dengan teks "cookie-file.txt",
client $ curl -X GET http://localhost:3000 -c cookie-file.txt
Ini akan membuat file teks bernama "cookie-file.txt" di folder /client. File teks ini akan muncul di project Anda. Anda sekarang dapat memanggil curl lagi, tetapi kali ini dengan tanda "-b", panggil cookie-file.txt dan beri tahu cURL untuk mengirim sessionID di data header. Mari tambahkan juga tanda "-v" untuk mengonfirmasi hal ini.
curl -X GET http://localhost:3000 -b cookie-file.txt -v
...
> GET / HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.54.0
> Accept: */*
> Cookie: connect.sid=s%3Ade59a40f-6737-4b8d-98bf-bf2bb8495118.e0pWTi2w8%2FAAOKxKgKDBdu99JnspruYSEgLSV3tvxX4
...
Saya telah menghilangkan output di atas, tetapi seperti yang Anda lihat, sessionID sedang dikirim di header request, dan tanda > mengirimkannya ke server. Coba panggil fungsi ini sebanyak yang Anda suka. Saat Anda beralih ke log server, Anda dapat melihat bahwa sessionID yang sama dikeluarkan ke konsol setiap saat. Anda mungkin juga memperhatikan bahwa log "Inside Session Middleware" belum dibuat. Ini karena fungsi "genid" tidak dipanggil karena id sudah ditangkap.
okey. Sekarang satu masalah diharapkan. Mari kita restart server.
Di tab terminal tempat server berjalan, tekan "control C" dan kemudian mulai pencadangan dengan nodemon.
Inside the homepage callback function
de59a40f-6737-4b8d-98bf-bf2bb8495118
^C
server $ nodemon server.js
Listening on localhost:3000
Ingat perintah cURL dari folder client.
client $ curl -X GET http://localhost:3000 -b cookie-file.txt
Kemudian lihat kembali log server.
Listening on localhost:3000
Inside the session middleware
de59a40f-6737-4b8d-98bf-bf2bb8495118
Inside the homepage callback function
ac656d2a-9796-4560-9dbf-73996a1853f8
Seperti disebutkan di atas, fungsi genid middleware session dipanggil. Ini karena session disimpan di memori server. Oleh karena itu, ketika saya me-restart server, sessionID terhapus dengan sisa memori. Penguraiannya adalah sebagai berikut.
- Server akan dimulai ulang dan memori session akan dihapus.
- Kirim request cURL ke server dengan sessionID
- Server menerima request dan middleware session tidak dapat menemukan sessionID di memori, sehingga memanggil fungsi genid.
- Fungsi genid mencatat bahwa itu ada di middleware session dan mencatat sessionID dari request object. Karena Anda mengirim sessionID dalam request cURL, request object sebenarnya dibuat dengan sessionID tersebut. Namun, sessionID ini ditimpa oleh nilai kembalian fungsi genid.
- Saat middleware session selesai menimpa sessionID yang dikirim, kontrol diteruskan ke fungsi callback di app.get(). Sekarang catat bahwa Anda berada di fungsi callback hompage dan catat ID baru.
- Mari buat request curl itu lagi dari folder client.
client $ curl -X GET http://localhost:3000 -b cookie-file.txt
Periksa log server lagi.
Inside the session middleware
de59a40f-6737-4b8d-98bf-bf2bb8495118
Inside the homepage callback function
b02aa920-7031-427f-ac2e-b82f21140002
Sekali lagi, karena Anda mengirim sessionID yang sama sebelum Anda me-restart server, server merespons dengan sessionID yang berbeda. Anda harus memanggil request curl lagi, tetapi kali ini Anda melewati tanda "-c", yang menimpa informasi session yang ada.
client $ curl -X GET http://localhost:3000 -c cookie-file.txt
Kembali ke log server.
Inside the session middleware
undefined
Inside the homepage callback function
74f37795-6fcf-4300-beb9-3de41395eafe
req.sessionID tidak ditentukan karena request curl tidak mengirim informasi session. Lihatlah cookie-file.txt. Benar saja, ada sessionID yang dibuat dan dikembalikan.
...
#HttpOnly_localhost FALSE / FALSE 0 connect.sid s%3A74f37795-6fcf-4300-beb9-3de41395eafe.5mblOCOvpwAMh7bNuTZ9qyloG5UOcIczep5GjMnVEi8
Sekarang, jika saya memanggil request curl lagi dengan flag "-b", saya tidak melihat bahwa log "Insidethesessionmiddle" dipanggil karena genid tidak dipanggil. sessionID cocok dengan sessionID di memori.
Namun, masalahnya belum terpecahkan. Ketika Anda me-restart server, memori akan terhapus lagi. Oleh karena itu, diperlukan suatu cara untuk dapat menyimpan sessionID meskipun server dimatikan. Di situlah "session store" masuk. Biasanya, database bertindak sebagai penyimpanan session, tetapi kami mencoba membuatnya sesederhana mungkin, jadi kami menyimpan informasi session dalam file teks.
Jika Anda mengunjungi dokumentasi ekspres, Anda akan melihat bahwa ada banyak paket npm yang bertindak sebagai perekat antara database dan middleware session. Gunakan nama "session-file-store". Instal seperti biasa.
server $ npm install session-file-store --save
Sekarang mari kita tambahkan ke file server.js.
//npm modules
const express = require('express');
const uuid = require('uuid/v4')
const session = require('express-session')
const FileStore = require('session-file-store')(session);
// create the server
const app = express();
// add & configure middleware
app.use(session({
genid: (req) => {
console.log('Inside the session middleware')
console.log(req.sessionID)
return uuid() // use UUIDs for sessionIDs
},
store: new FileStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
// create the homepage route at '/'
app.get('/', (req, res) => {
console.log('Inside the homepage callback function')
console.log(req.sessionID)
res.send(`You hit home page!\n`)
})
// tell the server what port to listen on
app.listen(3000, () => {
console.log('Listening on localhost:3000')
})
Perhatikan di atas bahwa FileStore memanggil variabel session bila diperlukan. Kemudian tambahkan instance ke konfigurasi session FileStore.
Anda juga perlu melakukan satu hal lagi. Secara default, modul "session-file-store" membuat direktori "/session" baru saat pertama kali dipanggil. Setiap kali Anda membuat session baru untuk pertama kalinya, modul membuat file baru informasi session di folder / session. Mengimpor penyimpanan file session ke server.js dan penyimpanan file session bergantung pada folder /session, jadi nodemon me-restart server setiap kali membuat session baru.
Anda dapat menginstruksikan nodemon untuk mengabaikan file atau direktori dengan memanggil "—ignore" dan meneruskan nama file atau direktori.
server $ nodemon --ignore sessions/ server.js
Ini merepotkan untuk diingat jika Anda ingin kembali ke project ini dan memahami cara menjalankan server. Mari kita membuatnya lebih mudah dengan menambahkannya ke skrip npm di file package.json.
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev:server": "nodemon --ignore sessions/ server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.16.2",
"express-session": "^1.15.6",
"session-file-store": "^1.1.2",
"uuid": "^3.1.0"
}
}
Jika Anda belum melakukannya, lanjutkan dan matikan proses nodedemon saat ini dan panggil skrip dev: server yang Anda tambahkan.
^C
server $ npm run dev:server
Selanjutnya, mari kita buat perintah cURL untuk membuat file cookie baru yang akan disimpan di client.
client $ curl -X GET http://localhost:3000 -c cookie-file.txt
Anda sekarang harus memiliki sessionID baru yang disimpan di cookie-file.txt. Jika Anda mengabaikan bit "s% 3A" itu, sisanya sebelum "." Harus cocok dengan nama file baru yang disimpan di folder /session.
Sekarang restart server.
^C
server $ npm run dev:server
Kemudian panggil perintah cURL, kali ini dengan flag "-b" dan lewat cookie-file.txt, untuk mengirim sessionID yang Anda buat sebelum memulai ulang server.
client $ curl -X GET http://localhost:3000 -b cookie-file.txt
Silakan hubungi sebanyak yang Anda suka. Server harus menampilkan sessionID yang sama setiap saat. Oleh karena itu, jika Anda membuat penyimpanan file session di sini, Anda akan menemukan bahwa Anda dapat menyimpan session di sisi server.
Selamat jika Anda sampai sejauh ini! session tutorial ini selesai. Mari beralih ke Authentication!
Authentication
Langkah 1 Tambahkan endpoints login
kamu tidak apa apa! Mari kita mulai! Pertama, tambahkan rute masuk ke aplikasi Anda menggunakan metode GET dan POST. Perhatikan bahwa metode posting memanggil "req.body". Ini akan mencatat data yang dikirim oleh request POST ke server.
//npm modules
const express = require('express');
const uuid = require('uuid/v4')
const session = require('express-session')
const FileStore = require('session-file-store')(session);
// create the server
const app = express();
// add & configure middleware
app.use(session({
genid: (req) => {
console.log('Inside the session middleware')
console.log(req.sessionID)
return uuid() // use UUIDs for sessionIDs
},
store: new FileStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
// create the homepage route at '/'
app.get('/', (req, res) => {
console.log('Inside the homepage callback function')
console.log(req.sessionID)
res.send(`You got home page!\n`)
})
// create the login get and post routes
app.get('/login', (req, res) => {
console.log('Inside GET /login callback function')
console.log(req.sessionID)
res.send(`You got the login page!\n`)
})
app.post('/login', (req, res) => {
console.log('Inside POST /login callback function')
console.log(req.body)
res.send(`You posted to the login page!\n`)
})
// tell the server what port to listen on
app.listen(3000, () => {
console.log('Listening on localhost:3000')
})
Langkah 2 Konfigurasikan Express untuk membaca data POST
Mari kita buat perintah cURL baru pada client.
curl -X POST http://localhost:3000/login -b cookie-file.txt -H 'Content-Type: application/json' -d '{"email":"[email protected]", "password":"password"}'
Sederhananya, jika Anda menggunakan Windows, Anda perlu menggunakan tanda kutip ganda dan escape dengan tanda yen sebagai berikut:
curl -X POST http://localhost:3000/login -b cookie-file.txt -H "Content-Type: application/json" -d "{\"email\":\"[email protected]\", \"password\":\"password\"}"
Untuk keterbacaan, kami akan menggunakan tanda kutip tunggal untuk sisa artikel ini. Perlu diingat bahwa pada Windows Anda harus mengganti menggunakan tanda kutip ganda.
Sekarang mari kita kembali ke cerita. Di atas, kami telah membuat beberapa perubahan.
- Saat ini menggunakan -XPOST instead dari -XGET
- Saya menambahkan flag -H dan mengatur content-type header ke application/json
- Lewati flag -d dengan data yang ingin Anda kirim. Perhatikan bahwa itu diapit oleh tanda kutip tunggal
Melihat output server, Anda dapat melihat bahwa:
Inside POST /login callback function
undefined
req.body tampaknya "undifined". Masalahnya di sini adalah Express tidak benar-benar tahu cara membaca content-type JSON, jadi kita perlu menambahkan middleware lain untuk melakukan ini. Anda dapat menggunakan middleware body-parser untuk mengurai data dan menambahkannya ke properti req.body.
server $ npm install body-parser --save
Kemudian minta di server.js dan konfigurasikan express untuk menggunakannya.
//npm modules
const express = require('express');
const uuid = require('uuid/v4')
const session = require('express-session')
const FileStore = require('session-file-store')(session);
const bodyParser = require('body-parser');
// create the server
const app = express();
// add & configure middleware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(session({
genid: (req) => {
console.log('Inside the session middleware')
console.log(req.sessionID)
return uuid() // use UUIDs for sessionIDs
},
store: new FileStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
// create the homepage route at '/'
app.get('/', (req, res) => {
console.log('Inside the homepage callback function')
console.log(req.sessionID)
res.send(`You got home page!\n`)
})
// create the login get and post routes
app.get('/login', (req, res) => {
console.log('Inside GET /login callback function')
console.log(req.sessionID)
res.send(`You got the login page!\n`)
})
app.post('/login', (req, res) => {
console.log('Inside POST /login callback function')
console.log(req.body)
res.send(`You posted to the login page!\n`)
})
// tell the server what port to listen on
app.listen(3000, () => {
console.log('Listening on localhost:3000')
})
Di atas Anda dapat melihat bahwa kami telah mengonfigurasi aplikasi kami untuk menggunakan middleware body-parser, bodyParser.json() dan bodyParser.urlencoded(). Ini mengirimkan data langsung ke server dalam format JSON, tetapi jika Anda menambahkan ujung depan yang sebenarnya ke aplikasi Anda, data content-type dalam request POST akan dikirim sebagai "aplication/x-www-form-urlencoded". .. Saya telah menyertakan file ini di sini jika Anda ingin menggunakannya sebagai boilerplate untuk project baru Anda.
Langkah 3 Tambahkan dan konfigurasikan Passport.js
Instal modul passport.js dengan modul strategi otentikasi passport-lokal.
server $ npm install passport passport-local --save
Sebelum kita masuk ke kode, mari kita bicara tentang alur otentikasi.
- user POST informasi login ke route /login
- Anda perlu melakukan sesuatu dengan data itu. Di sinilah passport Anda masuk. Anda dapat menghubungi passport.authenticate ("strategi login", callback (err, user, info)). Metode ini membutuhkan dua parameter. Dalam hal ini, "login strategi", yang "lokal", diautentikasi dengan email, kata sandi (Anda dapat menggunakan passport Anda untuk menemukan daftar strategi masuk lainnya, termasuk Facebook, Twitter, dll.) dan fungsi callback. Melakukan. Jika otentikasi berhasil, ia menyediakan akses ke objek user, dan jika tidak berhasil, ia menyediakan akses ke objek kesalahan.
- passport.authenticate() memanggil strategi otentikasi "lokal", jadi Anda perlu mengonfigurasi passport Anda untuk menggunakan strategi itu. Anda dapat mengatur passport Anda dengan passport.use (newsstrategyClass). Di sini Anda memberi tahu passport Anda cara mengautentikasi user menggunakan strategi lokal.
- Dalam deklarasi strategyClass, ambil data dari request POST dan gunakan untuk mencari database untuk user yang cocok dan memverifikasi bahwa kredensial cocok. Jika cocok, passport menambahkan metode login() ke request object dan kembali ke fungsi callback passport.authenticate().
- Dalam fungsi callback passport.authenticate(), panggil metode req.login().
- Metode req.login (user, callback ()) menerima objek user yang baru saja dikembalikan dari strategi lokal dan memanggil passport.serializeUser (callback ()). Dapatkan objek user itu dan 1) simpan ID user di penyimpanan file session. 2) Simpan ID user di request object sebagai request.session.passport dan 3) tambahkan objek user di request object sebagai request.user. request selanjutnya ke route yang disetujui sekarang dapat mengambil objek user tanpa user masuk lagi (dapatkan ID dari penyimpanan file session dan gunakan untuk mengambil objek user dari database). , Tambahkan ke request object). ).
kamu tidak apa apa! Mungkin tampak banyak! Melihat kode yang dihasilkan dan log server akan membuat situasi lebih jelas.
//npm modules
const express = require('express');
const uuid = require('uuid/v4')
const session = require('express-session')
const FileStore = require('session-file-store')(session);
const bodyParser = require('body-parser');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const users = [
{id: '2f24vvg', email: '[email protected]', password: 'password'}
]
// configure passport.js to use the local strategy
passport.use(new LocalStrategy(
{ usernameField: 'email' },
(email, password, done) => {
console.log('Inside local strategy callback')
// here is where you make a call to the database
// to find the user based on their username or email address
// for now, we'll just pretend we found that it was users[0]
const user = users[0]
if(email === user.email && password === user.password) {
console.log('Local strategy returned true')
return done(null, user)
}
}
));
// tell passport how to serialize the user
passport.serializeUser((user, done) => {
console.log('Inside serializeUser callback. User id is save to the session file store here')
done(null, user.id);
});
// create the server
const app = express();
// add & configure middleware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(session({
genid: (req) => {
console.log('Inside session middleware genid function')
console.log(`Request object sessionID from client: ${req.sessionID}`)
return uuid() // use UUIDs for sessionIDs
},
store: new FileStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
app.use(passport.initialize());
app.use(passport.session());
// create the homepage route at '/'
app.get('/', (req, res) => {
console.log('Inside the homepage callback')
console.log(req.sessionID)
res.send(`You got home page!\n`)
})
// create the login get and post routes
app.get('/login', (req, res) => {
console.log('Inside GET /login callback')
console.log(req.sessionID)
res.send(`You got the login page!\n`)
})
app.post('/login', (req, res, next) => {
console.log('Inside POST /login callback')
passport.authenticate('local', (err, user, info) => {
console.log('Inside passport.authenticate() callback');
console.log(`req.session.passport: ${JSON.stringify(req.session.passport)}`)
console.log(`req.user: ${JSON.stringify(req.user)}`)
req.login(user, (err) => {
console.log('Inside req.login() callback')
console.log(`req.session.passport: ${JSON.stringify(req.session.passport)}`)
console.log(`req.user: ${JSON.stringify(req.user)}`)
return res.send('You were authenticated & logged in!\n');
})
})(req, res, next);
})
// tell the server what port to listen on
app.listen(3000, () => {
console.log('Listening on localhost:3000')
})
baiklah. Jadi sepertinya Anda telah menambahkan banyak kode di sini, tetapi jika Anda menghapus console.log() dan komentar tambahan, itu lebih banyak lagi. Mari kita lihat itu.
- Di awal file, Anda memerlukan passport dan strategi lokal passport.
- Jika Anda membuka setengah file, Anda akan melihat bahwa Anda telah mengonfigurasi aplikasi Anda untuk menggunakan passport Anda sebagai middleware dalam panggilan ke app.use (passport.initialize ()) dan app.use (passport.session ()). Perhatikan bahwa Anda memanggil ini setelah mengonfigurasi aplikasi Anda untuk menggunakan express-session dan penyimpanan file session. Ini karena passport berada di atas mereka.
- Lebih jauh ke bawah, Anda dapat melihat bahwa metode app.post ('login') segera memanggil passport.authenticate () dalam strategi lokal.
- Strategi lokal dikonfigurasi menggunakan passport.use (LocalStrategy baru ()) di awal file. Strategi lokal menggunakan nama user dan kata sandi untuk mengotentikasi user. Namun, aplikasi ini menggunakan alamat email bukan nama user, jadi alias bidang nama user menjadi "email". Kemudian beri tahu strategi lokal Anda cara menemukan user di database. Saya biasanya melihat sesuatu seperti "DB.findById ()" di sini, tetapi untuk saat ini saya mengabaikannya dan berasumsi bahwa memanggil array user yang berisi satu objek user akan mengembalikan To do yang benar untuk dilakukan user. Perhatikan bahwa bidang "email" dan "kata sandi" yang diteruskan ke fungsi di LocalStrategy () baru adalah email dan kata sandi yang dikirim ke server dalam request POST. Jika data yang diterima dari request POST cocok dengan data yang ditemukan dalam database, panggil metode done (objek kesalahan, objek user) dan berikan null dan objek user dikembalikan dari database. (Jika kredensial tidak segera cocok, kami akan menanganinya.)
- Lompat ke fungsi callback passport.authenticate() setelah metode done() dipanggil. Sekarang berikan objek user ke fungsi req.login() (ingat bahwa login telah ditambahkan dengan memanggil passport.authenticate()). () Berfungsi untuk meminta objek). Fungsi req.login() menangani serialisasi ID user ke penyimpanan session dan request object, dan menambahkan objek user ke request object.
- Terakhir, balas user yang memberi tahu mereka bahwa mereka telah diautentikasi.
mari kita coba! Memanggil request cURL dan mengirimkan kredensial login ke server. Sebelum melakukan hal berikut, hapus semua file yang disimpan di direktori / session, panggil request POST berikut dengan flag "-c", dan buat / timpa cookie-file.txt di folder client. Harap dicatat bahwa Anda sedang melakukannya. Dengan kata lain, kita pada dasarnya memulai dari keadaan bersih.
client $ curl -X POST http://localhost:3000/login -c cookie-file.txt -H 'Content-Type: application/json' -d '{"email":"[email protected]", "password":"password"}'
You were authenticated & logged in!
Anda akan melihat sesuatu seperti berikut di log server:
Inside session middleware genid function
Request object sessionID from client: undefined
Inside POST /login callback
Inside local strategy callback
Local strategy returned true
Inside passport.authenticate() callback
req.session.passport: undefined
req.user: undefined
Inside serializeUser callback. User id is save to the session file store here
Inside req.login() callback
req.session.passport: {"user":"2f24vvg"}
req.user: {"id":"2f24vvg","email":"[email protected]","password":"password"}
Seperti disebutkan di atas, objek req.session.passport dan req.user tidak ditentukan sebelum memanggil req.login(). Mereka didefinisikan setelah fungsi req.login() dipanggil (yaitu, ketika Anda memasukkan fungsi callback req.login()).
Langkah 4 Tambahkan rute yang memerlukan authorization(persetujuan)
Tambahkan rute yang memerlukan persetujuan ke aplikasi Anda. Sekarang user telah "diautentikasi" (yaitu, masuk), kita dapat berbicara tentang "otorisasi" yang memberi tahu server rute mana user harus masuk sebelum mengakses.
Mari kode!
//npm modules
const express = require('express');
const uuid = require('uuid/v4')
const session = require('express-session')
const FileStore = require('session-file-store')(session);
const bodyParser = require('body-parser');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const users = [
{id: '2f24vvg', email: '[email protected]', password: 'password'}
]
// configure passport.js to use the local strategy
passport.use(new LocalStrategy(
{ usernameField: 'email' },
(email, password, done) => {
console.log('Inside local strategy callback')
// here is where you make a call to the database
// to find the user based on their username or email address
// for now, we'll just pretend we found that it was users[0]
const user = users[0]
if(email === user.email && password === user.password) {
console.log('Local strategy returned true')
return done(null, user)
}
}
));
// tell passport how to serialize the user
passport.serializeUser((user, done) => {
console.log('Inside serializeUser callback. User id is save to the session file store here')
done(null, user.id);
});
passport.deserializeUser((id, done) => {
console.log('Inside deserializeUser callback')
console.log(`The user id passport saved in the session file store is: ${id}`)
const user = users[0].id === id ? users[0] : false;
done(null, user);
});
// create the server
const app = express();
// add & configure middleware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(session({
genid: (req) => {
console.log('Inside session middleware genid function')
console.log(`Request object sessionID from client: ${req.sessionID}`)
return uuid() // use UUIDs for sessionIDs
},
store: new FileStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
app.use(passport.initialize());
app.use(passport.session());
// create the homepage route at '/'
app.get('/', (req, res) => {
console.log('Inside the homepage callback')
console.log(req.sessionID)
res.send(`You got home page!\n`)
})
// create the login get and post routes
app.get('/login', (req, res) => {
console.log('Inside GET /login callback')
console.log(req.sessionID)
res.send(`You got the login page!\n`)
})
app.post('/login', (req, res, next) => {
console.log('Inside POST /login callback')
passport.authenticate('local', (err, user, info) => {
console.log('Inside passport.authenticate() callback');
console.log(`req.session.passport: ${JSON.stringify(req.session.passport)}`)
console.log(`req.user: ${JSON.stringify(req.user)}`)
req.login(user, (err) => {
console.log('Inside req.login() callback')
console.log(`req.session.passport: ${JSON.stringify(req.session.passport)}`)
console.log(`req.user: ${JSON.stringify(req.user)}`)
return res.send('You were authenticated & logged in!\n');
})
})(req, res, next);
})
app.get('/authrequired', (req, res) => {
console.log('Inside GET /authrequired callback')
console.log(`User authenticated? ${req.isAuthenticated()}`)
if(req.isAuthenticated()) {
res.send('you hit the authentication endpoint\n')
} else {
res.redirect('/')
}
})
// tell the server what port to listen on
app.listen(3000, () => {
console.log('Listening on localhost:3000')
})
Di atas Anda dapat melihat bahwa kami telah menambahkan route "/authrequired" yang tersedia melalui metode get yang memeriksa request object untuk melihat apakah req.isAuthenticated() benar. Ini adalah fungsi yang ditambahkan passport Anda ke request object. Mari masuk ke halaman beranda, buat session baru, dan gunakan session baru itu untuk membuka /route yang diperlukan.
Perhatikan bahwa request kedua di bawah ini melewati tanda "-L" curl yang memberi tahu cURL untuk mengikuti pengalihan.
client $ curl -X GET http://localhost:3000 -c cookie-file.txt
You got home page!
client $ curl -X GET http://localhost:3000/authrequired -b cookie-file.txt -L
You got home page!
Sekarang mari kita periksa log server.
#first request to the home page
Inside session middleware genid function
Request object sessionID from client: undefined
Inside the homepage callback
e6388389-0248-4c69-96d1-fda44fbc8839
#second request to the /authrequired route
Inside GET /authrequired callback
User authenticated? false
Anda dapat melihat di atas bahwa fungsi callback dari passport.deserializeUser() tidak tercapai karena tidak diautentikasi. Kemudian tekan route login lagi dan gunakan cookie-file.txt yang ada untuk menekan route / authrequired.
curl -X POST http://localhost:3000/login -b cookie-file.txt -H 'Content-Type: application/json' -d '{"email":"[email protected]", "password":"password"}'
You were authenticated & logged in!
curl -X GET http://localhost:3000/authrequired -b cookie-file.txt -L
you hit the authentication endpoint
Kali ini, kita dapat melihat bahwa kita telah mencapai endpoints otentikasi. Besar! Anda akan melihat yang berikut di log server:
Inside POST /login callback
Inside local strategy callback
Local strategy returned true
Inside passport.authenticate() callback
req.session.passport: undefined
req.user: undefined
Inside serializeUser callback. User id is save to the session file store here
Inside req.login() callback
req.session.passport: {"user":"2f24vvg"}
req.user: {"id":"2f24vvg","email":"[email protected]","password":"password"}
Inside deserializeUser callback
The user id passport saved in the session file store is: 2f24vvg
Inside GET /authrequired callback
User authenticated? true
Salah satu hal baru untuk ditunjukkan di sini adalah bahwa kami mendapatkan fungsi callback deserializeUser untuk mencocokkan sessionID dengan penyimpanan file session dan mendapatkan ID user.
Langkah 5 Hubungkan database dan tangani kredensial yang salah
Ini akan menjadi langkah besar lainnya! Pertama, mari buat folder lain bernama "db" di authTuts, inisialisasi npm, instal json-server dan buat file db.json baru.
authTuts $ mkdir db
authTuts $ cd db
db $ npm init -y
db $ npm install json-server --save
db $ touch db.json
Setelah json-server terinstal, mari tambahkan skrip "json: server" baru ke package.json.
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"json:server": "json-server --watch ./db.json --port 5000"
},
Jadi apa semua poinnya? json-server adalah paket yang secara otomatis menetapkan rute RESTful untuk data dalam file db.json. Mari kita coba. Salin dan tempel berikut ini ke file db.json Anda.
{
"users": [
{
"id":"2f24vvg",
"email": "[email protected]",
"password": "password"
},
{
"id":"d1u9nq",
"email": "[email protected]",
"password": "password"
}
]
}
Kemudian panggil "npm runjson: server" dari folder / db.
db $ npm run json:server
Kemudian buka http://localhost:5000/users di browser Anda. Anda akan melihat JSON dari file db.json kami menjadi output. Coba tekan route /user tertentu: http://localhost:5000/users/2f24vvg. Anda seharusnya hanya id, email, dan kata sandi untuk satu user itu. Mari kita coba lagi, tetapi alih-alih alihkan id user langsung ke URL, mari berikan melihat alamat email sebagai parameter kueri ke URL: http://localhost:5000/[email protected] Kali ini Anda harus mendapatkan objek JSON user ke-2 kami. Cukup keren, kan?!
biarkan json-server berjalan di tabnya sendiri di terminal, dan mari kembali ke tab terminal kita di folder server (atau buka yang baru jika perlu), dan mari instal axios, paket yang membantu mengambil data.
server $ npm install axios --save
Konfigurasi LocalStrategy menggunakan alamat email sebagai parameter kueri untuk mengambil objek user dari endpoints /user REST (seperti yang dilakukan sebelumnya secara manual). Sementara itu, perbarui konfigurasi Anda untuk menangani kredensial user yang tidak valid dan kesalahan yang dikembalikan oleh aksio dari server json.
Dalam fungsi passport.deserializeUser(), panggil aksioma untuk mendapatkan endpoints /user, berikan ID user di jalur (yaitu /user/:id), dan kembalikan objek user.
Selain itu, mari kita tangani berbagai kesalahan yang dapat terjadi selama otentikasi dengan fungsi callback passport.authenticate() dan mengarahkan user ke jalur /authrequired alih-alih hanya memberi tahu user bahwa mereka masuk.
//npm modules
const express = require('express');
const uuid = require('uuid/v4')
const session = require('express-session')
const FileStore = require('session-file-store')(session);
const bodyParser = require('body-parser');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const axios = require('axios');
// configure passport.js to use the local strategy
passport.use(new LocalStrategy(
{ usernameField: 'email' },
(email, password, done) => {
axios.get(`http://localhost:5000/users?email=${email}`)
.then(res => {
const user = res.data[0]
if (!user) {
return done(null, false, { message: 'Invalid credentials.\n' });
}
if (password != user.password) {
return done(null, false, { message: 'Invalid credentials.\n' });
}
return done(null, user);
})
.catch(error => done(error));
}
));
// tell passport how to serialize the user
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
axios.get(`http://localhost:5000/users/${id}`)
.then(res => done(null, res.data) )
.catch(error => done(error, false))
});
// create the server
const app = express();
// add & configure middleware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(session({
genid: (req) => {
return uuid() // use UUIDs for sessionIDs
},
store: new FileStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
app.use(passport.initialize());
app.use(passport.session());
// create the homepage route at '/'
app.get('/', (req, res) => {
res.send(`You got home page!\n`)
})
// create the login get and post routes
app.get('/login', (req, res) => {
res.send(`You got the login page!\n`)
})
app.post('/login', (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
if(info) {return res.send(info.message)}
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.login(user, (err) => {
if (err) { return next(err); }
return res.redirect('/authrequired');
})
})(req, res, next);
})
app.get('/authrequired', (req, res) => {
if(req.isAuthenticated()) {
res.send('you hit the authentication endpoint\n')
} else {
res.redirect('/')
}
})
// tell the server what port to listen on
app.listen(3000, () => {
console.log('Listening on localhost:3000')
})
Seperti disebutkan di atas, saya menghapus semua log di server. Sekarang setelah Anda memahami alur autentikasi, Anda tidak perlu mencatat semuanya. Ada sedikit kode baru di atas, tetapi seharusnya cukup mudah untuk memahami apa yang terjadi. Dalam kebanyakan kasus, Anda hanya perlu menambahkan pernyataan "jika" untuk menangani kesalahan.
Coba tekan endpoints login dengan request cURLPOST. Perhatikan bahwa kami mengecualikan flag "-XPOST" karena cURL mengikuti pengalihan dari route /login ke route /authrequired untuk mendapatkannya. Jika Anda meninggalkan tanda "-XPOST", itu juga akan mencoba untuk mengirim ke rute /authrequired. Sebagai gantinya, biarkan cURL menebak apa yang harus dilakukan dengan setiap rute.
client $ curl http://localhost:3000/login -c cookie-file.txt -H 'Content-Type: application/json' -d '{"email":"[email protected]", "password":"password"}' -L
you hit the authentication endpoint
Langkah 6) Menangani kata sandi terenkripsi
Pertama, mari kita instal bcrypt di server.
server $ npm install bcrypt-nodejs --save
Anda memerlukan ini di file server.js Anda dan menyebutnya dalam konfigurasi LocalStrategy Anda. Sekarang cocokkan kredensial yang dikirim oleh user dengan kredensial yang disimpan di backend. Pertama, masukkan kata sandi yang Anda terima dari user (harus berupa teks biasa). Argumen kedua adalah kata sandi hash yang disimpan dalam database.
//npm modules
const express = require('express');
const uuid = require('uuid/v4')
const session = require('express-session')
const FileStore = require('session-file-store')(session);
const bodyParser = require('body-parser');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const axios = require('axios');
const bcrypt = require('bcrypt-nodejs');
// configure passport.js to use the local strategy
passport.use(new LocalStrategy(
{ usernameField: 'email' },
(email, password, done) => {
axios.get(`http://localhost:5000/users?email=${email}`)
.then(res => {
const user = res.data[0]
if (!user) {
return done(null, false, { message: 'Invalid credentials.\n' });
}
if (!bcrypt.compareSync(password, user.password)) {
return done(null, false, { message: 'Invalid credentials.\n' });
}
return done(null, user);
})
.catch(error => done(error));
}
));
// tell passport how to serialize the user
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
axios.get(`http://localhost:5000/users/${id}`)
.then(res => done(null, res.data) )
.catch(error => done(error, false))
});
// create the server
const app = express();
// add & configure middleware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(session({
genid: (req) => {
return uuid() // use UUIDs for sessionIDs
},
store: new FileStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
app.use(passport.initialize());
app.use(passport.session());
// create the homepage route at '/'
app.get('/', (req, res) => {
res.send(`You got home page!\n`)
})
// create the login get and post routes
app.get('/login', (req, res) => {
res.send(`You got the login page!\n`)
})
app.post('/login', (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
if(info) {return res.send(info.message)}
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.login(user, (err) => {
if (err) { return next(err); }
return res.redirect('/authrequired');
})
})(req, res, next);
})
app.get('/authrequired', (req, res) => {
if(req.isAuthenticated()) {
res.send('you hit the authentication endpoint\n')
} else {
res.redirect('/')
}
})
// tell the server what port to listen on
app.listen(3000, () => {
console.log('Listening on localhost:3000')
})
Selanjutnya, Anda perlu memastikan bahwa kata sandi hash disimpan dalam database. Anda dapat menggunakan alat ini untuk meng-hash kata "kata sandi" dan menyimpan serta mengganti nilai kata sandi yang ada di file "db.json".
{
"users": [
{
"id":"2f24vvg",
"email": "[email protected]",
"password": "$2a$12$nv9iV5/UNuV4Mdj1Jf8zfuUraqboSRtSQqCmtOc4F7rdwmOb9IzNu"
},
{
"id":"d1u9nq",
"email": "[email protected]",
"password": "$2a$12$VHZ9aJ5A87YeFop4xVW.aOMm95ClU.EviyT9o0i8HYLdG6w6ctMfW"
}
]
}
Terakhir, coba masuk lagi.
client $ curl http://localhost:3000/login -c cookie-file.txt -H 'Content-Type: application/json' -d '{"email":"[email protected]", "password":"password"}' -L
you hit the authentication endpoint
Kamu sudah selesai!
Semoga Anda telah belajar sedikit lebih banyak tentang:
- Cara menggunakan Express dan middleware
- Cara menyimpan dan mengambil data session di server dan client
- Alur otentikasi passport dan cara menggunakannya untuk otentikasi
- Cara menggunakan bcrypt untuk menyusun teks biasa dengan kata sandi hash
Penambahan alur pendaftaran dibiarkan sebagai latihan. Namun, poin umumnya adalah sebagai berikut: Pastikan tidak ada user dalam database yang memiliki alamat email tersebut. Jika tidak, Anda dapat menggunakan axios.post() untuk menyimpan data di db.json (selalu bcrypt kata sandi) dan panggil req.login() pada objek user yang Anda buat.
Terakhir, jika Anda mencari informasi lebih lanjut, pastikan untuk merujuk ke dokumentasi.