Vue权限管理
这些天XX老师带着做了一个项目实战,把Vue权限管理相关内容整理一下,目的有二:其一,整理整个过程的逻辑思路;其二,备日后参考改进。
思路
- 后端返回需展示数据
- 后端只返回用户权限
后端返回需展示数据(只概述思路)
- 后端返回数据实例
其中:title=>面包屑 component =>方便进行组件拼接 icon =>导航栏图标
const routesdata = [
{path:'/index',name:'index',title:'首页',component:'index',icon:'a'},
{path:'/loan-input',name:'loan-input',title:'贷款申请',component:'loan-input',icon:'icona'},
{path:'/index',name:'/index',title:'首页',component:'index',icon:'a'},
]
- 创建routes数组,遍历routesdata数组,并按照标准路由格式,追加到routes中,最后形成一个和静态路由相似样式的数组对象。
- 再利用router.addRoutes方法,把生成的路由数组对象routes追加到router中
感觉这种方式需要前端和后端的沟通,前端要明确自己需要那些数据,后端才能进行相应的传值。
后端只返回用户权限
后端只需要返回用户权限,剩下的数据筛选过滤都由前端来完成。需要修改的有三个文件:
【路由】【Vuex】【导航栏Nav】
- 设置两个存放路由的数组对象,分别是路由的常规配置和异步路由,其中异步路由对象需要添加一个权限参数roles
- 设置路由拦截,在路由跳转之前,获取用户权限信息,然后追加路由和设置导航栏的递归
方式二实现步骤
1.router/index.js文件
//两个路由数组定义
//常规配置
export const constantRoutes = [
{
path: '/',
redirect:'/home'
},
{
path: '/login', //登录
name: 'login',
component: () => import('../views/login/index')
},
{
path: '/home', //布局页
name: 'home',
redirect: '/index',
meta: {title: '首页',roles:['input','approve']},
component: () => import('../layout/index'),
}
]
//异步路由 注意:为meta添加了roles对象,用于路由过滤,其中input和approve必须和后端返回权限一致。
export const asyncRoutes = [ //异步路由
{
path: '/index', //首页
name: 'index',
meta:{title:'首页',roles: ['input','approve']},
component: () => import('../views/home/index')
},
{
path: '/loan-input', //贷款申请
name: 'loan-input',
meta:{title:'贷款申请',roles: ['input']},
component: () => import('../views/loan-input/index')
},
{
path: '/input-manager',
name: 'input-manager',
meta: { title: '申请管理' ,roles: ['input']},
component: () => import('../views/input-manager/index'),
},
{
path: '/loan-approve', //贷款审批
name: 'loan-approve',
meta:{title:'贷款审批',roles: ['approve']},
component: () => import('../views/loan-approve/index'),
children:[
{
path: '/loan-approve/first', //初审
name: 'first',
meta:{title:'初审'},
component: () => import('../views/loan-approve/first')
},
{
path: 'end', //终审
name: 'end',
meta:{title:'终审'},
component: () => import('../views/loan-approve/end')
},
]
},
{
path: '/contract',
name: 'contract',
meta: { title: '标的管理' ,roles: ['approve']},
component: () => import('@/views/contract/index'),
},
{
path: '/permission',
name: 'permission',
meta: { title: '权限管理'},
component: () => import('@/views/permission/index'),
children:[
{
path: '/permission/list',
meta: { title: '列表展示' },
component: () => import('@/views/permission/list'),
}
]
},
]
const router = new VueRouter({
routes:constantRoutes //这里只赋值constantRoutes
})
2.permission.js文件
功能:进行路由拦截
router.beforeEach(async(to,from,next)=>{
if(to.path=='/login'){
next();
}else {
var getRoles = store && store.getters.roles && store.getters.roles.length>0;
if(getRoles) {
next();
}else {
//获取详情信息,发送请求
var {roles} = await store.dispatch('getInfo');
//取出角色
var rolesName= roles.map(v=>v.name);
//过滤角色
var filterRoutes = await store.dispatch('GENERATEROUTES',rolesName);
//动态添加
router.addRoutes(filterRoutes);
if(roles) {
next({path:to.path})
}else {
next({path:'/login'})
}
}
}
})
3.store中的permission.js:进行角色过滤
import {constantRoutes,asyncRoutes} from '@/router'
function filterAsyncRouter(routes,name){ //过滤角色
var data = routes.filter(route=>{
return route.meta && route.meta.roles && name.some(v=>route.meta.roles.includes(v))
})
return data;
}
const state={
routes:[] //动态路由
};
const getters={
get_routes:state=>state.routes,
};
const actions={
GENERATEROUTES({commit,state},rolesName){ //通过角色来过滤路由
return new Promise((resolve, reject) => {
var _routes; //
let home = constantRoutes.filter(v=>v.path=='/home')[0]; //
home.children = []; //清除
if(rolesName.includes('administrator')){ //是否是管理员
home.children = asyncRoutes;
}else {
let filterRouter = filterAsyncRouter(asyncRoutes,rolesName);
home.children = filterRouter;
};
_routes = [home] || [];
commit('SET_ROUTES', _routes);
resolve(_routes)
})
},
};
const mutations={
SET_ROUTES:(state,routes)=>{
state.routes = routes;
}
};
export default{
state,
getters,
mutations,
actions
}
4.设置导航栏
NavMenu.vue
<template>
<el-aside width="200px" class="aside">
<!-- 左侧导航 -->
<el-menu
:default-active="$route.path" exact
router>
<sideItem v-for="v in get_routes[0].children" :key="v.path" :item="v" :path="v.path"/>
</el-menu>
</el-aside>
</template>
<script>
import {mapGetters} from 'vuex'
import sideItem from './sideItem'
export default {
data(){
return {
}
},
computed:{
...mapGetters(['get_routes'])
},
components:{
sideItem
}
}
</script>
//sideItem.vue
<template>
<div>
<!-- 没有子级 -->
<el-menu-item :index="path" v-if="!item.children">
<i class="el-icon-setting"></i>
<span slot="title">{{item.meta.title}}</span>
</el-menu-item>
<!-- 有子级 -->
<el-submenu :index="path" v-else>
<template slot="title">{{item.meta.title}}</template>
<sideItem v-for="child in item.children" :key="child.path" :item="child" :path="getPath(child.path)"/>
</el-submenu>
</div>
</template>
<script>
import _path from 'path'
export default {
name:'sideItem',
data(){
return {
}
},
props:["item","path"],
methods:{
//_path.resolve('a/b','./c') '/a/b/c'
getPath(url){
return _path.resolve(this.path,url);
}
}
}
</script>