前端权限代码说明
路由
路由分为两部分,一部分是固定的几个 ,比如/login,/404,另一部分是根据权限动态生成的.
router/index.js
里,动态路由都在 asyncRouterMap内,里面元素的关键属性为menu , 生成动态路由时,会根据用户权限json内的menuList里是否含有这个menu,来决定是否为此用户添加这个路由.
生成动态路由过程
permission.js
vue-router的全局拦截器, 如果已登录状态而没有拿到用户的权限属性的话,说明还没查询用户权限信息,初始化动态路由
if (!store.getters.role) { store.dispatch('GetInfo').then(() => { next({...to}) }) }
user.js
,查询到用户权限信息,并且存入vuex
"userPermission":{ "menuList":[ "role", "user", "article" ], "roleId":1, "nickname":"超级用户", "roleName":"管理员", "permissionList":[ "article:list", "article:add", "user:list", ], "userId":10003 }
为什么不在登录的时候一并返回呢? 因为页面F5刷新的时候,vuex信息会丢失,所以需要重新查询一遍这些权限信息. 当然,把权限信息存入cookie也可以解决.
拿到userPermission后,调用生成动态路由的方法
store.dispatch('GenerateRoutes', userPermission).then(() => { router.addRoutes(store.getters.addRouters) })
store/modules/permission.js
现在,我们已经拿到了用户的权限信息,再从@/router/index
内拿到asyncRouterMap,逐一比较便可知道为用户生成哪些路由了
页面元素
只需在按钮上添加 v-if="hasPerm('article:add')"
就可以根据用户的权限来控制本页面元素(比如按钮)是否显示了.
hasPerm方法也非常简单
export function hasPermission(permission) { let myPermissions = store.getters.permissions; return myPermissions.indexOf(permission) > -1; }
DEMO
admin/123456 管理员身份登录,可以新增用户,角色.
角色可以分配权限
控制菜单是否显示,新增/删除按钮是否显示
设计思路
核心
每个登录用户拥有各自的N条权限,比如 文章:查看/编辑/发布/删除
后端
基于 RBAC新解 .
通常我们的权限设计都是 用户--角色--权限 ,其中角色是我们写代码的人没法控制的,它可以有多条权限,每个用户又可以设计为拥有多个角色.因此如果从角色着手进行权限验证,系统都必须根据用户的配置动起来,非常复杂.
所以我们后台设计的关键点就在于: 后台接口只验证权限,不看角色.
角色的作用其实只是用来管理分配权限的,真正的验证只验证权限 ,而不去管你是否是那种角色.体现在代码上就是接口上注解为
@RequiresPermissions("article:add")
而不是
@RequiresRoles(value = {"admin","manager","writer"}, logical = Logical.OR)
前端
采用了vueAdmin-template , ElementUI , 权限设计思路也是参考了 vueAdmin 的动态路由的设计.
后端负责了接口的安全性,而前端之所以要做权限处理,最主要的目的就是隐藏掉不具有权限的菜单(路由)和按钮.
登录系统后,后端返回此用户的权限信息,比如
"userPermission":{ "menuList":[ "role", "user", "article" ], "roleId":1, "nickname":"超级用户", "roleName":"管理员", "permissionList":[ "article:list", "article:add", "user:list", ], "userId":10003 }
根据menuList判断给此用户生成哪些路由, 根据permissionList判断给用户显示哪些按钮,能请求哪些接口.
数据库
如果某用户拥有表格中前五条权限,就可以查出他就拥有article和user两个菜单,至于页面内是否显示(新增)(修改)按钮,就根据他的permissionList来判断.
具体实现
有了思路,就可以根据各自的业务进行实现,本项目在此进行了简单的实现,后端代码在back文件夹,前端代码在vue文件夹.前端启动只需
npm install --registry=https://registry.npm.taobao.org
npm run dev
后端就是常规的shiro配置,前端代码如果看不明白,可以参考前端权限代码说明