
(以下两种权限管理的方法均基于 RBAC 模型)
// 用户数据 const users = [ { userId: 1, username: 'admin', password: '123456', phone: '13600000000', email: '[email protected]', desc: '超级管理员', roles: [1] }, { userId: 2, username: 'user', password: '123456', phone: '13600000001', email: '[email protected]', 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' } ] 看了很多后台项目,基本都是这两种方案的思路,我个人觉得第一种方案要更靠谱点?大家项目都是用的哪种呢?
1 basefas 2021 年 7 月 5 日 全部交给后端做,前端不要判断权限 |
2 Aliennnnnn 2021 年 7 月 5 日 第一种 |
5 hellwys1 2021 年 7 月 5 日 第一种。 第二种不靠谱,但是小项目前端也这样做过。 |
7 rsyjjsn 2021 年 7 月 6 日 理论第一种更优 实际第二种更方便(毕竟代码要自己写,antd 的中台目前也是第二种) |
8 csdoker OP @luoyelusheng 第二种就是前端的工作量要大点,需要根据角色去手动改一些配置 |
9 rsyjjsn 2021 年 7 月 7 日 @csdoker 这就得看你的项目初期架构怎么样了,如果公司有成熟的技术栈,那么像这种配置基本上就是拿来随便改改就行了,反而是第一种,你无法保证后端返回权限符合你当前前端页面排版,毕竟后端重架构,前台重交互(这也是我经常和后端开架的理由) |
10 lizy0329 2024 年 9 月 4 日 为什么要“前端把角色类型写死”? 都数据 fetch 下来 match 一下不就完了吗 |