前端實際上是很難有權限驗證的,由於從安全的角度來講,前端沒有絕對的安全,攻擊者老是能夠修改前端的代碼。對於 API 的權限能夠由服務端保證,可是對於頁面的權限可能就比較麻煩了。最好的方法固然仍是後端控制——也就是 NodeJs 的後端。若是不能達到這個安全級別的話(不過許多應用也不必),那麼剩下的方法都沒有什麼太大區別,不過若是須要支持動態配置,就須要服務端路由。javascript
這一塊算是 Antd Pro 的模板代碼,由於 React Router 和 umi 並無對於權限流(workflow)的封裝(雖然實現起來很簡單)。umi 能夠在配置中增長Routes
字段來進入鑑權組件,Antd Pro 的Routes
使用了本身實現的Authorized
組件。前端
Antd Pro 增長了另外一個authority
字段,用來判斷每一個路由的權限。Antd Pro 團隊應該準備把這裏設置的很靈活,由於在checkPermissions
裏是能夠接受 promise 的,可是在src/pages/Authorized
裏最終看到的getRouteAuthority
的 ts 定義只接受string
和string[]
。這也是有緣由的,我猜想是 umi 對配置裏的 routeData 作了序列化,致使裏面的函數丟失。若是須要寫自定義的路由鑑權方式,可能須要從這個地方改起。java
Antd Pro 的權限組件在src/components/Authorized
模塊下。這個模塊默認導出一個RenderAuthorize
的高階函數,分別接受Authorized
組件和currentAuthority
做爲參數。這個高階函數的做用在於根據傳入的currentAuthority
來解析(parse)當前用戶的權限,其內部使用了一個CURRENT
變量來緩存解析的結果,並暴露給模塊外部使用,這樣能夠避免重複解析形成效率損失。git
咱們也能夠不使用這個高階函數,那樣就會每次調用傳入的權限獲取方法(在 Antd Pro 裏是getAuthority
)。github
感受這裏有一點亂的地方是把最終配置了getAuthority
的Authorized
放在了utils
裏。我以爲做爲一個默認配置的實例,應當仍是放在原先的組件文件夾下比較好,比較有條理性。typescript
最後看一下在Pages
裏實際使用的Authorized
組件。咱們能夠看到它的 TypeScript 接口類型(話說有了 TypeScript 之後,看源代碼真的方便許多):後端
type IAuthorizedType = React.FunctionComponent<AuthorizedProps> & {
Secured: typeof Secured;
check: typeof check;
AuthorizedRoute: typeof AuthorizedRoute;
};
複製代碼
這個組件的內容很簡單,就是調用check
來檢查權限。這個check
是對抽象出來的checkPermissions
方法的再封裝,本質上就是爲了實現一個包裹當前權限的部分應用函數。前面也提到過,checkPermissions
能夠對各類類型的authority
作支持(好比說函數),具體細節比較簡單就不細說了。api
最終,這就是咱們在src/pages/Authorized
裏看到的封裝:promise
<Authorized
authority={getRouteAuthority(location.pathname, routes) || ''}
noMatch={isLogin ? <Redirect to="/exception/403" /> : <Redirect to="/user/login" />}>
{children}
</Authorized>
複製代碼
全部的判斷邏輯都在一個入口處實現。緩存
研究 Antd Pro 權限組件的初衷主要仍是一些特殊需求和中間偶爾出現的 bug。好比,一開始我遇到了登陸後重定向到登陸頁面的 bug,分析了源代碼以後,我發現主要緣由是由於CURRENT
變量緩存了未登陸時的權限。解決方法也很簡單,只要調用reloadAuthorized
便可。其實文檔裏對此也提到了,不過沒有很是明確的提出這個約定,因此我覺得 Antd Pro 會隱式的作這一步,結果是我想多了。
還有當我在 config 裏設置路由時,對於和Routes
同層的authority
配置是無效的。不過這個屬於 umi 讀取配置的邏輯:
{
path: '/',
component: '../layouts/BasicLayout',
Routes: ['src/pages/Authorized'],
authority: ['admin', 'user'],
routes: [
// forms
{
path: '/form',
icon: 'form',
name: 'form'
},
],
}
複製代碼
總之,Antd Pro 就是對權限判斷邏輯作了一層簡單的封裝,彌補 React Router 的不足。
Antd Pro 默認將權限所有存儲在前端(頁面權限和用戶權限)。Antd Pro 曾經有對後端路由的支持,它是經過一種插件模式,來修改 app 的 render 函數。但後來這部分被移除了,由於它的數據是基於 mock 的,通常服務器沒有實現,就會報錯。
這部分的過程都被我考古出來了……其實我以爲保留挺好的,可是可能這就是社區對開源項目的影響吧……
在基於 token 的認證中,咱們能夠從 jwt token 裏提取當前的身份信息(注意到這並不安全),但沒有必要。咱們能夠直接根據當前用戶的 token 來獲得後端路由。我所理解的後端路由,前端仍然會有 config.ts 裏的配置,由於像 component 不可能在後端作管理。
社區裏有很多人想要實如今登陸後獲取路由的模式,這主要是基於角色的路由實在比較簡單。感受這是Antd Pro 目前還不成熟的體現。
目前 umi 提供的異步掛載路由的方式是經過插件機制來解決,感受並不能說是很是正式的(能用)。並且這個在 app.js 裏,不能在登陸後處理。
最後,我本身的實現是在登陸的異步請求以後掛載路由,可是這隻能經過g_routes
全局變量來操做,感受也是不太正式,只能期待 umi 團隊再接再礪了。