后端項目地址就不剝離開了,自己解讀(中間件那)
前端項目地址(可能是空的,為還沒上傳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。
后記
看的再多不如動手一次。因為會發現想象著很簡單的東西實現起來完全脫離自己掌控。