vue element后台鉴权流程分析

 更新时间:2021年4月10日 00:00  点击:2894

前言:

最近项目遇到一个管理系统,感觉权限配置挺有意思,记录一下流程实现的过程,便于自己学习以及整理思路,部分思路整合在代码的注释中:

路由拦截鉴权常用的两种方法

1:路由拦截:单纯给路由加字段标识符,通过路由拦截实现
2:动态路由:第二种是通过路由的拆分另外需要后端的配合去实现的动态路由配置

比较:

路由拦截实现方式比较简单,只需要简单的在router.beforeEach中根据路由配置信息过滤页面是否有权限前往改组件,若相对于的权限不够则不前往相应的组件

动态路由实现相对比较复杂,并且需要后端的配合,本质是路由配置表分成两部分,相应的不同用户登录的时候,是根据用户权限信息过滤筛选除路由配置表,动态添加,而用户没有权限的部分则不渲染,更适合相对比较大型的后台系统

注:本篇内容主要介绍动态路由鉴权实现方式

与动态路由相关的通常有以下几个文件:

  • router.js
  • permission.js(全局的路由拦截文件)
  • store.js

router.js

router.js的路由配置表可以分为两部分,公共路由以及动态权限路由,动态权限路由可以放在前端,鉴权的时候前端自己进行数组的过滤,也可以放在后端过滤,思路相同,下面介绍的是配置表都放在前端的

export default new  Router({ 
routes:[
   {
		path:'/login',
		name:'login',
		component:aa
	},
	{
		path:'/home',
		name:'home',
		component:cc
	},
	]
})

上面这个是一般项目的路由配置,现在我们需要做鉴权所以需要把路由配置表稍微拆分一下,拆成以下两个数组:

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export const defauleRoute = [ //固定部分权限的数组,所有用户都能访问的路由
	{
		path:'/login',
		component:aa
	},
]

export const  asyncRoute = [ //动态配置的路由表,工作之前需要过滤
	{
		path:'/order',
		name:'order',
		component:aa,
		meta:{
			system:'order'
		}
	}
	{
		path:'/roles',
		name:'roles',
		component:aa,
		meta:{
			system:'roles'
		}
	}
]

//注册路由工作表
const createRouter = () => new Router({
	  // mode: 'history', // require service support
	  scrollBehavior: () => ({ y: 0 }),
	  routes: constantRoutes
})
const router = createRouter()

//重置路由工作表,退出登录的时候需要调用此方法
export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher 
}

export default router

permission.js permission文件主要做全局的路由拦截,以及路由根据用户权限动态过滤等功能,那么这部分内容主要设涉及的就是两个问题 什么时候去处理动态路由什么条件去处理路由

import router from './router'
import store from './store'
import { getToken } from '@/utils/auth' // 自定义封装存取token的方法

Route.beforeEach((to,from,next) =>{
	//取token,判断用户是否已登录
	const  hasToken = getToken() 
	if(hasToken ){
	//判断用户已登录
		if(to.path === "/login"){
			/**
			*用户已经登陆,但是还路由到login页面,这代表用户已经执行了退出登录的操
			*作,所以这个地方可以清一下token之类的,或者自定义写一些逻辑
			*/
			next()
		}else{
		/**
		*这里是已经登录或者点击了登录按钮,token已经存入localstorage,但是但是不路
		*由到login的情况如果没有路由到/login,那么就直接让他放行就行,在这里面我处
		*理一些东西,就是用户既然已经登陆,并且可以直接放行,那么我们放
		*行之前,在这个地方需要做一些逻辑,就是判断用户的权限,然后根
		*据用户的权限,把我们的动态配置的路由表中符合他权限的那几条路
		*由给过滤出来,然后插入到路由配置表中去使用
		*
		*那么就涉及到两个问题:
		*1:什么时候去处理动态路由(登陆之后,进入到首页之前,也就
		*是next之前)
		*2:什么条件处理动态路由
		*/
		
		/**
		*这地方可以先判断一下store中的用户权限列表长度是否为0,若长度为0,则代表用户
		*是刚点击了登录按钮,但是还没有进入到页面,这时候需要再去做一些权限过滤之类的	
		*操作如果长度不为0代表鉴权流程都没问题了,直接前往对应的组件就行
		*这一步主要是为了防止重复过滤数组,节约性能
		*/
			if(store.getters.roles.length > 0){
				next()
			}else{
				//代码如果走到了这个地方,代表用户是已登录。并且鉴权流程还没走,
				//那么在这地方就需要去走鉴权流程
				store.dispatch('getRoles').then(res=>{
					//这个地方的res是第三步那个地方的peomise中的resolve传
					//过来的,也就是权限信息的那个数组
					store.dispatch('createRouters',res.data)
					.then(res=>{
						//这里是调用store创造动态路由的那个函数,这个地方可以把那
						//个权限数组传到这个函数内部,或者不在这里传,这个
						//函数内部直接去取自己state里面的roles的值也是一样的
						let  addRouters = store.getters('addRouters')
						let  allRouters = store.getters('allRouters')

						//添加动态路由部分到工作路由
						router.addRoutes(accessRoutes)
						//前往拦截的页面
          				next({ ...to, replace: true })
					})	
				})
			}
		}
	} else {
		/**这里是处理没有token的情况,也就是说这时候用户还没有登陆,那
		*如果没用户登录,那么判断用户是不是去登录页面,如果是登录
		*页面,就直接放行,如果没登陆就想去访问主页那种页面,就让
		*他重定向到登录页面
		*/
		if(to.path == '/login'){
			//这地方可以判断的仔细一点,不一定是去login的时候再让他直接放行,而是
			//前往所有公共组件的时候,都直接让他放行
			next()
		}else{
			next('/login')
		}
	}
})

 

