携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情 >>
前言
在ToB的项目里鉴权是最常遇到的需求之一,鉴权包括菜单权限,按钮权限,数据权限等等,一般来说的实现是动态路由+前端权限判断的思路,这样做仅仅只能防住页面上的直接提交和访问,本文采用和后台关联的方式,将权限真正做进页面内的按钮级。
实现思路概述
首先我们需要将系统内的菜单拆分为功能,生成功能编码functionCode,将功能进行聚类,形成模块编码moduleCode, 真正的业务实现在功能这一级,模块仅仅作为聚类的作用,方便我们进行勾选,将全局的操作抽象为按钮并提供按钮编码 permCode这样,我们就得到了我们绑定接口api所需要的必要参数,在请求接口时,携带按钮编码与功能编码,即可实现针对页面级的鉴权
路由设计
路由设计我们采用固定模块编码+动态功能编码的方式做params路由,也就是形似/saleOrder/:functionCode这样的形式,为什么这样设计我们后续讲全局路由拦截鉴权的时候再说。
页面级鉴权的实现
项目本身是基于vue,那我就以vue为例,假设我们已经封装好一个全局的页面请求实例,那么在接口调用的时候,我们可以通过headers来携带我们的页面及按钮编码标识,如下文代码中那样
axiosInstance.getOrder({
...
}, {
headers: {
permCode: '当前按钮的编码',
functionCode: this.$route.params.functionCode
}
})
后台可以根据headers内的按钮与权限编码判断当前用户是否在当前页面具备某个接口的调用权限,在全局的请求拦截器里,我们可以拦截特定的错误码,所以,在开发时,当没有权限的时候,我们可以根据特定状态码,动态进行授权,这样,当我们开发完成后,每个页面每个按钮所需要调用的接口就动态维护好了,不会出现人为维护遗漏授权的情况
路由全局守卫拦截鉴权
因为上文采用的是参数路由,这也意味着,假如我们不做任何处理的情况下,任何人只要知道功能编码,即可成功访问对应的功能,所以我们这里需要在路由的全局导航守卫的前置守卫内添加相应的鉴权,首先当然是要声明一些白名单页面,或者是 在路由的元信息meta内标识当前路由为参数路由,这两种方式都可以实现区分普通路由与参数路由,当我们检测到是参数路由时,需要校验当前用户是否具备当前功能,所以我们需要在登录完成后获取用户授权信息并进行缓存,可以基于vuex,也可以通过sessionStorage或localStorage进行存储,存储格式为键值对的形式,key为功能编码,值为布尔值true,这样我们就可以在全局导航守卫内拦截无权限的参数路由访问
按钮级权限
按钮当然也是在登录完成后通过授权信息接口进行获取并存储,存储形式也是键值对的形式,这个看自己的设计,如果设计按钮编码全局唯一并且一一对应,那直接用按钮编码作为key即可,否则在维护时就需要维护按钮与功能之间的关系,键值对的key也需要是 功能编码_按钮编码这样的形式进行保存,页面上动态进行判断即可