Express實(shí)現(xiàn)Session身份認(rèn)證的示例代碼
Cookie
HTTP
HTTP(Hyper Text Transfer Protocol,超文本傳輸模式)屬于無狀態(tài)協(xié)議,在同一個(gè)連接中,兩個(gè)執(zhí)行成功的請求之間是沒有關(guān)系的。這就帶來了一個(gè)問題,用戶沒有辦法在同一個(gè)網(wǎng)站中進(jìn)行連續(xù)的交互。例如:
在一個(gè)電商網(wǎng)站里,用戶把某個(gè)商品加入到購物車,切換一個(gè)頁面后再次添加了商品,這兩次添加商品的請求之間沒有關(guān)聯(lián),瀏覽器無法知道用戶最終選擇了哪些商品。而使用 HTTP 的標(biāo)頭(請求頭及響應(yīng)頭)擴(kuò)展,HTTP Cookie 就可以解決這個(gè)問題。把 Cookie 添加到標(biāo)頭中,創(chuàng)建一個(gè)會話讓每次請求都能共享相同的上下文信息,達(dá)成相同的狀態(tài)。
Cookie
Cookie 是一段不超過 4KB 的小型文本數(shù)據(jù),由一個(gè)名稱(Name)以及其對應(yīng)的值(Value)和其它幾個(gè)用于控制 Cookie 有效期、安全性、使用范圍的可選屬性組成。
服務(wù)器端
如果一個(gè)客戶是首次登錄該網(wǎng)頁的,那么在本次登錄成功后,服務(wù)器端將向客戶端發(fā)送一個(gè) Cookie ,其中保存了用戶的登錄信息。
客戶端
Cookie 保存了你的登錄信息,瀏覽器會通過域名來劃分瀏覽器中所有的 Cookie。在你訪問一個(gè)網(wǎng)頁時(shí),瀏覽器會首先查看瀏覽器中是否存儲了與該域名相關(guān)的 Cookie。如果存在,則在向該域名發(fā)起請求時(shí)將攜帶與該域名相關(guān)的所有的未過期 Cookie。
Session
Session 是基于 Cookie 的,但服務(wù)器生成的 Cookie 是一段無意義的字符串(稱為 SessionID)。在訪問網(wǎng)頁時(shí)你將發(fā)送與該網(wǎng)頁相關(guān)的 Cookie,即 SessionID。服務(wù)器端接收到該數(shù)據(jù)后將在服務(wù)器中查詢與該 SessionID 相關(guān)的 Session 對象并通過該對象中存儲的用戶信息來決定對該客戶端的行為。
Session VS Cookie
- Session 將用戶信息存儲在服務(wù)器端,而 Cookie 將用戶信息存儲在客戶端。因此,Cookie 不適合用于保存重要的數(shù)據(jù)。
- Session 將用戶數(shù)據(jù)保存在服務(wù)器端,這會導(dǎo)致服務(wù)器端的工作量增大。
- 攻擊者可以通過分析 Cookie 中的數(shù)據(jù)來進(jìn)行 Cookie 欺騙。而使用 Session 進(jìn)行身份認(rèn)證時(shí),用戶的相關(guān)信息保存在服務(wù)器中,因此不用擔(dān)心會被欺騙。
Express 實(shí)現(xiàn) Session 身份認(rèn)證
獲取
在 Express 中,如果你希望使用 Session 進(jìn)行身份認(rèn)證,你可以通過第三方中間件 express-session 來實(shí)現(xiàn)。如果你使用的是 npm(NodeJS Package Manager) 包管理器,那么你可以通過如下命令來下載并安裝第三方中間件:
npm install express-session
配置
// 導(dǎo)入第三方提供的 express-session 中間件 const session = require('express-session'); // 配置 express-session 中間件 app.use(session({ ? ? secret: 'RedHeart', ? ? resave: false, ? ? saveUninitialized: true }))
其中:
- app.use() 函數(shù)用于將中間件注冊為全局中間件。對于客戶端發(fā)送到服務(wù)器端的任意類型的請求,如果該請求中沒有包含 Cookie,服務(wù)器端將向該客戶端發(fā)送 Cookie 。
- 對于傳遞給中間件函數(shù) session() 的參數(shù)對象,有:
項(xiàng)目 | 描述 |
---|---|
secret | 用于為生成的 SessionID 進(jìn)行簽名。 |
name | 用于設(shè)置發(fā)送到客戶端的 Cookie 的名稱。 |
對于 resave: false 及 saveUninitialized: true 的作用 還沒有搞清楚,但網(wǎng)上的相關(guān)資料均推薦這樣設(shè)置。
登錄
const express = require('express'); // 導(dǎo)入第三方提供的 express-session 中間件 const session = require('express-session'); const app = express(); // 監(jiān)聽本機(jī) 9090 端口 app.listen(9090); // 配置 express-session 中間件 app.use(session({ ? ? secret: 'RedHeart', ? ? resave: false, ? ? saveUninitialized: true })) // 設(shè)置登錄頁面的路由 app.get('/login', (req, res) => { ? ? // 判斷 GET 請求中的查詢字符串中的參數(shù)的值是否符合要求 ? ? if(req.query.username === 'redheart' && req.query.password === 'twomoons'){ ? ? ? ? // 將用戶信息添加至 Session 中 ? ? ? ? req.session.user = req.query; ? ? ? ? // 標(biāo)記當(dāng)前用戶目前處于登錄狀態(tài) ? ? ? ? req.session.isLogin = true; ? ? ? ? res.send('{ WIN }') ? ? }else{ ? ? ? ? res.send('{ LOSE }'); ? ? } })
執(zhí)行效果
在執(zhí)行上述代碼后,你可以通過訪問 http://127.0.0.1:9090/login/?username=redheart&password=twomoons 來進(jìn)行登錄。嘗試登錄后,若頁面中顯現(xiàn)字符串 { WIN } ,表明該用戶已經(jīng)登錄成功。
主頁
向前一個(gè)示例中添加如下代碼:
// 設(shè)置主頁路由 app.get('/home', (req, res) => { // 判斷客戶端的 Session 狀態(tài)是否為 true // 如果服務(wù)器端還未為該客戶端分配 SessionID // 則 req.session.isLogin 為 undefined 。 if(req.session.isLogin){ res.send('{ WIN }'); }else{ res.send('{ LOSE }'); } })
執(zhí)行效果
在通過訪問 http://127.0.0.1:9090/login/?username=redheart&password=twomoons 登錄成功后,訪問 http://127.0.0.1:9090/home 你將于頁面中觀察到字符串 { WIN }。你可以嘗試刷新該頁面,你會發(fā)現(xiàn)顯示的字符串并沒有變成 { LOSE },這說明服務(wù)器端已經(jīng)通過 SessionID 記住了你。
退出登錄
你可以通過調(diào)用 req.session.destroy() 來清除 當(dāng)前 客戶端保存在服務(wù)器端的 Session 數(shù)據(jù)。SessionID 仍保存在客戶端瀏覽器中,但已經(jīng)失效。
app.get('/logout', (req, res) => { req.session.destroy(); res.send('{ WIN }'); })
代碼總匯
const express = require('express'); // 導(dǎo)入第三方提供的 express-session 中間件 const session = require('express-session'); const app = express(); // 監(jiān)聽本機(jī) 9090 端口 app.listen(9090); // 配置 express-session 中間件 app.use(session({ ? ? secret: 'RedHeart', ? ? resave: false, ? ? saveUninitialized: true })) // 設(shè)置主頁路由 app.get('/home', (req, res) => { ? ? // 判斷客戶端的 Session 狀態(tài)是否為 true ? ? // 如果服務(wù)器端還未為該客戶端分配 SessionID ? ? // 則 req.session.isLogin 為 undefined 。 ? ? if(req.session.isLogin){ ? ? ? ? res.send('{ WIN }'); ? ? }else{ ? ? ? ? res.send('{ LOSE }'); ? ? } }) // 設(shè)置登錄頁面的路由 app.get('/login', (req, res) => { ? ? // 判斷 GET 請求中的查詢字符串中的參數(shù)的值是否符合要求 ? ? if(req.query.username === 'redheart' && req.query.password === 'twomoons'){ ? ? ? ? // 將用戶信息添加至 Session 中 ? ? ? ? req.session.user = req.query; ? ? ? ? // 標(biāo)記當(dāng)前用戶目前處于登錄狀態(tài) ? ? ? ? req.session.isLogin = true; ? ? ? ? res.send('{ WIN }') ? ? }else{ ? ? ? ? res.send('{ LOSE }'); ? ? } }) app.get('/logout', (req, res) => { ? ? req.session.destroy(); ? ? res.send('{ WIN }'); })
到此這篇關(guān)于Express實(shí)現(xiàn)Session身份認(rèn)證的示例代碼的文章就介紹到這了,更多相關(guān)Express Session身份認(rèn)證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用nginx + node在阿里云部署https的步驟詳解
這篇文章主要給大家介紹了關(guān)于利用nginx + node在阿里云部署https的步驟,文中通過圖文及示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12node自定義安裝更改npm全局模塊默認(rèn)安裝路徑的步驟
有段時(shí)間沒用npm了,新建個(gè)項(xiàng)目,需要改變npm全局包默認(rèn)安裝的路徑,本文就來介紹一下node自定義安裝更改npm全局模塊默認(rèn)安裝路徑的步驟,感興趣的可以了解下2021-09-09node.js學(xué)習(xí)之?dāng)嘌詀ssert的使用示例
assert 模塊主要用于編寫程序的單元測試時(shí)使用,通過斷言可以提早發(fā)現(xiàn)和排查出錯(cuò)誤。下面這篇文章主要給大家介紹了關(guān)于node.js學(xué)習(xí)之?dāng)嘌詀ssert的相關(guān)資料,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09Node.js實(shí)現(xiàn)分片上傳斷點(diǎn)續(xù)傳示例詳解
這篇文章主要為大家介紹了Node.js實(shí)現(xiàn)分片上傳斷點(diǎn)續(xù)傳示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07