Skip to content

Ant design pro v4 父路由对象不设置 authority,子路由对象设置 authority 不生效bug?

例如有如下配置的路由👇

javascript
{
	path: '/setting',
	name: 'setting',
	icon: 'SettingOutlined',
 	routes: [
		{
			path: '/setting/message',
            name: 'message',
            authority: ['user'],
            component: './setting/user/Message',
            dynamic: true,
		},
        {
			path: '/setting/list',
			name: 'account-list',
			authority: ['admin'],
			component: './setting/admin/AccountList',
			dynamic: true,
		}
	]
}

触发场景:我登录的是 admin 权限的账号,我通过地址栏跳转到 /setting/message,按配置来看,是跳转不成功的,但实际成功显示了。你们可以尝试一下。

当时陷入了深思,是我路由配错了吗?是配置写错了吗?然后回官网查看文档,是可以配置子路由的呀,又找前端的朋友看一下我的配置文件,演示一次给他看,他也懵逼了。😂😂😂

冒着脱发的危险,查看了他们的鉴权模块。

大概是这样子的:

jsx
// BasicLayout.jsx
// 当你访问一个路由时,它会在路由配置文件中返回与你访问路由匹配的路由对象
const authorized = getAuthorityFromRouter(props.route.routes, location.pathname || '/') || [{
   authority: undefined,
 }]

// 权鉴 props authority 就是传入到组件中进行鉴权,权限通过则显示,不通过则显示 noMatch 组件(props传入)
<Authorized authority={authorized.authorized} noMatch={noMatch}>
	{children}
</Authorized>

然后一次偶然的 console.log(authorized.authorized) 发现了问题,(依旧是触发场景的操作)authorized 竟然返回来的是 undefined(导致页面无需权限即可访问),明明我配置的权限是 ['user'] 🤔🤔🤔

再往上console.log(authorized)发现它返回的是 父路由 对象,就是 开头例子中那一整个对象。🤔

继续往上查阅 utils.jsgetAuthorityFromRouter 方法,这个路由的功能就是 在路由配置文件中返回与你访问路由匹配的路由对象。问题就是出在这里了。🧐🧐🧐

因为这个方法,无论如何都是返回与你访问路由匹配的 父路由对象。就是你访问 /setting/message 这个路由,但返回的是 setting 整个路由,它上面是没有设置 authority,这也导致后续的判断中,被判断为无需权限即可访问。

简单来说,它只会判断父路由对象上的 authority,子路由 authority 无论是什么都不会生效

你们可以尝试一下设置反例👇(发现 admin 账号都无法访问 setting 子路由,无论何种方式访问)

jsx
// 反例
{
	path: '/setting',
	name: 'setting',
	icon: 'SettingOutlined',
    authority: ['user'],
 	routes: [
		{
			path: '/setting/message',
            name: 'message',
            component: './setting/user/Message',
            dynamic: true,
		},
        {
			path: '/setting/list',
			name: 'account-list',
			component: './setting/admin/AccountList',
			dynamic: true,
		}
	]
}

然后就只能...开战🙂🙂🙂

javascript
// utils.js
export const getAuthorityFromRouter = (router = [], pathname) => {
  const authorityList = []
  const route = router.find(
    ({
      routes,
      path = '/',
      target = '_self'
    }) => {
      if (path && target !== '_blank' && pathRegexp(path).exec(pathname)) return true

      const temp = getAuthorityFromRouter(routes, pathname)
      if (routes && temp) {
        temp.length && authorityList.push(temp)
        return true
      }

      return false
    }
  );
  // 计算权限并返回
  if (route) {
    // 如果之前就有无权限访问,直接拒绝
    if (authorityList.includes('non')) return 'non'
    
    let auth = route.authority
    if (!auth) {
      return authorityList.flat()
    } else if (typeof auth === 'string') {
      auth = [auth]
    }
    
    authorityList.unshift(auth)
    // 取交集
    const intersection = authorityList.reduce((total = [], a) => total.filter(item => a.includes(item)), authorityList[0])
    console.log(intersection);
    return intersection.length ? intersection : 'non'
  }

  return undefined
}
jsx
// BasicLayout.jsx
// 如果返回[]和undefined 都代表页面无需权限, non表示无权限访问该网页
let authorized = getAuthorityFromRouter(props.route.routes, location.pathname || '/');
authorized = authorized && authorized.length ? authorized : undefined

<Authorized authority={authorized} noMatch={noMatch}>
	{children}
</Authorized>

nice!!!😛😛😛经过初步测试可以解决掉上面所有问题,虽然改写的代码丑陋了点(本人是一只菜鸡),哈哈哈。

如果大神有更好的解决方法,或者我理解有误可以到我的 GitHub 发邮件给我。

Released under the MIT License.