Session與JWT(實現JWT重新整理與後端限制授權)
Session與JWT(實現JWT重新整理與後端限制授權)
後端專案地址就不剝離開了,自己解讀(中介軟體那)
前端專案地址(可能是空的,為還沒上傳O(∩_∩)O哈哈~)
前言
Hello World!怕是大多數程式設計師寫的第一句程式碼了吧。我就是用C語言寫的第一個程式碼就是它了。雖然現在沒有從事有關C語言的工作,不過還是受益於學習它所經歷的每一行程式碼。
登入註冊怕是寫web應用裡的Hello World!級存在了。第一份工作做的是j2ee和app,做的第一個模組就算是它了。不過這個"Hello World!"可一點都不簡單。
正文
首先我們先搞清楚什麼是認證和授權。百度一下發現很掉書袋。其實吧簡單來說就是:認證就是讓伺服器知道你是誰,授權就是伺服器讓你知道你什麼能幹,什麼不能幹
認證授權倆種方式:Session-Cookie與JWT
Session
伺服器只有一臺,客戶端卻有千千萬。怎麼能夠讓伺服器知道當前請求服務的是哪臺客戶端呢?我們舉個生活中的例子:
你去圖書館(服務端)借書(請求服務)。先得辦卡(登入獲取session_id)吧,放兜裡(cookie)。去刷卡處刷卡看看卡是不是偽造的,看看卡里的資訊和資料庫比對下看看有沒有過期等等(檢查session_id是否被篡改,是否失效根據session_id查詢下記憶體或者資料庫(通常是記憶體資料庫)裡對應的有沒有過期)。過期不給進重新辦卡(重新登入認證),沒過期就給進(返回你請求的結果)
所以咯流程就是這樣子:
當 client通過使用者名稱密碼請求server並通過身份認證後,server就會生成身份認證相關的 session 資料,並且儲存在記憶體或者記憶體資料庫。並將對應的 sesssion_id返回給client,client會把儲存session_id(可以加密簽名下防止篡改)在cookie。此後client的所有請求都會附帶該session_id(畢竟預設會把cookie傳給server),以確定server是否存在對應的session資料以及檢驗登入狀態,許可權啦巴拉巴拉......如果通過校驗就該幹嘛幹嘛,否則重新登入咯。
前端退出的話就清cookie。後端強制前端重新認證的話就清或者修改session。
JWT
這裡就不介紹jwt的三部分組成、由什麼組成、怎麼生成加密了。
日常的舉個生活中的例子吧:
你去遊樂園(服務端)玩耍(請求服務)。先得買門票(登入獲取token)吧,放兜裡(cookie、header......)。去檢票口檢票看看票有沒有過期(檢查token是否失效)。過期不給進重新買票(重新登入認證),沒過期就給進(返回你請求的結果)
有沒有覺得和Session有什麼不一樣?server不用儲存資訊了。一切都存在客戶端。個人覺得這就是最大的不同。
這裡大致列下倆者區別,一些比如JWT更簡單、APP對支援不易的一些已經解決或者細究覺得很扯的或者大同小異的不在此列
Session | JWT | |
---|---|---|
安全性 | 得考慮CSRF攻擊 | 無需考慮 |
儲存 | 需要倆端都儲存 | 客戶端儲存即可 |
可控性 | 服務端可隨時修改許可權.... | 只能等待Token過期 |
本來網上還是有很多區別的,但是我想了下貌似就這麼幾點。
安全性
首先這個還真不算什麼。現在WEB框架該都內建了防CSRF。而且既然知道有這個編寫程式碼注意下也是應該的。
儲存
這個還真是,JWT真心可以,不過得看情況。如果考慮可控性,那你簡直想哭。
可控性
服務端儲存認證相關資訊還是很有必要的。舉個栗子。如果你發現你賬號被異地登入,你肯定想著換密碼呀。換了以後發現我去,怎麼又被異地登入。因為Token未過期,人家還是可以使用。這就很麻煩了。服務端根本不能控制。這時候你會記得session得好。
其他
還真沒什麼好說的,可能有人覺得JWT加密解密開銷大、有人覺得JWT太長佔空間、session太老了該讓位了、JWT只需要儲存Token在客戶端方便、JWT加密感覺好安全不一而足......
對於以上的看別人博文沒什麼卵用,自己實現下就知道厲害了。
JWT變異之路(實現)
實現來講的話有點後端開發基礎的應該都知道怎麼寫程式碼在知道實現原理的情況下。這裡不再講述,要講的是本人使用JWT用於個人部落格遇到一些情況。在此記錄,與君共勉之。
前提
首先輕輕鬆鬆實現了JWT。本人後端採用Koa2搭建。鑑權使用koa-jwt、生成token採用jsonwebtoken。npm就是這麼方便啊。不過還是懷念當初馳騁j2ee的時候。言歸正傳。發現幾個個很蛋疼的問題。
遇到的問題
- 我什麼服務端居然不能掌控全域性,居然不能讓禁止某個使用者登入。這哪能忍。
好吧,絞盡腦汁,超越處女座忍受極限。我生成token返回前端時,將使用者id作為key,token作為value(存token只是隨意,這裡只是舉例)存在redis,且設定過期時間和token一致。每次前端請求時我都先和往常一般常規驗證,ok之後繼續解出使用者id,檢視redis有沒有這條記錄。有的話該幹嘛幹嘛,沒有的話說明因為某種原因你被管理員kill掉了。乖乖重新登入或者申訴吧。
感覺還可以,雖然不再是無狀態了,但是解決了問題不是,心裡好受多了。但是發現想多了。
- 這點其實是因為工作立馬就想到了。當時公司要開發個聯機幫助工具。就交給我全權開發。
當時開發完了有人反饋說是我寫到一半有點事耽擱了下,然後退出了,這個不就白寫了。好吧,想起自己的個人部落格,雖然我肯定會做個keyup監測儲存功能,但是有可能我訪問著訪問著就退出了。使用者體驗有木有啊。辣雞有木有啊。
那就客戶端加個重新整理token策略咯。綜合考慮之下打算認證時後端生成返回倆個token給前端:accesstoken、refreshtoken。前者用於訪問鑑權,後者用於重新整理token。區別在於前者過期時間短,後者過期時間長。具體時長自己開心就好。
然後現在就這樣子了。比如我accesstoken過期時間30min,refreshtoken過期時間7d。在即將過期的時候(25min),我使用refreshtoken重新向服務端拉取新的accesstoken。你想順帶更新下refreshtoken也是可以的。看自己業務邏輯使用場景。當然也可以在過期時檢測下refreshtoken有沒有過期,沒過期的話拉下新token。
以上就是本人遇到的倆個問題,結果最後發現我的JWT又變成Session。
後記
看的再多不如動手一次。因為會發現想象著很簡單的東西實現起來完全脫離自己掌控。