前端实际上是很难有权限验证的,由于从安全的角度来讲,前端没有绝对的安全,攻击者老是能够修改前端的代码。对于 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 团队再接再砺了。