在Ant Design Pro脚手架中,配置权限是很简单的,只需要在src/access.ts中返回一个对象,对象中的属性值是boolean类型,然后配合路由的 access:“键” 的属性,即会调用 src/access.ts 中返回的对应键进行鉴权,true则显示,false则不显示。并且src/access.ts的函数可以直接接收到initialState参数,即可以非常方便地拿到权限信息,并进行权限控制。
但是最近的开发中遇到这样一个问题:整个项目的所有页面都是需要进行鉴权的,即都需要权限判断是否可以展示的,没有一个公共页面,也就是没办法在路由中写死进入项目后重定向到的页面。这可给我难住了。
尝试过在src/app.tsx的获取初始数据getInitialState中,在拿到初始权限数据后去找出第一个菜单,再history.push("有权限的菜单路由"),但是这样有个问题,就是:用户在浏览页面时,不管在哪个页面,只要手动点击浏览器上的刷新,就会重新执行getInitialState,也就会再给放到那个初始页面去,这肯定不行......
于是就各种找官网,最后在umijs的官网找到了可以在运行时配置,添加路由,就采取了下面这种方式,虽然性能上还是有点问题,但是至少功能给实现了。如果各位大佬有更好的解决办法,请不吝赐教,好人一生平安/(ㄒoㄒ)/~~
/*大体思路为:
1.在render配置中发请求获取到用户拥有的权限菜单;
2.再用patchRoutes({ routes })来修改路由,在路由的最后添加需要重定向的路由。
*/
//1.先在最外面定义一个变量,用来放需要添加的路由。
let extraRoutes: any[];
// 2.在render函数内获取到有权限的路由
export function render(oldRender: any) {
api.getMenu({参数}).then((res) => {
/*这里做判断是先看用户有没有权限进入这个系统,
有权限就添加需要重定向的路由,没权限直接添加重定向路由去403页面*/
if (res.data.hasAccess && res.data.menuTree!.length > 0) {
/*这里是对于请求回来的数据进行处理,拿到了有权限的第一个页面 */
const defaultRoute = res.data.menuTree![0].menu!.path;
extraRoutes = [
{
path: '/',
redirect: defaultRoute,
},
{
component: '@/pages/404.tsx',
},
];
} else {
extraRoutes = [
{
path: '/',
redirect: '/exception',
},
{
component: '@/pages/404.tsx',
},
];
}
oldRender();
});
}
//3.添加路由
export function patchRoutes({ routes }) {
/*这里:在本地启动时是routes[1],在发布时是routes[0],
因为本地启动第一项是openapi相关的,所以在这里做了判断isDev*/
routes[isDev ? 1 : 0].routes.push(...extraRoutes);
}
过程中遇到的坑:
- 一开始就只添加重定向的这一个路由了,404路由就还是放在正常的路由中,但是这样上来“/”路由匹配不到,直接就去404页面了,根本匹配不到重定向的这个路由;
- 一开始没有做用户是否有权限进入页面的判断,以为在getInitialState函数中已经做了拦截就没事了,但是后来打印才知道,render函数在getInitialState函数之前执行,如果没有权限的话,根本走不到getInitialState函数那里就会报错了;
- 添加路由时,看到开发时打印出来的routes,需要把路由添加到数组第1项,但是实际发布环境之后,开发时打印的数组第0项没有了,所以做了个三元的形式来确定加到哪一项里面;
- 这样处理有一点不好的地方:需要在render函数中发一次请求获取初始值,但是还需要在getInitialState函数中发一次请求获取并保存初始值,以供src/access.ts使用,这样的话,就相当于在刚进入项目时发了两次一样的请求,降低了性能。
这种方法虽然实现了功能,但是感觉弯弯绕绕的,还多发了一次请求,如果大家有更好的处理方法,烦请让我知道下呗,谢谢!