NUK JavaScript Lesson 12:在 Express 上應用 Session 實作登入功能
本篇筆記會介紹如何在 Express 上使用 express-session 模組來應用 Session,並實作出會員登入功能。
什麼是 Session
以 Facebook 為例,一般來說我們可以在 Console → Application → Cookies 中取得 c_user
,也就是使用者編號 (ID),這時只要再取得登入狀態 (spin
) 與 xs
就能成功登入帳號。
而在我們登入後,因為有 Session 的關係,所以這個帳號只有在網頁或伺服器重新啟動時,才會重置資料,像這種應用就是 Session 的普遍的使用方式。
express-session 簡單介紹
想要在 Express 中實作出 Session 的效果,可以使用第三方模組 express-session。
安裝:
npm install express-session --save
初始化設定:在 app.js 撰寫以下的程式碼
1
2
3
4
5
6
7
8
9var session = require('express-session'); // 讓 Express 有 Session 的功能
app.use(
session({
secret: '1q3rrwefsgdh54uu5h56', // 加密
resave: false,
saveUninitialized: true,
cookie: { maxAge: 1000 * 15 }, // 時間可更改
})
);接下來就透過一些實作練習,來開始使用 express-session 吧!
實作應用:登入功能
假登入
實作功能:登入後記錄 Cookie,過一段時間後清除。
在 index.js 增加兩個路由,來測試 Session
1
2
3
4
5
6
7
8
9
10
11
12
13
14// (2) 取得 Server 端的 Session
router.get('/', function (req, res, next) {
res.render('index', {
title: 'express',
name: req.session.name,
password: req.session.password,
});
// (1) 自訂 Session 到 Server 端儲存
router.post('/', function (req, res) {
// 自訂瀏覽器"暫時"要寫什麼資訊進去
req.session.name = req.body.name;
req.session.password = req.body.password;
res.redirect('/')
})製作 index.ejs 呈現 Session 的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14<!-- ...omit -->
<body>
<p><%= name %></p>
<p><%= password %></p>
<p><%= memberId %></p>
<h2>假登入</h2>
<!-- 傳送兩個值 name, email -->
<form action="/" method="post">
<input type="text" name="name" value="">
<input type="text" name="password" value="">
<input type="submit" name="" value="送出">
</form>
</body>
<!-- omit... -->完成後開啟
http://localhost:3000/
進行假登入,輸入的帳號密碼會作為 Session 顯示在標題上方。
不過這只是假的登入功能,因為我們沒有連接到資料庫做驗證。
真正的登入應該還要經過 Server 端的資料庫做驗證、比對帳密後,才能完成登入的動作。
真登入
我們可以透過 Firestore 建立假資料庫,使用我們自訂的帳密做驗證比對,實作出真正的登入功能。
Firestore + express-session
為 index.ejs 新增真登入的表單欄位
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<!-- ...omit -->
<body>
<p><%= name %></p>
<p><%= password %></p>
<p><%= memberId %></p>
<h2>假登入</h2>
<form action="/" method="post">
<input type="text" name="name" value="">
<input type="text" name="password" value="">
<input type="submit" name="" value="送出">
</form>
<h2>真登入</h2>
<form action="/login" method="post">
<input type="text" name="name" value="">
<input type="text" name="password" value="">
<input type="submit" name="" value="送出">
</form>
</body>
<!-- omit... -->在 index.js 中使用 Firestore 加上 express-session 製作登入的路由
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18router.post('/login', function (req, res) {
var memberRef = db.collection('member');
memberRef
.where('account', '==', req.body.name)
.get()
.then(function (querySnapshot) {
querySnapshot.forEach(function (doc) {
// 以下三行是測試用的
console.log(doc.data().password == req.body.password);
console.log(doc.data().password);
console.log(req.body.password);
if (doc.data().password == req.body.password) {
req.session.memberId = doc.id;
res.redirect('/');
}
});
});
});- 資料驗證方式:
當資料庫裡的account
與該筆表單送出的name
相同時,再去驗證資料庫裡的password
是否也與表單的password
相同。
如果都符合,就把資料庫的該筆文件的id
當作memberId
一併呈現於畫面上。
- 資料驗證方式:
練習題:取得會員的購物清單
實作功能:會員登入後,列出該位會員的產品購買清單。
重要觀念整理
doc.data()
會回傳該筆文件的整個內容,可再存取doc.data().name
與doc.data().password
等個別欄位的資料內容。doc.id
會指向該筆文件的 ID,像是4NK3b5G0wf5jOLo62pN8
這種亂碼。let docRef = db.collection("member").doc("singleObjectWithDataFields")
的.doc()
是指向該筆文件的 “參考”。
在開始之前,要先建立好資料集,以下為會員購物清單 orderlist
資料集的截圖。
最左邊是每個會員的亂碼 ID,每個會員除了有基本資料的欄位外,都還有一個集合 orderlist
,這是代表他們每個人的購物清單。
如果想要存取到 orderlist
裡面的文件內容,可以透過這段程式碼來取得:let orderlistRef = db.collection("member").doc(doc.id).collection("orderlist")
。
實作步驟說明
- 透過
db.collection("member")
存取 member 資料集內的文件 doc.id
等於每一位會員的亂碼 ID- 接著的
.doc(doc.id)
即可取得該 ID 的參考位置 - 再透過
.collection("orderlist")
取得參考位置裡的資料集orderlist
- 用空陣列
orderData
接取文件裡的購買資料
最後我們就把需要的資料 render
出來,讓 member.ejs 替我們渲染出結果。
透過兩次取得資料集的方式,我們就能成功拿到包在資料集裡面的資料集的資料囉!
範例程式碼
member.ejs
1 | <!-- ...omit --> |
index.js
1 | router.post('/login', function (req, res) { |
以上資源是我自己整理過後的筆記,若有錯誤歡迎隨時和我聯繫。