鑒權,是指驗證用戶是否擁有訪問系統的權利。它是一個系統的重要組成部分,隻是我好像從來沒有寫過相關的文章。于是,于是,最近手不怎麼疼,又剛好有幾個項目有相關的問題。讨論了多次之後,我發現鑒權簡直稱得上是一門藝術。
不過,在開始之前,我不得不聲明一下這裡的場景:
Token 鑒權
單頁面應用
傳統的 Cookie-Session 的方式,并不需要這樣的方式。
通用的基于 Token 的鑒權方案,大緻步驟如下所示:
客戶端将用戶名和密碼等信息,發送到服務端。
服務端驗證生成 Token,并以 Token 作為 Key,存儲到數據庫中,并返回 Token 給前端。
前端存儲 Token 到前端『數據庫』中。
需要注意的是,對于那些對安全要求高的系統而言,前端所需要提供的參數,不限于用戶名和密碼,還要有地理位置、設備相關信息等參數。
随後:
前端在每個請求中,帶個授權相關的信息。
後端校驗前端的 Token 是否有效,再返回給前端相應的結果。
前端處理後端返回的結果。一旦鑒權失敗,則删除 Token,調用登錄邏輯。
好像沒的毛病,大家都是這麼做的,那麼到底哪來的平衡藝術?
前端是以路由作為邊界,來劃分不同領域的。也因此,在用戶進行每一個路由點擊之前, 系統需要對用戶是否有權限進行判斷。若是用戶有權限,便繼續訪問;若是用戶沒有權限,那麼就返回 401,并重新登錄。
基于這種鑒權模式,我們會有多種多樣的路由守衛方式。在執行路由跳轉時,存在這麼一些基礎的模式:
提交時驗證。這樣的系統,可能是不存在的,但是我不确定。
Token 存在驗證。隻驗證 Token 是存在的,懂技術的用戶可以修改,但是後果自負(無非就是數據丢失 重定向)。
關鍵步驟二次驗證。先驗證是否存在 Token,随後在進行一些重要的操作之前,先進行 Token 有效性驗證,再進行路由跳轉。
每步二次驗證。即每次在路由跳轉時先進行驗證,再決定是否跳轉。同理于刷新頁面的情形。
跳轉後二次驗證。先跳轉到頁面上,再進行二次驗證。
……
于是,我們可以做一個簡單的對比(從 1 到 5):
相應的解釋如下:
提交時驗證。提交後再告訴用戶授權失敗,會導緻數據丢失。或者額外的前端持久化數據,而每個持久化都會帶來額外的工作量。
Token 存在驗證。當用戶(開發人員)修改 Token 或者 Role 時,他/她可以訪問一些不應該看到的頁面。
關鍵步驟二次驗證。額外的後台 API,以及關鍵步驟的設計。
每步驗證。每次跳轉時,都需要等待時間,并訪問後台API——會對性能造成影響。
跳轉後驗證。減少等待時間,但是還存在大量的後台接口訪問。
對于不同的場景,都可以采用不同的方案。又或者是組合出自己需求的方案。
回到我們的故事上,我們采用的是第二種方案:關鍵步驟二次驗證。
首先,我們有兩個後端 API:
登錄鑒權 API。返回 Token 和用戶信息,以及 Token 的過期時間。
Token 有效性 API。返回用戶信息,以及 Token 的過期時間。
前端代碼設計(以 Angular 為例):
鑒權守衛(AuthGuard)。進行 Token 存在驗證,和 Token 過期時間驗證。
角色守衛(RoleGuard)。進行角色驗證
HTTP 異常攔截(HTTP Interceptor)。後端返回 401 時,删除 Token 等,并引導用戶重新登錄。
關鍵名詞解釋:
Token 存在驗證。在本地的浏覽器裡存在 Token 時,便是認證通過。
Token 有效期驗證。将本地的 Token 生成時間,與本地時間進行對比,如果不過期,則是有效的。
Token 有效性驗證。發送請求到後端,看 Token 是否有效,更刷新用戶角色。
最後,我們的組合模式如下所示:
用戶進行普通(諸如自身相關的操作),隻驗證 Token 是否存在 是否在有效期内。
在用戶進行部分關鍵操作(諸如角色綁定菜單)之前,先進行 Token 有效性驗證,随後刷新本地的用戶角色。
……
反正,後端會進行一系列的權限校驗,不是嗎?
平衡,真的是是一門藝術。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!