前端如何進行使用者許可權管理

weixin_33807284發表於2018-11-27

1:問題:

假如在做一個管理系統,面向老師學生的,學生提交申請,老師負責稽核(或者還需要新增其他角色,功能許可權都不同)。

現在的問題是,每種角色登入看到的介面應該都是不一樣的,那這個頁面的區分如何實現呢?

2:要不要給老師和學生各自設計一套頁面?這樣工作量是不是太大了,並且如果還要加入其它角色的話,難道每個角色對應一套程式碼?

所以我們需要用一套頁面適應各種使用者角色,並根據身份賦予他們不同許可權

3:許可權設計與管理是一個很複雜的問題,涉及的東西很多,相比前端,更偏向於後端,在蒐集相關資料的過程中

,發現摻雜了許多資料庫之類的知識,以及幾個用於許可權管理的java框架,比如spring,比如shiro等等,都屬於後端的工作

4:那我們前端能做什麼呢?

許可權的設計中比較常見的就是RBAC基於角色的訪問控制,基本思想是,對系統操作的各種許可權不是直接授予具體的使用者,而是在使用者集合與許可權集合之間建立一個角色集合。每一種角色對應一組相應的許可權。

一旦使用者被分配了適當的角色後,該使用者就擁有此角色的所有操作許可權。這樣做的好處是,不必在每次建立使用者時都進行分配許可權的操作,只要分配使用者相應的角色即可,而且角色的許可權變更比使用者的許可權變更要少得多,這樣將簡化使用者的許可權管理,減少系統的開銷。

在Angular構建的單頁面應用中,要實現這樣的架構我們需要額外多做一些事.從整體專案上來講,大約有3處地方,前端工程師需要進行處理.

  1. UI處理(根據使用者擁有的許可權,判斷頁面上的一些內容是否顯示)
  2. 路由處理(當使用者訪問一個它沒有許可權訪問的url時,跳轉到一個錯誤提示的頁面)
  3. HTTP請求處理(當我們傳送一個資料請求,如果返回的status是401或者401,則通常重定向到一個錯誤提示的頁面)

如何實現?

首先需要在Angular啟動之前就獲取到當前使用者的所有的permissions,然後比較優雅的方式是通過一個service存放這個對映關係.對於UI處理一個頁面上的內容是否根據許可權進行顯示,我們應該通過一個directive來實現.當處理完這些,我們還需要在新增一個路由時額外為其新增一個"permission"屬性,併為其賦值表明擁有哪些許可權的角色可以跳轉這個URL,然後通過Angular監聽routeChangeStart事件來進行當前使用者是否擁有此URL訪問許可權的校驗.最後還需要一個HTTP攔截器監控當一個請求返回的status是401或者403時,跳轉頁面到一個錯誤提示頁面.

大致上的工作就是這些,看起來有些多,其實一個個來還是挺好處理的.

在Angular執行之前獲取到permission的對映關係

clipboard.png

Angular專案通過ng-app啟動,但是一些情況下我們是希望Angular專案的啟動在我們的控制之中.比如現在這種情況下,我就希望能獲取到當前登入使用者的所有permission對映關係後,再啟動Angular的App.幸運的是Angular本身提供了這種方式,也就是angular.bootstrap().看的仔細的人可能會注意到,這裡使用的是$.get(),沒有錯用的是jQuery而不是Angular的$resource或者$http,因為在這個時候Angular還沒有啟動,它的function我們還無法使用.

進一步使用上面的程式碼可以將獲取到的對映關係放入一個service作為全域性變數來使用.

clipboard.png

在取得當前使用者的許可權集合後,我們將這個集合存檔到對應的一個service中,然後又做了2件事:

(1) 將permissions存放到factory變數中,使之一直處於記憶體中,實現全域性變數的作用,但卻沒有汙染名稱空間.

(2) 通過$broadcast廣播事件,當許可權發生變更的時候.

如何確定UI元件的依據許可權進行顯隱

clipboard.png

這裡我們需要自己編寫一個directive,它會依據許可權關係來進行顯示或者隱藏元素.

這裡看到了比較理想的情況是通關一個has-permission屬性校驗permission的name,如果當前使用者有則顯示,沒有則隱藏.

clipboard.png

擴充套件一下之前的factory:

clipboard.png

路由上的依許可權訪問
這一部分的實現的思路是這樣: 當我們定義一個路由的時候增加一個permission的屬性,屬性的值就是有哪些許可權才能訪問當前url.然後通過routeChangeStart事件一直監聽url變化.每次變化url的時候,去校驗當前要跳轉的url是否符合條件,然後決定是跳轉成功還是跳轉到錯誤的提示頁面.

router.js:

clipboard.png

mainController.js 或者 indexController.js (總之是父層Controller)

clipboard.png

這裡依然用到了之前寫的hasPermission,這些東西都是高度可複用的.這樣就搞定了,在每次view的route跳轉前,在父容器的Controller中判斷一些它到底有沒有跳轉的許可權即可.

HTTP請求處理

這個應該相對來說好處理一點,思想的思路也很簡單.因為Angular應用推薦的是RESTful風格的介面,所以對於HTTP協議的使用很清晰.對於請求返回的status code如果是401或者403則表示沒有許可權,就跳轉到對應的錯誤提示頁面即可.

當然我們不可能每個請求都去手動校驗轉發一次,所以肯定需要一個總的filter.程式碼如下:

clipboard.png

寫到這裡我們就基本實現了在這種前後端分離模式下,前端部分的許可權管理和控制。

相關文章