You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
constrouterMap=[{path: '/permission',component: Layout,redirect: '/permission/index',alwaysShow: true,// will always show the root menumeta: {title: 'permission',icon: 'lock',roles: ['admin','editor']// you can set roles in root nav},children: [{path: 'page',component: ()=>import('@/views/permission/page'),name: 'pagePermission',meta: {title: 'pagePermission',roles: ['admin']// or you can only set roles in sub nav}},{path: 'directive',component: ()=>import('@/views/permission/directive'),name: 'directivePermission',meta: {title: 'directivePermission'// if do not set roles, means: this page does not require permission}}]}]
importrouterfrom'./router'importstorefrom'./store'import{Message}from'element-ui'importNProgressfrom'nprogress'// progress barimport'nprogress/nprogress.css'// progress bar styleimport{getToken}from'@/utils/auth'// getToken from cookieNProgress.configure({showSpinner: false})// NProgress Configuration// permission judge functionfunctionhasPermission(roles,permissionRoles){if(roles.indexOf('admin')>=0)returntrue// admin permission passed directlyif(!permissionRoles)returntruereturnroles.some(role=>permissionRoles.indexOf(role)>=0)}constwhiteList=['/login','/authredirect']// no redirect whitelistrouter.beforeEach((to,from,next)=>{NProgress.start()// start progress barif(getToken()){// determine if there has token/* has token*/if(to.path==='/login'){next({path: '/'})NProgress.done()// if current page is dashboard will not trigger afterEach hook, so manually handle it}else{if(store.getters.roles.length===0){// 判断当前用户是否已拉取完user_info信息store.dispatch('GetUserInfo').then(res=>{// 拉取user_infoconstroles=res.data.roles// note: roles must be a array! such as: ['editor','develop']store.dispatch('GenerateRoutes',{ roles }).then(()=>{// 根据roles权限生成可访问的路由表router.addRoutes(store.getters.addRouters)// 动态添加可访问路由表next({ ...to,replace: true})// hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record})}).catch((err)=>{store.dispatch('FedLogOut').then(()=>{Message.error(err||'Verification failed, please login again')next({path: '/'})})})}else{// 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓if(hasPermission(store.getters.roles,to.meta.roles)){next()//}else{next({path: '/401',replace: true,query: {noGoBack: true}})}// 可删 ↑}}}else{/* has no token*/if(whiteList.indexOf(to.path)!==-1){// 在免登录白名单,直接进入next()}else{next('/login')// 否则全部重定向到登录页NProgress.done()// if current page is login will not trigger afterEach hook, so manually handle it}}})router.afterEach(()=>{NProgress.done()// finish progress bar})
面试官:vue要做权限管理该怎么做?如果控制到按钮级别的权限怎么做?
一、权限控制
权限是对特定资源的访问许可,所谓权限控制,也就是确保用户只能访问到被分配的资源
而前端权限归根结底是请求的发起权,请求的发起可能有下面两种形式触发
总的来说,所有的请求发起都触发自前端路由或视图
所以我们可以从这两方面入手,对触发权限的源头进行控制,最终要实现的目标是:
路由方面,用户登录后只能看到自己有权访问的导航菜单,也只能访问自己有权访问的路由地址,否则将跳转
4xx
提示页视图方面,用户只能看到自己有权浏览的内容和有权操作的控件
最后再加上请求控制作为最后一道防线,路由可能配置失误,按钮可能忘了加权限,这种时候请求控制可以用来兜底,越权请求将在前端被拦截
二、如何做
前端权限控制可以分为四个方面:
接口权限
接口权限目前一般采用
jwt
的形式来验证,没有通过的话一般返回401
,跳转到登录页面重新进行登录登录完拿到
token
,将token
存起来,通过axios
请求拦截器进行拦截,每次请求的时候头部携带token
路由权限控制
方案一
初始化即挂载全部路由,并且在路由上标记相应的权限信息,每次路由跳转前做校验
这种方式存在以下四种缺点:
加载所有的路由,如果路由很多,而用户并不是所有的路由都有权限访问,对性能会有影响。
全局路由守卫里,每次路由跳转都要做权限判断。
菜单信息写死在前端,要改个显示文字或权限信息,需要重新编译
菜单跟路由耦合在一起,定义路由的时候还有添加菜单显示标题,图标之类的信息,而且路由不一定作为菜单显示,还要多加字段进行标识
方案二
初始化的时候先挂载不需要权限控制的路由,比如登录页,404等错误页。如果用户通过URL进行强制访问,则会直接进入404,相当于从源头上做了控制
登录后,获取用户的权限信息,然后筛选有权限访问的路由,在全局路由守卫里进行调用
addRoutes
添加路由按需挂载,路由就需要知道用户的路由权限,也就是在用户登录进来的时候就要知道当前用户拥有哪些路由权限
这种方式也存在了以下的缺点:
菜单权限
菜单权限可以理解成将页面与理由进行解耦
方案一
菜单与路由分离,菜单由后端返回
前端定义路由信息
name
字段都不为空,需要根据此字段与后端返回菜单做关联,后端返回的菜单信息中必须要有name
对应的字段,并且做唯一性校验全局路由守卫里做判断
每次路由跳转的时候都要判断权限,这里的判断也很简单,因为菜单的
name
与路由的name
是一一对应的,而后端返回的菜单就已经是经过权限过滤的如果根据路由
name
找不到对应的菜单,就表示用户有没权限访问如果路由很多,可以在应用初始化的时候,只挂载不需要权限控制的路由。取得后端返回的菜单后,根据菜单与路由的对应关系,筛选出可访问的路由,通过
addRoutes
动态挂载这种方式的缺点:
方案二
菜单和路由都由后端返回
前端统一定义路由组件
后端路由组件返回以下格式
在将后端返回路由通过
addRoutes
动态挂载之间,需要将数据处理一下,将component
字段换为真正的组件如果有嵌套路由,后端功能设计的时候,要注意添加相应的字段,前端拿到数据也要做相应的处理
这种方法也会存在缺点:
按钮权限
方案一
按钮权限也可以用
v-if
判断但是如果页面过多,每个页面页面都要获取用户权限
role
和路由表里的meta.btnPermissions
,然后再做判断这种方式就不展开举例了
方案二
通过自定义指令进行按钮权限的判断
首先配置路由
自定义权限鉴定指令
在使用的按钮中只需要引用
v-has
指令小结
关于权限如何选择哪种合适的方案,可以根据自己项目的方案项目,如考虑路由与菜单是否分离
权限需要前后端结合,前端尽可能的去控制,更多的需要后台判断
参考文献
The text was updated successfully, but these errors were encountered: