Nodejs中的JWT和Session

最近的項(xiàng)目需要在node服務(wù)端做一個(gè)用戶登錄的校驗(yàn)以及權(quán)限攔截轴咱,專業(yè)一點(diǎn)叫用戶認(rèn)證與授權(quán)锡宋,經(jīng)過一番收集資料盟猖,目前常用的有兩種——JWTSession

使用JWT

JWTJsonWebTokens的簡寫形式州藕,具體是啥我就不詳細(xì)寫了纽门,可以查看資料急鳄。
這里引入兩個(gè)插件谤民,express-jwt和JsonWebTokens,-

  • JsonWebTokens:用作生成token
  • express-jwt:用作驗(yàn)證指定http請求的JsonWebTokens的有效性疾宏,如果有效就將JsonWebTokens的值設(shè)置到req.user里面张足,然后路由到相應(yīng)的router

express-jwt內(nèi)部引用了jsonwebtoken,對其封裝使用坎藐。使用JWT形式進(jìn)行認(rèn)證與授權(quán)的思路如下为牍。
jwt認(rèn)證流程

服務(wù)端中使用方式如下:

//安裝
npm i jsonwebtoken --save
npm i express-jwt --save

//引入
const jwt= require('jsonwebtoken');
const expressJwt = require('express-jwt');

//定義簽名
const secret = 'salt';
//生成token
const token = jwt.sign({
    name: 123
}, secret, {
    expiresIn:  60 //秒到期時(shí)間
});
//生成的token
//eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxMjMsImlhdCI6MTQ5MTQ3NTQyNCwiZXhwIjoxNDkxNDc1NDg0fQ.hYNC4qFAyhZClmPaLixfN137d41R2CFk1xPlfLK10JU

//使用中間件驗(yàn)證token合法性
app.use(expressJwt ({
    secret:  secret 
}).unless({
    path: ['/login', '/getUserInfo']  //除了這些地址,其他的URL都需要驗(yàn)證
}));

//攔截器
app.use(function (err, req, res, next) {
    //當(dāng)token驗(yàn)證失敗時(shí)會(huì)拋出如下錯(cuò)誤
    if (err.name === 'UnauthorizedError') {   
        //這個(gè)需要根據(jù)自己的業(yè)務(wù)邏輯來處理( 具體的err值 請看下面)
        res.status(401).send('invalid token...');
    }
});

//定義一個(gè)接口岩馍,返回token給客戶端
app.get('/getUserInfo', function(req, res) {
    res.json({
        token: token
    })
})

客戶端中使用token的正確形式應(yīng)該是把token放在authorization 這個(gè)header里碉咆, 對應(yīng)的值以Bearer開頭然后空一格

authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiQmluTWFpbmciLCJkYXRhIjoiPT09PT09PT09PT09PSIsImlhdCI6MTUwMTgxNDE4OCwiZXhwIjoxNTAxODE0MjQ4fQ.GoxGlc6E02W5VvqDNawaOrj3MPO-4UYeFdngKR4bVTE

//采用axios可以這么寫
const instance = axios.create();
const yourToken = 'sfsgagfdgd';
//設(shè)置請求攔截器
instance.interceptors.request.use(function(config) {
    config.headers.authorization = `Bearer ${yourToken}` 
    return config;
})

使用Session

傳統(tǒng)的認(rèn)證和用戶識別分別采用如下形式

  • 服務(wù)端:創(chuàng)建一個(gè)session對象保存用戶登錄信息和狀態(tài),該對象有唯一ID蛀恩,并返回一個(gè)cookie給客戶端
  • 客戶端:請求api時(shí)發(fā)送http頭部自動(dòng)帶上cookie

這里使用cookie的方式需要引入兩個(gè)插件:

  • express-session:node端的session中間件疫铜,主要用作配置session的屬性并生成
  • cookie-parser:node端解析cookie對象

使用思路和JWT差不多,這里主要的區(qū)別在于客戶端請求資源時(shí)不用手動(dòng)在http請求的header添加標(biāo)識双谆,瀏覽器會(huì)自動(dòng)加上cookie壳咕,具體使用方式如下

var express = require('express');
var cookieParser = require('cookie-parser');
var session = require('express-session');
 
