來自:掘金(作者:秋天不落葉)
原文鏈接:https://juejin.im/post/6844904034181070861
什么是認(rèn)證(Authentication)
通俗地講就是驗(yàn)證當(dāng)前用戶的身份缅阳,證明“你是你自己”(比如:你每天上下班打卡磕蛇,都需要通過指紋打卡,當(dāng)你的指紋和系統(tǒng)里錄入的指紋相匹配時(shí)十办,就打卡成功)
互聯(lián)網(wǎng)中的認(rèn)證:
用戶名密碼登錄
郵箱發(fā)送登錄鏈接
手機(jī)號(hào)接收驗(yàn)證碼
只要你能收到郵箱/驗(yàn)證碼秀撇,就默認(rèn)你是賬號(hào)的主人
什么是授權(quán)(Authorization)
用戶授予第三方應(yīng)用訪問該用戶某些資源的權(quán)限
你在安裝手機(jī)應(yīng)用的時(shí)候,APP 會(huì)詢問是否允許授予權(quán)限(訪問相冊(cè)向族、地理位置等權(quán)限)
你在訪問微信小程序時(shí)呵燕,當(dāng)?shù)卿洉r(shí),小程序會(huì)詢問是否允許授予權(quán)限(獲取昵稱件相、頭像再扭、地區(qū)、性別等個(gè)人信息)
實(shí)現(xiàn)授權(quán)的方式有:cookie夜矗、session泛范、token、OAuth
什么是憑證(Credentials)
實(shí)現(xiàn)認(rèn)證和授權(quán)的前提是需要一種媒介(證書) 來標(biāo)記訪問者的身份
在戰(zhàn)國(guó)時(shí)期紊撕,商鞅變法罢荡,發(fā)明了照身帖。照身帖由官府發(fā)放对扶,是一塊打磨光滑細(xì)密的竹板区赵,上面刻有持有人的頭像和籍貫信息。國(guó)人必須持有辩稽,如若沒有就被認(rèn)為是黑戶惧笛,或者間諜之類的。
在現(xiàn)實(shí)生活中逞泄,每個(gè)人都會(huì)有一張專屬的居民身份證,是用于證明持有人身份的一種法定證件。通過身份證喷众,我們可以辦理手機(jī)卡/銀行卡/個(gè)人貸款/交通出行等等各谚,這就是認(rèn)證的憑證。
在互聯(lián)網(wǎng)應(yīng)用中到千,一般網(wǎng)站(如掘金)會(huì)有兩種模式昌渤,游客模式和登錄模式。游客模式下憔四,可以正常瀏覽網(wǎng)站上面的文章膀息,一旦想要點(diǎn)贊/收藏/分享文章,就需要登錄或者注冊(cè)賬號(hào)了赵。當(dāng)用戶登錄成功后潜支,服務(wù)器會(huì)給該用戶使用的瀏覽器頒發(fā)一個(gè)令牌(token),這個(gè)令牌用來表明你的身份柿汛,每次瀏覽器發(fā)送請(qǐng)求時(shí)會(huì)帶上這個(gè)令牌冗酿,就可以使用游客模式下無法使用的功能。
什么是 Cookie
HTTP 是無狀態(tài)的協(xié)議(對(duì)于事務(wù)處理沒有記憶能力络断,每次客戶端和服務(wù)端會(huì)話完成時(shí)裁替,服務(wù)端不會(huì)保存任何會(huì)話信息):每個(gè)請(qǐng)求都是完全獨(dú)立的,服務(wù)端無法確認(rèn)當(dāng)前訪問者的身份信息貌笨,無法分辨上一次的請(qǐng)求發(fā)送者和這一次的發(fā)送者是不是同一個(gè)人弱判。所以服務(wù)器與瀏覽器為了進(jìn)行會(huì)話跟蹤(知道是誰在訪問我),就必須主動(dòng)的去維護(hù)一個(gè)狀態(tài)锥惋,這個(gè)狀態(tài)用于告知服務(wù)端前后兩個(gè)請(qǐng)求是否來自同一瀏覽器昌腰。而這個(gè)狀態(tài)需要通過 cookie 或者 session 去實(shí)現(xiàn)。
cookie 存儲(chǔ)在客戶端: cookie 是服務(wù)器發(fā)送到用戶瀏覽器并保存在本地的一小塊數(shù)據(jù)净刮,它會(huì)在瀏覽器下次向同一服務(wù)器再發(fā)起請(qǐng)求時(shí)被攜帶并發(fā)送到服務(wù)器上剥哑。
cookie 是不可跨域的: 每個(gè) cookie 都會(huì)綁定單一的域名,無法在別的域名下獲取使用淹父,一級(jí)域名和二級(jí)域名之間是允許共享使用的(靠的是 domain)株婴。
cookie 重要的屬性
什么是 Session
session 是另一種記錄服務(wù)器和客戶端會(huì)話狀態(tài)的機(jī)制
session 是基于 cookie 實(shí)現(xiàn)的,session 存儲(chǔ)在服務(wù)器端暑认,sessionId 會(huì)被存儲(chǔ)到客戶端的cookie 中
session 認(rèn)證流程:
用戶第一次請(qǐng)求服務(wù)器的時(shí)候困介,服務(wù)器根據(jù)用戶提交的相關(guān)信息,創(chuàng)建對(duì)應(yīng)的 Session
請(qǐng)求返回時(shí)將此 Session 的唯一標(biāo)識(shí)信息 SessionID 返回給瀏覽器
瀏覽器接收到服務(wù)器返回的 SessionID 信息后蘸际,會(huì)將此信息存入到 Cookie 中座哩,同時(shí) Cookie 記錄此 SessionID 屬于哪個(gè)域名
當(dāng)用戶第二次訪問服務(wù)器的時(shí)候,請(qǐng)求會(huì)自動(dòng)判斷此域名下是否存在 Cookie 信息粮彤,如果存在自動(dòng)將 Cookie 信息也發(fā)送給服務(wù)端根穷,服務(wù)端會(huì)從 Cookie 中獲取 SessionID姜骡,再根據(jù) SessionID 查找對(duì)應(yīng)的 Session 信息,如果沒有找到說明用戶沒有登錄或者登錄失效屿良,如果找到 Session 證明用戶已經(jīng)登錄可執(zhí)行后面操作圈澈。
根據(jù)以上流程可知,SessionID 是連接 Cookie 和 Session 的一道橋梁尘惧,大部分系統(tǒng)也是根據(jù)此原理來驗(yàn)證用戶登錄狀態(tài)康栈。
Cookie 和 Session 的區(qū)別
安全性: Session 比 Cookie 安全,Session 是存儲(chǔ)在服務(wù)器端的喷橙,Cookie 是存儲(chǔ)在客戶端的啥么。
存取值的類型不同:Cookie 只支持存字符串?dāng)?shù)據(jù),想要設(shè)置其他類型的數(shù)據(jù)贰逾,需要將其轉(zhuǎn)換成字符串悬荣,Session 可以存任意數(shù)據(jù)類型。
有效期不同: Cookie 可設(shè)置為長(zhǎng)時(shí)間保持似踱,比如我們經(jīng)常使用的默認(rèn)登錄功能隅熙,Session 一般失效時(shí)間較短,客戶端關(guān)閉(默認(rèn)情況下)或者 Session 超時(shí)都會(huì)失效核芽。
存儲(chǔ)大小不同: 單個(gè) Cookie 保存的數(shù)據(jù)不能超過 4K囚戚,Session 可存儲(chǔ)數(shù)據(jù)遠(yuǎn)高于 Cookie,但是當(dāng)訪問量過多轧简,會(huì)占用過多的服務(wù)器資源驰坊。
什么是 Token(令牌)
Acesss Token
訪問資源接口(API)時(shí)所需要的資源憑證
簡(jiǎn)單 token 的組成: uid(用戶唯一的身份標(biāo)識(shí))、time(當(dāng)前時(shí)間的時(shí)間戳)哮独、sign(簽名拳芙,token 的前幾位以哈希算法壓縮成的一定長(zhǎng)度的十六進(jìn)制字符串)
特點(diǎn):
服務(wù)端無狀態(tài)化、可擴(kuò)展性好
支持移動(dòng)端設(shè)備
安全
支持跨程序調(diào)用
token 的身份驗(yàn)證流程:
客戶端使用用戶名跟密碼請(qǐng)求登錄
服務(wù)端收到請(qǐng)求皮璧,去驗(yàn)證用戶名與密碼
驗(yàn)證成功后舟扎,服務(wù)端會(huì)簽發(fā)一個(gè) token 并把這個(gè) token 發(fā)送給客戶端
客戶端收到 token 以后,會(huì)把它存儲(chǔ)起來悴务,比如放在 cookie 里或者 localStorage 里
客戶端每次向服務(wù)端請(qǐng)求資源的時(shí)候需要帶著服務(wù)端簽發(fā)的 token
服務(wù)端收到請(qǐng)求睹限,然后去驗(yàn)證客戶端請(qǐng)求里面帶著的 token ,如果驗(yàn)證成功讯檐,就向客戶端返回請(qǐng)求的數(shù)據(jù)
每一次請(qǐng)求都需要攜帶 token羡疗,需要把 token 放到 HTTP 的 Header 里
基于 token 的用戶認(rèn)證是一種服務(wù)端無狀態(tài)的認(rèn)證方式,服務(wù)端不用存放 token 數(shù)據(jù)别洪。用解析 token 的計(jì)算時(shí)間換取 session 的存儲(chǔ)空間叨恨,從而減輕服務(wù)器的壓力,減少頻繁的查詢數(shù)據(jù)庫
token 完全由應(yīng)用管理挖垛,所以它可以避開同源策略
Refresh Token
另外一種 token——refresh token
refresh token 是專用于刷新 access token 的 token痒钝。如果沒有 refresh token秉颗,也可以刷新 access token,但每次刷新都要用戶輸入登錄用戶名與密碼午乓,會(huì)很麻煩站宗。有了 refresh token闸准,可以減少這個(gè)麻煩益愈,客戶端直接用 refresh token 去更新 access token,無需用戶進(jìn)行額外的操作夷家。
Access Token 的有效期比較短蒸其,當(dāng) Acesss Token 由于過期而失效時(shí),使用 Refresh Token 就可以獲取到新的 Token库快,如果 Refresh Token 也失效了摸袁,用戶就只能重新登錄了。
Refresh Token 及過期時(shí)間是存儲(chǔ)在服務(wù)器的數(shù)據(jù)庫中义屏,只有在申請(qǐng)新的 Acesss Token 時(shí)才會(huì)驗(yàn)證靠汁,不會(huì)對(duì)業(yè)務(wù)接口響應(yīng)時(shí)間造成影響,也不需要向 Session 一樣一直保持在內(nèi)存中以應(yīng)對(duì)大量的請(qǐng)求闽铐。
Token 和 Session 的區(qū)別
Session 是一種記錄服務(wù)器和客戶端會(huì)話狀態(tài)的機(jī)制蝶怔,使服務(wù)端有狀態(tài)化,可以記錄會(huì)話信息兄墅。而 Token 是令牌踢星,訪問資源接口(API)時(shí)所需要的資源憑證。Token 使服務(wù)端無狀態(tài)化隙咸,不會(huì)存儲(chǔ)會(huì)話信息沐悦。
Session 和 Token 并不矛盾,作為身份認(rèn)證 Token 安全性比 Session 好五督,因?yàn)槊恳粋€(gè)請(qǐng)求都有簽名還能防止監(jiān)聽以及重放攻擊藏否,而 Session 就必須依賴鏈路層來保障通訊安全了。如果你需要實(shí)現(xiàn)有狀態(tài)的會(huì)話充包,仍然可以增加 Session 來在服務(wù)器端保存一些狀態(tài)副签。
所謂 Session 認(rèn)證只是簡(jiǎn)單的把 User 信息存儲(chǔ)到 Session 里,因?yàn)?SessionID 的不可預(yù)測(cè)性误证,暫且認(rèn)為是安全的继薛。而 Token ,如果指的是 OAuth Token 或類似的機(jī)制的話愈捅,提供的是 認(rèn)證 和 授權(quán) 遏考,認(rèn)證是針對(duì)用戶,授權(quán)是針對(duì) App 蓝谨。其目的是讓某 App 有權(quán)利訪問某用戶的信息灌具。這里的 Token 是唯一的青团。不可以轉(zhuǎn)移到其它 App上,也不可以轉(zhuǎn)到其它用戶上咖楣。Session 只提供一種簡(jiǎn)單的認(rèn)證督笆,即只要有此 SessionID ,即認(rèn)為有此 User 的全部權(quán)利诱贿。是需要嚴(yán)格保密的娃肿,這個(gè)數(shù)據(jù)應(yīng)該只保存在站方,不應(yīng)該共享給其它網(wǎng)站或者第三方 App珠十。所以簡(jiǎn)單來說:如果你的用戶數(shù)據(jù)可能需要和第三方共享料扰,或者允許第三方調(diào)用 API 接口,用 Token 焙蹭。如果永遠(yuǎn)只是自己的網(wǎng)站晒杈,自己的 App,用什么就無所謂了孔厉。
什么是 JWT
JSON Web Token(簡(jiǎn)稱 JWT)是目前最流行的跨域認(rèn)證解決方案拯钻。
是一種認(rèn)證授權(quán)機(jī)制。
JWT 是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于 JSON 的開放標(biāo)準(zhǔn)(RFC 7519)撰豺。JWT 的聲明一般被用來在身份提供者和服務(wù)提供者間傳遞被認(rèn)證的用戶身份信息粪般,以便于從資源服務(wù)器獲取資源。比如用在用戶登錄上郑趁。
可以使用 HMAC 算法或者是 RSA 的公/私秘鑰對(duì) JWT 進(jìn)行簽名刊驴。因?yàn)閿?shù)字簽名的存在,這些傳遞的信息是可信的寡润。
阮一峰老師的 JSON Web Token 入門教程 講的非常通俗易懂捆憎,這里就不再班門弄斧了
生成 JWT
JWT 的原理
JWT 認(rèn)證流程:
用戶輸入用戶名/密碼登錄,服務(wù)端認(rèn)證成功后梭纹,會(huì)返回給客戶端一個(gè) JWT
客戶端將 token 保存到本地(通常使用 localstorage躲惰,也可以使用 cookie)
當(dāng)用戶希望訪問一個(gè)受保護(hù)的路由或者資源的時(shí)候,需要請(qǐng)求頭的 Authorization 字段中使用Bearer 模式添加 JWT变抽,其內(nèi)容看起來是下面這樣
Authorization: Bearer <token>
服務(wù)端的保護(hù)路由將會(huì)檢查請(qǐng)求頭 Authorization 中的 JWT 信息础拨,如果合法,則允許用戶的行為
因?yàn)?JWT 是自包含的(內(nèi)部包含了一些會(huì)話信息)绍载,因此減少了需要查詢數(shù)據(jù)庫的需要
因?yàn)?JWT 并不使用 Cookie 的诡宗,所以你可以使用任何域名提供你的 API 服務(wù)而不需要擔(dān)心跨域資源共享問題(CORS)
因?yàn)橛脩舻臓顟B(tài)不再存儲(chǔ)在服務(wù)端的內(nèi)存中,所以這是一種無狀態(tài)的認(rèn)證機(jī)制
JWT 的使用方式
- 客戶端收到服務(wù)器返回的 JWT击儡,可以儲(chǔ)存在 Cookie 里面塔沃,也可以儲(chǔ)存在 localStorage。
方式一
-
當(dāng)用戶希望訪問一個(gè)受保護(hù)的路由或者資源的時(shí)候阳谍,可以把它放在 Cookie 里面自動(dòng)發(fā)送蛀柴,但是這樣不能跨域螃概,所以更好的做法是放在 HTTP 請(qǐng)求頭信息的 Authorization 字段里,使用 Bearer 模式添加 JWT鸽疾。
GET /calendar/v1/events
用戶的狀態(tài)不會(huì)存儲(chǔ)在服務(wù)端的內(nèi)存中吊洼,這是一種 無狀態(tài)的認(rèn)證機(jī)制
服務(wù)端的保護(hù)路由將會(huì)檢查請(qǐng)求頭 Authorization 中的 JWT 信息,如果合法制肮,則允許用戶的行為冒窍。
由于 JWT 是自包含的,因此減少了需要查詢數(shù)據(jù)庫的需要
JWT 的這些特性使得我們可以完全依賴其無狀態(tài)的特性提供數(shù)據(jù) API 服務(wù)弄企,甚至是創(chuàng)建一個(gè)下載流服務(wù)超燃。
因?yàn)?JWT 并不使用 Cookie ,所以你可以使用任何域名提供你的 API 服務(wù)而不需要擔(dān)心跨域資源共享問題(CORS)
方式二
- 跨域的時(shí)候拘领,可以把 JWT 放在 POST 請(qǐng)求的數(shù)據(jù)體里。
方式三
- 通過 URL 傳輸
http://www.example.com/user?token=xxx
項(xiàng)目中使用 JWT
項(xiàng)目地址:https://github.com/yjdjiayou/jwt-demo
Token 和 JWT 的區(qū)別
相同:
都是訪問資源的令牌
都可以記錄用戶的信息
都是使服務(wù)端無狀態(tài)化
都是只有驗(yàn)證成功后樱调,客戶端才能訪問服務(wù)端上受保護(hù)的資源
區(qū)別:
Token:服務(wù)端驗(yàn)證客戶端發(fā)送過來的 Token 時(shí)约素,還需要查詢數(shù)據(jù)庫獲取用戶信息,然后驗(yàn)證 Token 是否有效笆凌。
JWT:將 Token 和 Payload 加密后存儲(chǔ)于客戶端圣猎,服務(wù)端只需要使用密鑰解密進(jìn)行校驗(yàn)(校驗(yàn)也是 JWT 自己實(shí)現(xiàn)的)即可,不需要查詢或者減少查詢數(shù)據(jù)庫乞而,因?yàn)?JWT 自包含了用戶信息和加密的數(shù)據(jù)送悔。
常見的前后端鑒權(quán)方式
Session-Cookie
Token 驗(yàn)證(包括 JWT,SSO)
OAuth2.0(開放授權(quán))
常見的加密算法
哈希算法(Hash Algorithm)又稱散列算法爪模、散列函數(shù)欠啤、哈希函數(shù),是一種從任何一種數(shù)據(jù)中創(chuàng)建小的數(shù)字“指紋”的方法屋灌。哈希算法將數(shù)據(jù)重新打亂混合洁段,重新創(chuàng)建一個(gè)哈希值。
哈希算法主要用來保障數(shù)據(jù)真實(shí)性(即完整性)共郭,即發(fā)信人將原始消息和哈希值一起發(fā)送祠丝,收信人通過相同的哈希函數(shù)來校驗(yàn)原始數(shù)據(jù)是否真實(shí)。
哈希算法通常有以下幾個(gè)特點(diǎn):
2 的 128 次方為 340282366920938463463374607431768211456除嘹,也就是 10 的 39 次方級(jí)別
2 的 160 次方為 1.4615016373309029182036848327163e+48写半,也就是 10 的 48 次方級(jí)別
2 的 256 次方為 1.1579208923731619542357098500869 × 10 的 77 次方,也就是 10 的 77 次方
正像快速:原始數(shù)據(jù)可以快速計(jì)算出哈希值
逆向困難:通過哈希值基本不可能推導(dǎo)出原始數(shù)據(jù)
輸入敏感:原始數(shù)據(jù)只要有一點(diǎn)變動(dòng)尉咕,得到的哈希值差別很大
沖突避免:很難找到不同的原始數(shù)據(jù)得到相同的哈希值叠蝇,宇宙中原子數(shù)大約在 10 的 60 次方到 80 次方之間,所以 2 的 256 次方有足夠的空間容納所有的可能龙考,算法好的情況下沖突碰撞的概率很低:
注意:
以上不能保證數(shù)據(jù)被惡意篡改蟆肆,原始數(shù)據(jù)和哈希值都可能被惡意篡改矾睦,要保證不被篡改,可以使用RSA 公鑰私鑰方案炎功,再配合哈希值枚冗。
哈希算法主要用來防止計(jì)算機(jī)傳輸過程中的錯(cuò)誤,早期計(jì)算機(jī)通過前 7 位數(shù)據(jù)第 8 位奇偶校驗(yàn)碼來保障(12.5% 的浪費(fèi)效率低)蛇损,對(duì)于一段數(shù)據(jù)或文件赁温,通過哈希算法生成 128bit 或者 256bit 的哈希值,如果校驗(yàn)有問題就要求重傳淤齐。
常見問題
使用 cookie 時(shí)需要考慮的問題
因?yàn)榇鎯?chǔ)在客戶端股囊,容易被客戶端篡改,使用前需要驗(yàn)證合法性
不要存儲(chǔ)敏感數(shù)據(jù)更啄,比如用戶密碼稚疹,賬戶余額
使用 httpOnly 在一定程度上提高安全性
盡量減少 cookie 的體積,能存儲(chǔ)的數(shù)據(jù)量不能超過 4kb
設(shè)置正確的 domain 和 path祭务,減少數(shù)據(jù)傳輸
cookie 無法跨域
一個(gè)瀏覽器針對(duì)一個(gè)網(wǎng)站最多存 20 個(gè)Cookie内狗,瀏覽器一般只允許存放 300 個(gè)Cookie
移動(dòng)端對(duì) cookie 的支持不是很好,而 session 需要基于 cookie 實(shí)現(xiàn)义锥,所以移動(dòng)端常用的是 token
使用 session 時(shí)需要考慮的問題
將 session 存儲(chǔ)在服務(wù)器里面柳沙,當(dāng)用戶同時(shí)在線量比較多時(shí),這些 session 會(huì)占據(jù)較多的內(nèi)存拌倍,需要在服務(wù)端定期的去清理過期的 session
當(dāng)網(wǎng)站采用集群部署的時(shí)候赂鲤,會(huì)遇到多臺(tái) web 服務(wù)器之間如何做 session 共享的問題。因?yàn)?session 是由單個(gè)服務(wù)器創(chuàng)建的柱恤,但是處理用戶請(qǐng)求的服務(wù)器不一定是那個(gè)創(chuàng)建 session 的服務(wù)器数初,那么該服務(wù)器就無法拿到之前已經(jīng)放入到 session 中的登錄憑證之類的信息了。
當(dāng)多個(gè)應(yīng)用要共享 session 時(shí)膨更,除了以上問題妙真,還會(huì)遇到跨域問題,因?yàn)椴煌膽?yīng)用可能部署的主機(jī)不一樣荚守,需要在各個(gè)應(yīng)用做好 cookie 跨域的處理珍德。
sessionId 是存儲(chǔ)在 cookie 中的,假如瀏覽器禁止 cookie 或不支持 cookie 怎么辦矗漾? 一般會(huì)把 sessionId 跟在 url 參數(shù)后面即重寫 url锈候,所以 session 不一定非得需要靠 cookie 實(shí)現(xiàn)
移動(dòng)端對(duì) cookie 的支持不是很好,而 session 需要基于 cookie 實(shí)現(xiàn),所以移動(dòng)端常用的是 token
使用 token 時(shí)需要考慮的問題
如果你認(rèn)為用數(shù)據(jù)庫來存儲(chǔ) token 會(huì)導(dǎo)致查詢時(shí)間太長(zhǎng),可以選擇放在內(nèi)存當(dāng)中真屯。比如 redis 很適合你對(duì) token 查詢的需求笼踩。
token 完全由應(yīng)用管理获列,所以它可以避開同源策略
token 可以避免 CSRF 攻擊(因?yàn)椴恍枰?cookie 了)
移動(dòng)端對(duì) cookie 的支持不是很好谷市,而 session 需要基于 cookie 實(shí)現(xiàn),所以移動(dòng)端常用的是 token
使用 JWT 時(shí)需要考慮的問題
因?yàn)?JWT 并不依賴 Cookie 的击孩,所以你可以使用任何域名提供你的 API 服務(wù)而不需要擔(dān)心跨域資源共享問題(CORS)
JWT 默認(rèn)是不加密迫悠,但也是可以加密的。生成原始 Token 以后巩梢,可以用密鑰再加密一次创泄。
JWT 不加密的情況下,不能將秘密數(shù)據(jù)寫入 JWT括蝠。
JWT 不僅可以用于認(rèn)證鞠抑,也可以用于交換信息。有效使用 JWT忌警,可以降低服務(wù)器查詢數(shù)據(jù)庫的次數(shù)搁拙。
JWT 最大的優(yōu)勢(shì)是服務(wù)器不再需要存儲(chǔ) Session,使得服務(wù)器認(rèn)證鑒權(quán)業(yè)務(wù)可以方便擴(kuò)展慨蓝。但這也是 JWT 最大的缺點(diǎn):由于服務(wù)器不需要存儲(chǔ) Session 狀態(tài)感混,因此使用過程中無法廢棄某個(gè) Token 或者更改 Token 的權(quán)限。也就是說一旦 JWT 簽發(fā)了礼烈,到期之前就會(huì)始終有效,除非服務(wù)器部署額外的邏輯婆跑。
JWT 本身包含了認(rèn)證信息此熬,一旦泄露,任何人都可以獲得該令牌的所有權(quán)限滑进。為了減少盜用犀忱,JWT的有效期應(yīng)該設(shè)置得比較短。對(duì)于一些比較重要的權(quán)限扶关,使用時(shí)應(yīng)該再次對(duì)用戶進(jìn)行認(rèn)證阴汇。
JWT 適合一次性的命令認(rèn)證,頒發(fā)一個(gè)有效期極短的 JWT节槐,即使暴露了危險(xiǎn)也很小搀庶,由于每次操作都會(huì)生成新的 JWT,因此也沒必要保存 JWT铜异,真正實(shí)現(xiàn)無狀態(tài)哥倔。
為了減少盜用,JWT 不應(yīng)該使用 HTTP 協(xié)議明碼傳輸揍庄,要使用 HTTPS 協(xié)議傳輸咆蒿。
使用加密算法時(shí)需要考慮的問題
絕不要以明文存儲(chǔ)密碼
永遠(yuǎn)使用 哈希算法 來處理密碼,絕不要使用 Base64 或其他編碼方式來存儲(chǔ)密碼,這和以明文存儲(chǔ)密碼是一樣的沃测,使用哈希缭黔,而不要使用編碼。編碼以及加密蒂破,都是雙向的過程馏谨,而密碼是保密的,應(yīng)該只被它的所有者知道寞蚌, 這個(gè)過程必須是單向的田巴。哈希正是用于做這個(gè)的,從來沒有解哈希這種說法挟秤, 但是編碼就存在解碼壹哺,加密就存在解密。
絕不要使用弱哈纤腋眨或已被破解的哈希算法管宵,像 MD5 或 SHA1 ,只使用強(qiáng)密碼哈希算法攀甚。
絕不要以明文形式顯示或發(fā)送密碼箩朴,即使是對(duì)密碼的所有者也應(yīng)該這樣。如果你需要 “忘記密碼” 的功能秋度,可以隨機(jī)生成一個(gè)新的 一次性的(這點(diǎn)很重要)密碼炸庞,然后把這個(gè)密碼發(fā)送給用戶。
分布式架構(gòu)下 session 共享方案
1. session 復(fù)制
- 任何一個(gè)服務(wù)器上的 session 發(fā)生改變(增刪改)荚斯,該節(jié)點(diǎn)會(huì)把這個(gè) session 的所有內(nèi)容序列化埠居,然后廣播給所有其它節(jié)點(diǎn),不管其他服務(wù)器需不需要 session 事期,以此來保證 session 同步
優(yōu)點(diǎn): 可容錯(cuò)滥壕,各個(gè)服務(wù)器間 session 能夠?qū)崟r(shí)響應(yīng)。
缺點(diǎn): 會(huì)對(duì)網(wǎng)絡(luò)負(fù)荷造成一定壓力兽泣,如果 session 量大的話可能會(huì)造成網(wǎng)絡(luò)堵塞绎橘,拖慢服務(wù)器性能。
2. 粘性 session /IP 綁定策略
- 采用 Ngnix 中的 ip_hash 機(jī)制唠倦,將某個(gè) ip的所有請(qǐng)求都定向到同一臺(tái)服務(wù)器上称鳞,即將用戶與服務(wù)器綁定。 用戶第一次請(qǐng)求時(shí)牵敷,負(fù)載均衡器將用戶的請(qǐng)求轉(zhuǎn)發(fā)到了 A 服務(wù)器上胡岔,如果負(fù)載均衡器設(shè)置了粘性 session 的話,那么用戶以后的每次請(qǐng)求都會(huì)轉(zhuǎn)發(fā)到 A 服務(wù)器上枷餐,相當(dāng)于把用戶和 A 服務(wù)器粘到了一塊靶瘸,這就是粘性 session 機(jī)制。
優(yōu)點(diǎn): 簡(jiǎn)單,不需要對(duì) session 做任何處理怨咪。
缺點(diǎn): 缺乏容錯(cuò)性屋剑,如果當(dāng)前訪問的服務(wù)器發(fā)生故障,用戶被轉(zhuǎn)移到第二個(gè)服務(wù)器上時(shí)诗眨,他的 session 信息都將失效唉匾。
適用場(chǎng)景: 發(fā)生故障對(duì)客戶產(chǎn)生的影響較小匠楚;服務(wù)器發(fā)生故障是低概率事件 巍膘。
實(shí)現(xiàn)方式: 以 Nginx 為例,在 upstream 模塊配置 ip_hash 屬性即可實(shí)現(xiàn)粘性 session芋簿。
3. session 共享(常用)
使用分布式緩存方案比如 Memcached 峡懈、Redis 來緩存 session,但是要求 Memcached 或 Redis 必須是集群
把 session 放到 Redis 中存儲(chǔ)与斤,雖然架構(gòu)上變得復(fù)雜肪康,并且需要多訪問一次 Redis ,但是這種方案帶來的好處也是很大的:
實(shí)現(xiàn)了 session 共享撩穿;
可以水平擴(kuò)展(增加 Redis 服務(wù)器)磷支;
服務(wù)器重啟 session 不丟失(不過也要注意 session 在 Redis 中的刷新/失效機(jī)制);
不僅可以跨服務(wù)器 session 共享食寡,甚至可以跨平臺(tái)(例如網(wǎng)頁端和 APP 端)
4. session 持久化
- 將 session 存儲(chǔ)到數(shù)據(jù)庫中雾狈,保證 session 的持久化
優(yōu)點(diǎn): 服務(wù)器出現(xiàn)問題,session 不會(huì)丟失
缺點(diǎn): 如果網(wǎng)站的訪問量很大抵皱,把 session 存儲(chǔ)到數(shù)據(jù)庫中箍邮,會(huì)對(duì)數(shù)據(jù)庫造成很大壓力,還需要增加額外的開銷維護(hù)數(shù)據(jù)庫叨叙。
只要關(guān)閉瀏覽器 ,session 真的就消失了堪澎?
不對(duì)擂错。對(duì) session 來說,除非程序通知服務(wù)器刪除一個(gè) session樱蛤,否則服務(wù)器會(huì)一直保留钮呀,程序一般都是在用戶做 log off 的時(shí)候發(fā)個(gè)指令去刪除 session。
然而瀏覽器從來不會(huì)主動(dòng)在關(guān)閉之前通知服務(wù)器它將要關(guān)閉昨凡,因此服務(wù)器根本不會(huì)有機(jī)會(huì)知道瀏覽器已經(jīng)關(guān)閉爽醋,之所以會(huì)有這種錯(cuò)覺,是大部分 session 機(jī)制都使用會(huì)話 cookie 來保存 session id便脊,而關(guān)閉瀏覽器后這個(gè) session id 就消失了蚂四,再次連接服務(wù)器時(shí)也就無法找到原來的 session。如果服務(wù)器設(shè)置的 cookie 被保存在硬盤上,或者使用某種手段改寫瀏覽器發(fā)出的 HTTP 請(qǐng)求頭遂赠,把原來的 session id 發(fā)送給服務(wù)器久妆,則再次打開瀏覽器仍然能夠打開原來的 session。
恰恰是由于關(guān)閉瀏覽器不會(huì)導(dǎo)致 session 被刪除跷睦,迫使服務(wù)器為 session 設(shè)置了一個(gè)失效時(shí)間筷弦,當(dāng)距離客戶端上一次使用 session 的時(shí)間超過這個(gè)失效時(shí)間時(shí),服務(wù)器就認(rèn)為客戶端已經(jīng)停止了活動(dòng)抑诸,才會(huì)把 session 刪除以節(jié)省存儲(chǔ)空間烂琴。
項(xiàng)目地址
https://github.com/yjdjiayou/jwt-demo
后語
本文只是基于自己的理解講了理論知識(shí),因?yàn)閷?duì)后端/算法知識(shí)不是很熟蜕乡,如有謬誤奸绷,還請(qǐng)告知,萬分感謝异希!
如果本文對(duì)你有所幫助健盒,還請(qǐng)點(diǎn)個(gè)贊~~