Node.js編程中客戶(hù)端Session的使用詳解
靜態(tài)網(wǎng)站很容易擴(kuò)展。你只需要全部緩存,不需要考慮從不同服務(wù)器組合有狀態(tài)的內(nèi)容給用戶(hù)。
可惜,大多數(shù)Web應(yīng)用使用有狀態(tài)的內(nèi)容提供個(gè)性化體驗(yàn)。如果你的應(yīng)用可以登錄,就需要記住用戶(hù)的Session。經(jīng)典的處理方法是客戶(hù)端設(shè)置包含隨機(jī)唯一Session標(biāo)識(shí)的Cookie,被標(biāo)識(shí)的Session數(shù)據(jù)保存到服務(wù)端。
擴(kuò)展有狀態(tài)服務(wù)
當(dāng)擴(kuò)展服務(wù)的時(shí)候,你肯定有三種選擇:
- 不同服務(wù)端同步Session數(shù)據(jù)
- 不同服務(wù)端連接單點(diǎn)中心(獲取Session)
- 保證用戶(hù)訪(fǎng)問(wèn)同一個(gè)服務(wù)端
但都有缺陷:
- 同步數(shù)據(jù)增加性能開(kāi)銷(xiāo)
- 單點(diǎn)中心降低系統(tǒng)擴(kuò)展性
- 如果用戶(hù)上次訪(fǎng)問(wèn)的服務(wù)端需要維護(hù)怎么辦
然而,如果你換個(gè)角度思考,會(huì)發(fā)現(xiàn)第四種選擇:將Session數(shù)據(jù)保存在客戶(hù)端
客戶(hù)端Session
在客戶(hù)端保存Session有一些優(yōu)勢(shì):
- 無(wú)所謂哪個(gè)服務(wù)端,Session數(shù)據(jù)都有效
- 不需要維護(hù)服務(wù)端狀態(tài)
- 不需要服務(wù)端同步
- 任意添加新的服務(wù)端
但是客戶(hù)端Session存在一個(gè)嚴(yán)重問(wèn)題:你不能保證用戶(hù)不篡改Session數(shù)據(jù)。
比如你在Cookie中保存用戶(hù)的ID。用戶(hù)很容易修改它,從而訪(fǎng)問(wèn)別人的賬戶(hù)。
這似乎否定了客戶(hù)端Session的可能,但有一種方法可以巧妙解決這問(wèn)題:加密打包Session數(shù)據(jù)(還是存在Cookie中)。這樣就不需要擔(dān)心用戶(hù)修改Session數(shù)據(jù),服務(wù)端會(huì)驗(yàn)證數(shù)據(jù)的。
實(shí)際應(yīng)用上,就是Cookie中保存一個(gè)加密的Server Key。Server Key驗(yàn)證后才有權(quán)利讀取和修改Session數(shù)據(jù)。這就是客戶(hù)端Session。
Node客戶(hù)端Session
Node.JS有一個(gè)庫(kù)可以實(shí)現(xiàn)客戶(hù)端Session:node-client-session.它可以代替Connect(一個(gè)Node中間件框架)內(nèi)置的session和cookieParser中間件。
在Express框架應(yīng)用中的使用:
const clientSessions = require("client-sessions");
app.use(clientSessions({ secret: '0GBlJZ9EKBt2Zbi2flRPvztczCewBxXK' // 設(shè)置一個(gè)隨機(jī)長(zhǎng)字符串! })
然后,向req.session對(duì)象添加屬性:
app.get('/login', function (req, res){ req.session.username = 'JohnDoe'; });
讀取屬性:
app.get('/', function (req, res){ res.send('Welcome ' + req.session.username); });
使用reset方法終止Session:
app.get('/logout', function (req, res) { req.session.reset(); });
即時(shí)注銷(xiāo)Persona Session
(注:Persona是Mozzilla推出的網(wǎng)絡(luò)身份系統(tǒng))
與服務(wù)器端Session不同,客戶(hù)端Session的問(wèn)題是服務(wù)端無(wú)法刪除Session。
服務(wù)器端架構(gòu)時(shí),你可以刪除Session數(shù)據(jù)。任意的客戶(hù)端Cookie標(biāo)識(shí)的Session很可能不存在。但客戶(hù)端架構(gòu)時(shí),Session數(shù)據(jù)不在服務(wù)端,不能保證Session數(shù)據(jù)在每個(gè)客戶(hù)端都被刪除。換句話(huà)說(shuō),我們無(wú)法同步用戶(hù)的客戶(hù)端狀態(tài)(已經(jīng)登錄)和服務(wù)端狀態(tài)(注銷(xiāo)登錄)。
為了彌補(bǔ)這個(gè)缺陷,客戶(hù)端Session中添加了過(guò)期時(shí)間。展開(kāi)Session數(shù)據(jù)(被加密打包)前驗(yàn)證過(guò)期時(shí)間。如果過(guò)期了,拋棄Session數(shù)據(jù)并改變用戶(hù)狀態(tài)(如注銷(xiāo)登錄)。
過(guò)期機(jī)制在很多應(yīng)用中運(yùn)行良好(尤其是短過(guò)期時(shí)間需求)。如在Persona中,當(dāng)用戶(hù)發(fā)覺(jué)密碼收到威脅或已經(jīng)損壞時(shí),我們需要提供方法讓用戶(hù)立即注銷(xiāo)Session數(shù)據(jù)。
這意味著需要保留一點(diǎn)點(diǎn)狀態(tài)信息在服務(wù)后端。我們處理即時(shí)注銷(xiāo)的方法是添加一個(gè)Token在用戶(hù)數(shù)據(jù)表和Session數(shù)據(jù)中。
每次API調(diào)用時(shí)比對(duì)Session數(shù)據(jù)中的Token和數(shù)據(jù)庫(kù)中的Token。如果不相同,返回錯(cuò)誤信息并退出用戶(hù)。
這樣會(huì)附加多余的數(shù)據(jù)庫(kù)操作去查詢(xún)Token。幸好,大多數(shù)的API調(diào)用都需要讀取用戶(hù)數(shù)據(jù)表,把Token一起帶上就好了。
相關(guān)文章
gyp?ERR!報(bào)錯(cuò)問(wèn)題解決辦法
這篇文章主要給大家介紹了關(guān)于gyp?ERR!報(bào)錯(cuò)問(wèn)題的解決辦法,文中將解決的辦法介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-01-01
NPM命令運(yùn)行報(bào)錯(cuò):npm?v10.2.4?is?known?not?to?run?on?Node.js
這篇文章主要給大家介紹了關(guān)于NPM命令運(yùn)行報(bào)錯(cuò):npm?v10.2.4?is?known?not?to?run?on?Node.js?v14.21.1的解決辦法,文中將解決辦法介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01