store.js

//在api文件夹中定义一个获取此用户的权限的接口,并且在这个actions中调用
import { getUserRole } from "../api/getRoles"  //获取权限的接口
import { logout } from '../api/user'   //用户退出登录的接口
import { resetRouter } from './router'
import { removeToken } from '@/utils/auth' // 自定义封装清除token的方法

//这个是过滤数组的方法,如果路由表是多层嵌套的,那么可以递归调用这个方法去过滤数组
//function hasPermission(roles, route) {
//  if (route.meta && route.meta.roles) {
//    return roles.some(role => route.meta.roles.includes(role))
//  } else {
//    return true
//  }
//}

//export function filterAsyncRoutes(routes, roles) {
//  const res = []

//  routes.forEach(route => {
//    const tmp = { ...route }
//    if (hasPermission(roles, tmp)) {
//      if (tmp.children) {
//        tmp.children = filterAsyncRoutes(tmp.children, roles)
//      }
//      res.push(tmp)
//    }
//  })
//
//  return res
//}

//引入默认路由以及动态路由
import  { defauleRoute , asyncRouter }  from '@/router'
const state = {
	roles:[]    //掉接口拿到的权限列表,假设数据格式为:["order","roles"],
	allRouters: [], //这个是全部整合以后,最终要工作的路由
	addRouters: [],//这个是根据权限动态匹配过滤出来部分的路由
}
	  
const getters = {
	/**把state中的roles存入到这个getters中,那么其他获取这个getters中的
	*roles的地方,只要原本的roles发生改变,其他地方的这个roles也就会发生
	*改变了,这个相当于是computed计算属性
	*/
	roles:state => state.roles
	allRouters:state => state.allRouters
	addRouters:state => state.addRouters
}
const mutations:{
	/**在下面的actions里面通过commit把权限信息的数组提交到这个地方,然后
	*这个地方把数组提交到state的roles
	*/
	SetRoute(state,router)
		//这个地方的router就是根据用户权限,过滤出来的路由表
		state.allRouters = defauleRoute.concat(router)
		state.addRouters = router
	}
	//把路由权限数组存储到state
	setRoles(state,value){
		state.roles = value
	}
}
const actions:{
	//写一个获取当前登陆角色权限的请求,比如["/order","roles"],如果请求回
	//来的是这样的,那么就代表这个角色的权限就是可以访问 order路由以及
	//roles路由
	
	//获取权限信息可能有两种情况:除了下面这种权限信息是一个单独的接口,
	//权限信息也可能跟着用户登陆的接口就一并返回
	//获取当前用户的权限信息,并且存入到state中,这个权限信息,可能跟后
	//端在沟通的时候,他不会单独写成一个接口给你去请求,而是你在登陆请求
	//的时候就把用户信息和这个此用户的权限信息都一次性返回给你了,那就在
	//用户登陆的时候就把这个权限信息存入到这个state中,也一
	//样的,目的就是要把权限信息的数组存入到state中就行
	//获取roles权限方法
	getRoles({commit},data){
		return new Promise(resolve,reject){
			//调用获取用户权限接口
			getUserRole().then(res =>{
				//这里返回的数据应该是一个权限信息的数组,如:["order","roles"]
				//把权限信息通过mutations存入到state
				commit('setRoles',res.data)
				resolve(res.data)
			})
		}
	})
	//根据权限过滤数组配置表的方法
	createRouters({ commit } , data ){
		return new Promise((resolve,reject) =>{
			let addRouters =  [ ] 
			if(data.includes("admin"){
				addRouters = asyncRouter
			}else{
				//项目开发中路由数组可能是多层嵌套,那么这地方需要用上面自定义的方	
				//法通过递归的方式去过滤,此demo就只按一层数组处理
				//(filterAsyncRoutes)方法
				addRouters = asyncRouter.filter(item=>{
					if(data.includes(item.meta.system) ){
					   	return item
					}
				})
			}
			
			
			//把这个匹配出来的权限路由传到mutations中,让mutations
			//把这个匹配出来的路由存入到state
			commit.("SetRoute",addRouters)
			resolve()  //这个地方要调用一下这个resolve,这样外面访可以通过
					   //.then拿到数组过滤成功的回调
		})
	},
	logout({ commit }) {
	    return new Promise((resolve, reject) => {
	      logout().then(() => {
	        removeToken() // must remove  token  first
	        resetRouter()
	        commit('setRoles', [])
	        commit('SetRoute', [])
	        resolve()
	      }).catch(error => {
	        reject(error)
	      })
	    })
  },
}
export default {
	state,
	getters,
	mutations,
	actions
}

