(以下两种权限管理的方法均基于 RBAC 模型)
// 用户数据
const users = [
{
userId: 1,
username: 'admin',
password: '123456',
phone: '13600000000',
email: 'admin@react.com',
desc: '超级管理员',
roles: [1]
},
{
userId: 2,
username: 'user',
password: '123456',
phone: '13600000001',
email: 'user@react.com',
desc: '运维人员',
roles: [2]
}
]
// 角色数据
const roles = [
{
roleId: 1,
title: '超级管理员',
desc: '超级管理员',
menus: [
{
menuId: 1,
title: '首页',
icon: 'icon-home',
url: '/home',
desc: '首页',
parentId: null,
children: null
},
{
menuId: 2,
title: '系统管理',
icon: 'icon-setting',
url: '/system',
desc: '系统管理目录分支',
parentId: null,
children: [
{
menuId: 3,
title: '用户管理',
icon: 'icon-user',
url: '/system/useradmin',
desc: '系统管理 /用户管理',
parent: 2,
children: null
},
{
menuId: 4,
title: '角色管理',
icon: 'icon-team',
url: '/system/roleadmin',
desc: '系统管理 /角色管理',
parent: 2,
children: null
},
{
menuId: 5,
title: '权限管理',
icon: 'icon-safetycertificate',
url: '/system/poweradmin',
desc: '系统管理 /权限管理',
parent: 2,
children: null
},
{
menuId: 6,
title: '菜单管理',
icon: 'icon-appstore',
url: '/system/menuadmin',
desc: '系统管理 /菜单管理',
parent: 2,
children: null
}
]
},
],
powers: [
{
powerId: 1,
menuId: 3,
title: '新增',
code: 'user:add',
desc: '用户管理 - 添加权限'
},
{
powerId: 2,
menuId: 3,
title: '修改',
code: 'user:up',
desc: '用户管理 - 修改权限'
},
{
powerId: 3,
menuId: 3,
title: '查看',
code: 'user:query',
desc: '用户管理 - 查看权限'
},
{
powerId: 4,
menuId: 3,
title: '删除',
code: 'user:del',
desc: '用户管理 - 删除权限'
},
{
powerId: 5,
menuId: 3,
title: '分配角色',
code: 'user:role',
desc: '用户管理 - 分配角色权限'
},
{
powerId: 6,
menuId: 4,
title: '新增',
code: 'role:add',
desc: '角色管理 - 添加权限'
},
{
powerId: 7,
menuId: 4,
title: '修改',
code: 'role:up',
desc: '角色管理 - 修改权限'
},
{
powerId: 8,
menuId: 4,
title: '查看',
code: 'role:query',
desc: '角色管理 - 查看权限'
},
{
powerId: 18,
menuId: 4,
title: '分配权限',
code: 'role:power',
desc: '角色管理 - 分配权限'
},
{
powerId: 9,
menuId: 4,
title: '删除',
code: 'role:del',
desc: '角色管理 - 删除权限'
},
{
powerId: 10,
menuId: 5,
title: '新增',
code: 'power:add',
desc: '权限管理 - 添加权限'
},
{
powerId: 11,
menuId: 5,
title: '修改',
code: 'power:up',
desc: '权限管理 - 修改权限'
},
{
powerId: 12,
menuId: 5,
title: '查看',
code: 'power:query',
desc: '权限管理 - 查看权限'
},
{
powerId: 13,
menuId: 5,
title: '删除',
code: 'power:del',
desc: '权限管理 - 删除权限'
},
{
powerId: 14,
menuId: 6,
title: '新增',
code: 'menu:add',
desc: '菜单管理 - 添加权限'
},
{
powerId: 15,
menuId: 6,
title: '修改',
code: 'menu:up',
desc: '菜单管理 - 修改权限'
},
{
powerId: 16,
menuId: 6,
title: '查看',
code: 'menu:query',
desc: '菜单管理 - 查看权限'
},
{
powerId: 17,
menuId: 6,
title: '删除',
code: 'menu:del',
desc: '菜单管理 - 删除权限'
}
]
},
{
roleId: 2,
title: '运维人员',
desc: '运维人员',
menus: [
{
menuId: 1,
title: '首页',
icon: 'icon-home',
url: '/home',
parent: null,
desc: '首页'
}
],
powers: []
}
]
// 判断当前元素是否有权限(按钮级)
const checkPermission = powerCode => {
return powers.map(item => item.code).includes(powerCode)
}
checkPermission('menu:add') && <Button>新增</Button>
还有两个小问题我认为需要注意下:
这里可以进行一些接口的拆分,比如把路由和权限数据单独拆成一个接口来获取(/getMenusAndPowers,其实也就是当前角色对应的数据)
在每次路由渲染之前(也就是路由拦截逻辑中),判断当前 store 中有没有角色数据,如果没有就重新请求 /getMenusAndPowers 接口,获取最新的角色数据并存入 store 中;如果已经有数据,就什么都不做(避免重复请求)
这样做我认为有个好处,就是当用户修改了权限或者菜单数据后,刷新页面后,会去重新拉取最新的数据; 有的系统的做法是登陆以后请求一次接口,然后把权限和菜单数据存在 storage 中,但这样每次修改数据后,用户必须重新登录系统才能看到最新的效果,体验不好
路由可以分为不需要根据角色来判断权限的( constantRoutes,如 login 、404 等页面路由)路由和需要权限的( asyncRoutes,后端返回的就是这部分),前端最终的路由数据应该由这两部分组装
一般的前后端分离项目在路由拦截里还需要添加判断用户是否登录的逻辑
const menus = [
{
title: '',
path: '/login',
roles: ['admin', 'test'],
component: '@/page/user/Login'
},
{
title: '',
path: '/404',
roles: ['test'],
component: '@/page/404'
},
{
title: '',
path: '/home',
roles: ['admin'],
component: '@/page/home'
}
]
看了很多后台项目,基本都是这两种方案的思路,我个人觉得第一种方案要更靠谱点?大家项目都是用的哪种呢?
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.