項目要用到登錄註冊,就需要使用到Cookie和Session來保持登錄狀態,於是就簡單研究了一下
Cookie和Session的工作原理
前面已經專門發過一篇帖子記錄Cookie和Session的工作原理了,不明白的小夥伴可以看看Cookie、Session是如何保持登錄狀態的?。
使用Koa的Session中間件
Koa是一個簡潔的框架,把許多小功能都拆分成了中間件,用一個洋蔥模型保證了中間件豐富的可拓展性,我們要使用Session來保持登錄狀態,就需要引用Session中間件。
安裝Koa-Session中間件
npm install koa-session --save
如果需要使用TypeScript進行開發,則需要引入對應的TS類型聲明
npm install @types/koa-session --save
配置Session
Koa-Session需要做一些配置:
const session_signed_key = ["some secret hurr"]; // 這個是配合signed屬性的簽名key
const session_config = {
key: 'koa:sess', /** cookie的key。 (默認是 koa:sess) */
maxAge: 4000, /** session 過期時間,以毫秒ms爲單位計算 。*/
autoCommit: true, /** 自動提交到響應頭。(默認是 true) */
overwrite: true, /** 是否允許重寫 。(默認是 true) */
httpOnly: true, /** 是否設置HttpOnly,如果在Cookie中設置了"HttpOnly"屬性,那麼通過程序(JS腳本、Applet等)將無法讀取到Cookie信息,這樣能有效的防止XSS攻擊。 (默認 true) */
signed: true, /** 是否簽名。(默認是 true) */
rolling: true, /** 是否每次響應時刷新Session的有效期。(默認是 false) */
renew: false, /** 是否在Session快過期時刷新Session的有效期。(默認是 false) */
};
我們需要關注這幾個配置:
- renew rolling
這兩個都可以在用戶訪問的過程中刷新有效期,不至於讓用戶訪問過程中Session過期成爲未登錄狀態
- signed
這個是對客戶端Cookie的簽名,也就是用一個特點的字符加密,保證客戶端Cookie不會被僞造出來
- httpOnly
打開這個使得通過程序(JS腳本、Applet等)無法讀取Cookie,大大提高了安全性
- maxAge
以ms爲單位的過期時間
簡單的使用
首先理一下思路
- 判斷訪問者的Session有沒有過登錄記錄屬性
- 如果有且值爲true,則爲已登錄,否則爲未登錄
- 如果爲已登錄,則不執行判斷,直接返回已登錄,如果爲未登錄,則執行下一步登錄驗證
- 如果驗證成功,則返回的登錄成功,並且在它的session中記下登錄屬性爲true,如果驗證失敗,則返回登錄失敗。
爲了測試方便,以下用Get請求和一個固定的賬號密碼代替數據庫查詢,實際開發應該使用POST和數據庫比對。同時爲了測試方便,將過期時間設置爲4000ms,便於快速看到Cookies過期,實際開發應該設置長一些,比如幾小時甚至幾天,取決於業務需求。
const Koa = require('koa'); // 導入Koa
const Koa_Session = require('koa-session'); // 導入koa-session
// 配置
const session_signed_key = ["some secret hurr"]; // 這個是配合signed屬性的簽名key
const session_config = {
key: 'koa:sess', /** cookie的key。 (默認是 koa:sess) */
maxAge: 4000, /** session 過期時間,以毫秒ms爲單位計算 。*/
autoCommit: true, /** 自動提交到響應頭。(默認是 true) */
overwrite: true, /** 是否允許重寫 。(默認是 true) */
httpOnly: true, /** 是否設置HttpOnly,如果在Cookie中設置了"HttpOnly"屬性,那麼通過程序(JS腳本、Applet等)將無法讀取到Cookie信息,這樣能有效的防止XSS攻擊。 (默認 true) */
signed: true, /** 是否簽名。(默認是 true) */
rolling: true, /** 是否每次響應時刷新Session的有效期。(默認是 false) */
renew: false, /** 是否在Session快過期時刷新Session的有效期。(默認是 false) */
};
// 實例化
const app = new Koa();
const session = Koa_Session(session_config, app)
app.keys = session_signed_key;
// 使用中間件,注意有先後順序
app.use(session);
app.use(ctx => {
const databaseUserName = "testSession";
const databaseUserPasswd = "noDatabaseTest";
// 對/favicon.ico網站圖標請求忽略
if (ctx.path === '/favicon.ico') return;
if (!ctx.session.logged) { // 如果登錄屬性爲undefined或者false,對應未登錄和登錄失敗
// 設置登錄屬性爲false
ctx.session.logged = false;
// 取請求url解析後的參數對象,方便比對
// 如?nickname=post修改&passwd=123解析爲{nickname:"post修改",passwd:"123"}
let query = ctx.request.query;
// 判斷用戶名密碼是否爲空
if (query.nickname && query.passwd) {
// 比對並分情況返回結果
if (databaseUserName == query.nickname) { // 如果存在該用戶名
// 進行密碼比對並返回結果
ctx.body = (databaseUserPasswd == query.passwd) ? "登錄成功" : "用戶名或密碼錯誤";
ctx.session.logged = true;
} else { // 如果不存在該用戶名 // 如果用戶名不存在
ctx.body = "用戶名不存在";
}
} else {
ctx.body = "用戶名密碼不能爲空";
}
} else {
ctx.body = "已登錄";
}
}
);
app.listen(3000);
console.log("Koa運行在:http://127.0.0.1:3000");
運行一下,控制檯輸出:
Koa運行在:http://127.0.0.1:3000
訪問http://127.0.0.1:3000,可以看到我們沒有填寫登錄參數,然後返回了用戶名密碼不能空,並且按下F12,點擊Cookies再點擊http://127.0.0.1:3000,看到了我們的SessionId被記錄到了Cookies中,說明Session生效了。
我們靜置一會但不刷新頁面,再點擊Cookies後重新點擊,http://127.0.0.1:3000(刷新Cookies顯示),發現我們的SessionId不見了,說明我們的過期時間也生效了
我將Cookies的數據截詳細一點就是這樣的,可以看到有個過期時間:
我們再訪問http://127.0.0.1:3000/?nickname=123和http://127.0.0.1:3000/?passwd=123,都輸出了
訪問http://127.0.0.1:3000/?nickname=123&&passwd=123,輸出
訪問http://127.0.0.1:3000/?nickname=testSession&&passwd=123,輸出
最後嘗試正確的用戶名密碼http://127.0.0.1:3000/?nickname=testSession&&passwd=noDatabaseTest
,輸出
嘗試再次訪問http://127.0.0.1:3000/?nickname=testSession&&passwd=noDatabaseTest
,輸出
在有效期限內訪問別的頁面http://127.0.0.1:3000/,輸出
有效期內不斷刷新就能保持登錄狀態
有效期內沒有重新操作頁面刷新狀態就會自然過期