退出登录:

async function logout(){
	try{
		const res = await store.dispatch.logout()
		if(res.code == 200){
			//退出登录成功
		}
	}catch{
		//退出登录失败(出错了)
	}
}

结尾:

代码一大堆,其实思路很简单,不过是拿到路由配置表,过滤数组,动态添加而已

项目参考github:vue-element-admin

到此这篇关于vue element后台鉴权流程分析的文章就介绍到这了,更多相关vue element鉴权内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

[!--infotagslink--]

相关文章

  • vue中activated的用法

    这篇文章主要介绍了vue中activated的用法,帮助大家更好的理解和使用vue框架,感兴趣的朋友可以了解下...2021-01-03
  • 基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件功能

    这篇文章主要介绍了基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-23
  • Antd-vue Table组件添加Click事件,实现点击某行数据教程

    这篇文章主要介绍了Antd-vue Table组件添加Click事件,实现点击某行数据教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-11-17
  • vue 实现动态路由的方法

    这篇文章主要介绍了vue 实现动态路由的方法,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-07-06
  • Vue组件跨层级获取组件操作

    这篇文章主要介绍了Vue组件跨层级获取组件操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-28
  • Vue基于localStorage存储信息代码实例

    这篇文章主要介绍了Vue基于localStorage存储信息代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-11-16
  • vue 监听 Treeselect 选择项的改变操作

    这篇文章主要介绍了vue 监听 Treeselect 选择项的改变操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-01
  • 解决Element-ui el-table合计行 show-summary 不显示的问题

    有时候需要在table的底部有合计,这时候官方给的是在table里设置,show-summary就可以了但是给table加了一个固定高度的话,就不显示了,打开控制台可以看到这个合计是存在的那么需...2020-12-11
  • antdesign-vue结合sortablejs实现两个table相互拖拽排序功能

    这篇文章主要介绍了antdesign-vue结合sortablejs实现两个table相互拖拽排序功能,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-09
  • vue 获取到数据但却渲染不到页面上的解决方法

    这篇文章主要介绍了vue 获取到数据但却渲染不到页面上的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-19
  • vue项目多环境配置(.env)的实现

    最常见的多环境配置,就是开发环境配置,和生产环境配置,本文主要介绍了vue项目多环境配置的实现,感兴趣的可以了解一下...2021-07-20
  • vue项目页面嵌入代码块vue-prism-editor的实现

    这篇文章主要介绍了vue项目页面嵌入代码块vue-prism-editor的实现,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-10-30
  • vuejs element table 表格添加行,修改,单独删除行,批量删除行操作

    这篇文章主要介绍了vuejs element table 表格添加行,修改,单独删除行,批量删除行操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-18
  • Vue 3.0中jsx语法的使用

    这篇文章主要介绍了Vue 3.0 中 jsx 语法使用,帮助大家更好的理解和使用vue框架,感兴趣的朋友可以了解下...2020-11-13
  • 解决vue的router组件component在import时不能使用变量问题

    这篇文章主要介绍了解决vue的router组件component在import时不能使用变量问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-27
  • vue Treeselect下拉树只能选择第N级元素实现代码

    这篇文章主要介绍了vue Treeselect下拉树只能选择第N级元素实现代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-01
  • vue实现同时设置多个倒计时

    这篇文章主要为大家详细介绍了vue实现同时设置多个倒计时,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-05-20
  • Ant design vue table 单击行选中 勾选checkbox教程

    这篇文章主要介绍了Ant design vue table 单击行选中 勾选checkbox教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-25
  • Vue中slot-scope的深入理解(适合初学者)

    这篇文章主要给大家介绍了关于Vue中slot-scope的深入理解,这个教程非常适合初学者,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-17
  • vue实现div单选多选功能

    这篇文章主要为大家详细介绍了vue实现div单选多选功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-07-16