查看原文:前端权限验证控制与实现
查看原文点击关注“八戒技术团队”,阅读更多技术干货
欢迎大家一起探讨交流进入技术交流群
前言
在应用中,”权限验证“是一个常见的话题。从应用的层面来讲,虽然不同的应用有一定区别,但总体不外乎以下四种权限状态:游客、普通用户、管理员用户、超级管理员用户;从技术的层面上来讲,一个用户具有什么样的管理权限,应当是该用户的一个身份标识,而这样的身份标识应该是跟随用户信息一并存储在数据库中的数据。由此可见,用户权限的设计本质上来说应当是后端工作的一部分。
但在真正应用的过程中,却并非是纯后端的工作。首先站在产品经理的角度,用户使用什么样的功能应该在接触应用的时候就被展现出来,而交互功能的起始在前端;其次从用户的角度来讲,当某一个功能不能被使用时,此时应用做出诸如“错误提示”、“重定向“ 等操作比直接返回一个错误数据拥有更好的用户体验;最后是减轻服务器压力,对于没有权限的操作直接在前端进行相应的处理,更少的请求意味着服务器压力更小。
综上所述,前端权限验证仅仅作为后端权限体系的一个必要补充。虽然是一个补充,但是十分必要,它的必要性体现在:产品功能的完善、用户体验的提升、以及服务器压力的减轻等诸多方面。
前端的权限验证又主要分为三大部分:登录权限验证、页面权限验证、请求权限验证。本文主要结合Vue3、Vue-router4、以及Vuex 的后台管理系统案例来进行举例说明。
1、登陆权限验证
从使用流程上来看,往往用户进入应用之后,首先是登录的判断,譬如在后台管理系统中,用户通过外链或输入应用的网址链接,此时应用应对当前的登录状态进行验证。若已经登陆了即跳转到用户需要的页面,若如果没有登陆,那么应引导用户到登录页先进行登录操作。
从技术实现上来看,前端用户登录的本质是将用户信息(userName/passWord/token…)存储在本地(cookie/session/localStorage)和发送请求验证用户信息的有效性,并根据返回结果对当前用户的信息进行处理,从而判断当前用户是否已经正确登录。
例如当前首页需要进行登录拦截,用户在未登录的情况下需要跳转到登录界面进行操作,可在路由中直接重定向登录页面 。
1.1 页面重定向
先定义好路由,在需要登录权限的路由添加`meta`字段标识。
然后在 `router.beforeEach`中进行判断,对需要登录且未登录的页面进行重定向
1.2 页面引导登陆
除了直接重定向以外,有时还需要对用户进行引导。在`layout`文件目录中定义一个`default.vue`组件,在components中定一个登录引导组件 `guide.vue`,在`default.vue`中引入 `guide.vue `并进行登录的判断。
对于需要登录才能够看到的组件,最外层套用一层 `default.vue` 组件即
效果如下:
总结:根据用户是否登录判断用户是否能够看到对应的内容有两种做法:1、对router进行配置和重定向操作。2、为需要登录才能看到的组件包裹一层登录判断的高阶组件。
2、页面权限验证
页面的权限,不仅涉及登录的判断,还要根据用户在系统之中的角色进行判断,但是思路大同小异。首先是在vuex中存入用户的角色权限,然后在路由中进行权限过滤,或者封装高阶组件对目标页面进行处理。
2.1 路由权限验证
用户登录成功之后,后端接口返回给前端该账号下拥有的权限列表,至于是什么角色应该拥有什么权限,此逻辑统一为后端逻辑进行配置处理,假设登陆成功后返回的数据如下:(伪代码)
即是说,用户 kevin 有且只有`列表页`,`详情页 ` 的访问权限,此时应该根据用户拥有的权限来配置路由,生成一份符合当前用户角色的路由表。该路由表应该由两部分构成,一部分是无需角色认证即可访问的路由即静态路由,另一部分是由当前用户权限确定的路由即动态路由(使用vue-router4中的API `router.addRoute(route)` )。
当前用户只能够访问角色允许的页面,当用户访问不属于当前角色的页面时,由于没有生成对应的路由,所以用户无法进入对应的页面,如果要再优化一下,就应该告知当前操作者没有访问权限,或引导用户重定向到其他页面( 在 `router.beforeEach()`中进行判断)。
2.2 按钮权限验证
除了整个页面进行角色认证外,页面中操作按钮也应当根据角色权限的不同而进行不同的展示,譬如一个列表页面,普通用户和和管理员都能够进行访问,但是普通用户只能够进行`查看`,管理员才能够进行`修改`和`删除`操作,此时前端就要在这些功能按钮上进行权限控制和处理。
对于使用者来讲,常见的操作无非四种——增删改查,所以后端在返回用户信息的时候,除了可见页面的权限,还应当返回当前用的操作权限。这里对操作权限的定义有两种,第一种是对“增删改查”进行二进制编码的对应,拥有权限是`1`,没有权限是`0`,例如用户拥有所有操作权限,那么对应的数字应该是 `0001` 即 15;第二种做法是对“增删改查”进行字符串匹配,例如用户拥有所有权限,那么对应的编码应该是 `'CURD'`。采用哪种方式更加方便,这个视情况而定,本例中采用第二种方式进行介绍。例如,登陆之后后端返回的数据为:(伪代码)
上述代码中,不同的路由下对应着不同的权限,那么在页面的按钮中应该如何实现权限的判断呢 常见的做法有三种,第一种是拿到用户的权限,直接在页面 `v-if` 进行判断;第二种是应用高阶组件进行封装;第三种是自定义指令。
(1)v-if 判断
这种做法虽能实现功能,但是每次使用都要重写,很冗余。
(2)高阶组件
定义一个高阶组件 `p-button` ,然后将逻辑封装,利用 `props` 传递按钮对应权限
高阶组件大大减少了使用的复杂度,将逻辑抽离并独立出来,但是每一次使用都必须要引入组件,这个过程还是有些繁琐。
(3)自定义指令(v-permission)
指令控制十分方便,但是内部逻辑不便于更改,灵活性有所欠缺。
以上三种方式均能够实现以下效果:
总结:对比之后,v-if 简单粗暴,功能虽能实现,但过程过于繁琐;高阶组件,处理灵活但使用稍稍繁琐;自定义指令,使用足够简洁,但是不够灵活。所以应当根据使用的场景选择适当的实现方式。
3、axios接口请求权限验证
接口请求的权限验证,是一个非必要的补充,其目的在于路由失效,并且指令也失效的情况下,仍然可以做到前端的请求拦截。
接口请求拦截分为两步,第一步是请求拦截,第二步是响应拦截。请求拦截的目的是在请求头中添加登录成功时获取到的 `token`,响应拦截是对后端返回的状态码进行二次封装,实现更好的交互提示。
3.1 请求拦截
3.2 响应拦截
结语:本文基本概括了前端权限验证的三个方面,基本思路并不复杂。整个技术涉及全局状态管理(vuex)、路由管理(vue-router)、组件化思想(抽离逻辑并封装/自定义指令使用)、以及axios请求拦截。按照一般产品的使用流程,从用户登录,页面切换、按钮操作、请求发起等方面对用户权限验证介绍了相应的解决方案。随着技术的进步与更新,前端权限验证还会有更多的方法与思路,希望本文能够起到一定的参考作用。
希望以上内容能对有需要的人有所帮助
如若转载,请注明出处:https://www.vsaren.com/1463.html