現(xiàn)有項目架構(gòu):
1. jwt是否需要服務(wù)器存儲用戶狀態(tài)按照jwt的思路,,服務(wù)端是不需要存儲用戶狀態(tài)的,,只要有秘鑰+過期時間就可以實現(xiàn)用戶的認(rèn)證和過期,至于讀庫vs加解密驗證哪個過程對服務(wù)器的壓力更大,,這個可能需要對比測試,,但從原理和常識來講,存庫讀庫的成本應(yīng)該更高一點,。無庫產(chǎn)生的加解密開銷相對于讀寫庫應(yīng)該是非常小的,,而且無庫可以輕松做到跨服務(wù)器的認(rèn)證。 2. jwt方案中token的安全問題分為兩個安全問題:
綜上,,jwt碰到的安全問題跟傳統(tǒng)方式一樣。 3. jwt如何解決續(xù)簽問題傳統(tǒng)的cookie的續(xù)簽方案一般都是框架自帶的,,session有效期30分鐘,,30分鐘內(nèi)如果有訪問,session有效期被延長30分鐘,。那么jwt是怎么實現(xiàn)的呢,,細(xì)節(jié)沒看完,不過基本的邏輯是頻繁重簽名(不知道為什么有人這么干,,開銷應(yīng)該不小,,而且問題挺多),,或者是有效期30分鐘,,服務(wù)器發(fā)現(xiàn)token要過期了,提前三分鐘重簽并返回新的token,,客戶端每次請求都檢測新舊token,,如果不一致更新本地token(這個可以放在http的請求預(yù)處理里,復(fù)雜度和開銷都不大),。關(guān)于新token的發(fā)放導(dǎo)致舊token有效期內(nèi)的訪問失效的問題參見這里的token新舊更替問題討論 ,。這種方案就可以實現(xiàn)瀏覽器里傳統(tǒng)cookie的續(xù)簽需求,以及app7天內(nèi)登陸就可以持續(xù)刷新登陸狀態(tài)的問題(app比較特殊,,每天第一次訪問時刷新一下token),。 4. jwt如何解決注銷問題好了,jwt最大的問題來了,,怎么注銷,?先看傳統(tǒng)的session是怎么注銷的:用戶點擊退出,調(diào)用后臺退出接口,,也就是session注銷接口,,依托于后臺的狀態(tài)更新,。那么服務(wù)端做的呢,如果是用文件或者數(shù)據(jù)庫存儲的,,那么通過刪記錄是可以后臺強制踢出的,,放在內(nèi)存里就不要想了(如果用戶量大了放內(nèi)存的話服務(wù)器也吃不消,放文件里io太頻繁基本也不靠譜,,還好有了Redis),。jwt最大的問題就在于后臺沒有存儲用戶狀態(tài),用戶退出的話只是客戶端刪掉了token,,然而此token在有效期內(nèi)還是有效的,,也就是說如果token泄露的話就麻煩了,不過token泄露的問題已經(jīng)在上面講過了,,和cookie是同一個問題,。那么最麻煩的就是怎么讓一個token在用戶注銷后失效,以及后臺強制退出,,這個jwt是沒辦法的,,因為jwt的無狀態(tài)和用戶狀態(tài)維護(hù)是個矛盾沖突的話題。如果要解決就要建立一個黑名單,,也就是把用戶注銷后的token放到redis里,,然后每次校驗黑名單(這里還是用到了數(shù)據(jù)庫), 5. 使用jwt+Redis黑名單的方案接上個問題,,jwt推崇的無狀態(tài)和跨服務(wù)器認(rèn)證在數(shù)據(jù)庫的出現(xiàn)后,,貌似沒有任何優(yōu)勢,真的沒有優(yōu)勢嗎,?也不全是,,至少有兩個小優(yōu)勢,第一,,存儲黑名單(也就是注銷后的用戶或者黑戶)比起存儲登錄之后的用戶這個量級都是相當(dāng)小的,,存儲量下降&讀取速度提高。第二個優(yōu)勢是app和pc能共用同一套認(rèn)證機制,,也就意味著前后端徹底的分離,,不必再為cookie和session認(rèn)證單獨搭一個服務(wù)器。 6. 用了jwt之后html服務(wù)怎么提供呢對于前后端分離的項目來說,,pc服務(wù)器的兩個任務(wù)1是做認(rèn)證(jwt已經(jīng)解決),,2是提供html服務(wù),。html服務(wù)可以交給nginx或者放到cdn,,無論哪個方案都比tomcat之類的靜態(tài)資源處理能力更強大,也就是說html和js等靜態(tài)資源全部交給靜態(tài)資源服務(wù)器來處理,。那么安全問題又來了,,怎么對文件做權(quán)限控制呢,?對于一個前后端分離的項目來說,html一般不會嵌套后端的代碼,,所以html沒有所謂的安全問題,,換句話說html里根本沒有任何有價值的內(nèi)容。對于js來說,,里面包含了業(yè)務(wù)邏輯,,實際上對js做限制也是沒有任何意義的,因為前端的代碼是暴露給客戶端的,,即便控制,,黑客登錄之后也是能看到你的代碼的,惟一能做的就是壓縮混淆,,把壓縮后的代碼放到線上,,源碼不放到線上,最大程度增加通過閱讀js讀取業(yè)務(wù)邏輯的難度(實際意義也不大,,尤其對于有些公司壓根連壓縮這一步都不做的,,更沒有這個問題的顧慮了)。那么也就是說前后端分離的項目里html(沒有后端代碼嵌入)和js是沒有安全的考慮必要的,,真正要考慮的大概也就是圖片的防盜鏈和pdf等靜態(tài)資源的處理吧,,這個因為對于后端不是很熟悉所以不做深入討論,對于pdf等資源能想到的也就是通過需要授權(quán)的接口去拿pdf的路徑吧,。 7. 到底要不要數(shù)據(jù)庫如果不考慮用戶注銷后一定要token失效和強制退出需求的話,,是不需要數(shù)據(jù)庫的,即便加上redis對于傳統(tǒng)方案來說也是有上文提到的兩個優(yōu)勢,。而且其實注銷后一定要token失效主要也是考慮token泄露的問題(見上文),,所以如果有踢出用戶登錄需求的話,還是要有數(shù)據(jù)庫做黑名單存儲的,,一旦用戶被拉入黑名單,,就要立馬停掉用戶的簽名發(fā)放,,所以這個問題并不單單是認(rèn)證的問題,,還有簽名發(fā)放的問題。 8. 用戶認(rèn)證的終極解決方案(跨服務(wù)器)前提就是跨服務(wù),,實際上jwt本身已經(jīng)實現(xiàn)了跨服務(wù)(無狀態(tài)),,既然服務(wù)端不存儲用戶狀態(tài),只要多個服務(wù)器之間使用共同的秘鑰和加密方案就可以實現(xiàn)x.abc.com里登錄之后在y.abc.com那臺服務(wù)器做登錄認(rèn)證,。但是問題上面也說了,,如果不考慮注銷和強制退出的情況的話,這個話題也就到處為止了,。但是如果完美主義呢,?當(dāng)然還是要實現(xiàn)這兩個功能,,也就是要有黑名單服務(wù)器,或者說認(rèn)證服務(wù)器auth.abc.com,,無論x.abc.com還是y.abc.com里登錄或者注銷都要先通過auth.abc.com,,但是帶來的讀寫不一致和額外的認(rèn)證開銷問題大概也是一個歷史性難題吧?;蛟S也可以參考Oauth2.0的方案,,做隱式認(rèn)證。不存儲用戶的狀態(tài)的話,,jwt跨服務(wù)器應(yīng)該是個比較簡單的解決方案吧,,但如果一個公司有跨服務(wù)器需求的話,那么規(guī)模之大,,里面的后端童鞋應(yīng)該有更為專業(yè)的方案吧,,歡迎分享。此段不專業(yè)莫要踩我,。 結(jié)論:上文闡述了作為一個卑微的前端能想到的jwt的問題和思考,,總結(jié)來說,使用jwt可以實現(xiàn)真正的前后端分離,,瀏覽器可以和app用一樣的認(rèn)證機制,,無論對服務(wù)器的搭建還是服務(wù)器開銷都是不錯的優(yōu)化,至于黑名單的設(shè)置,,這個看需求吧,。 彩蛋
|
|