app.use(cookieParser('sessiontest'));
app.use(session({
    secret: 'sessiontest',//與cookieParser中的一致
    resave: true,    //(是否允許)當(dāng)客戶端并行發(fā)送多個(gè)請求時(shí),其中一個(gè)請求在另一個(gè)請求結(jié)束時(shí)對session進(jìn)行修改覆蓋并保存顽馋。
    rolling: true,    //強(qiáng)制在每個(gè)響應(yīng)中重設(shè)cookie的過期時(shí)間谓厘,并重新開始計(jì)時(shí)
    saveUninitialized:true,    //初始化session時(shí)是否保存到存儲(chǔ)。默認(rèn)為true寸谜, 但是(后續(xù)版本)有可能默認(rèn)失效竟稳,所以最好手動(dòng)添加。
    cookie: {
        maxAge: 60 * 1000  //過期時(shí)間熊痴,單位毫秒
    }
}));

/**
 * 資源請求攔截器
 * 用戶端若登錄狀態(tài)過期或未登錄則自動(dòng)拋出錯(cuò)誤
 */
app.use(function(req, res, next) {
    let url = req.originalUrl;
    req.session.touch();  //刷新session過期時(shí)間
    if (url !== '/login' && !req.session.user) {
        res.status(401).send('登錄狀態(tài)已過期');
        return
    }
    next();
})

對比

作為一個(gè)實(shí)踐派人士他爸,我把兩種都試了一遍,同時(shí)結(jié)合網(wǎng)上的博客歸納了如下對比

  • JWT無狀態(tài)果善,可擴(kuò)展和解耦诊笤。使用JWT不需要后端進(jìn)行記錄,每個(gè)token都是獨(dú)立的岭埠。而session的誕生就是為了解決http無狀態(tài)的問題盏混,這也就說明服務(wù)端是有存儲(chǔ)每個(gè)用戶對應(yīng)的session對象的蔚鸥,擴(kuò)展性會(huì)更繁瑣些
  • 跨域和CORS。每次發(fā)送請求到后端都需要檢查JWT许赃,只要驗(yàn)證通過就能處理請求止喷。而Cookie只能在單域和子域中發(fā)揮作用
  • JWT生成消耗一定的內(nèi)存,而且體積較大混聊,最小的它都比cookie要大弹谁,如果JWT里包含了許多聲明,那問題就比較嚴(yán)重了句喜,由于每次向服務(wù)器發(fā)起請求都要攜帶token预愤,太大了會(huì)造成請求緩慢
  • session比JWT好的地方在于在請求時(shí)瀏覽器會(huì)自動(dòng)帶http頭部帶上cookie,并且在用戶持續(xù)使用時(shí)會(huì)不斷地刷新session的過期時(shí)間咳胃,當(dāng)瀏覽器關(guān)閉時(shí)自動(dòng)清除session植康。相比之下JWT本身沒法做到隨著用戶的使用而更新或手動(dòng)清除,只能等自動(dòng)過期
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末展懈,一起剝皮案震驚了整個(gè)濱河市销睁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌存崖,老刑警劉巖冻记,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異来惧,居然都是意外死亡冗栗,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門供搀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來隅居,“玉大人,你說我怎么就攤上這事趁曼【” “怎么了棕洋?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵挡闰,是天一觀的道長。 經(jīng)常有香客問我掰盘,道長摄悯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任愧捕,我火速辦了婚禮奢驯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘次绘。我一直安慰自己瘪阁,他們只是感情好撒遣,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著管跺,像睡著了一般义黎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上豁跑,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天廉涕,我揣著相機(jī)與錄音,去河邊找鬼艇拍。 笑死狐蜕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的卸夕。 我是一名探鬼主播层释,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼快集!你這毒婦竟也來了湃累?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤碍讨,失蹤者是張志新(化名)和其女友劉穎治力,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體勃黍,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宵统,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了覆获。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片马澈。...
    茶點(diǎn)故事閱讀 40,115評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖弄息,靈堂內(nèi)的尸體忽然破棺而出痊班,到底是詐尸還是另有隱情,我是刑警寧澤摹量,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布涤伐,位于F島的核電站,受9級特大地震影響缨称,放射性物質(zhì)發(fā)生泄漏凝果。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一睦尽、第九天 我趴在偏房一處隱蔽的房頂上張望器净。 院中可真熱鬧,春花似錦当凡、人聲如沸山害。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽浪慌。三九已至柑晒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間眷射,已是汗流浹背匙赞。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留妖碉,地道東北人涌庭。 一個(gè)月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像欧宜,于是被迫代替她去往敵國和親坐榆。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容