vue admin 动态路由权限管理
主要思路 通过后端接口返回数据进行判断(通过后端实现的权限管理有许多种),在这里 我们主要通过 关键字即匹配前端路由meta.menu值来实现权限管理通常会把路由权限列表存至vux中箭头所指的便是后端接口返回的权限列表实现方法通过 通过 配置路由meta.menu 和 router.addRoute来实现权限匹配 和添加第一步 在router/index.js 中完成 无需权限路由的配置 我这里配
·
主要思路 通过后端接口返回数据 进行判断 (通过后端实现的权限管理有许多种),在这里 我们主要通过 关键字
即匹配前端路由meta.menu值
来实现权限管理通常会把路由权限列表存至vux中
箭头所指的便是 后端接口返回的权限列表
meta.menu来实现权限匹配
通过 router.addRoute来实现路由添加
通过meta.hidden 来决定是否在侧边栏展示当前页面
实现方法通过 通过 配置路由第一步 在router/index.js
中完成 无需权限路由的配置
我这里配备的便是 登录 404
和首页
const routes = [{
path: '/login',
component: () => import('@/views/Login.vue'),
meta: {
title: '登录'
}
},
{
path: '/404',
name: '404',
component: () => import('@/views/error/404'),
hidden: true
},
{
path: '',
redirect: '/',
component: Layout,
children: [{
path: '/',
component: () =>
import('../views/Home.vue'),
meta: {
title: '首页',
parentpath: '/home'
}
}]
}
]
第二步 动态权限的配置存放在vueX中
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
rolelist: [], // 后端返回的路由数据
asyncRouters: [], // 所有需要分配权限的路由
finallyRouters: [], // 最终筛选出的路由
},
mutations: {
setRoleList(state, data) {
state.rolelist = data
},
setAsyncRouter(state, asyncRouters) {
state.asyncRouters = asyncRouters
},
setFinallyRouters(state, data) {
// 因为总体是用addRoute 添加 所以这儿用的concat 一个一个拼接
state.finallyRouters = state.finallyRouters.concat(data)
// console.log(state.finallyRouters, '最后的路由')
}
},
actions: {
async SetAsyncRouter({
commit
}) {
var list = [
// 景区
{
path: '/scenic',
redirect: '/scenic/index',
component: (resolve) => require(['@/views/layout/index.vue'], resolve),
meta: {
menu: "spot",
title: '景区',
},
children: [{
path: 'index',
name: "scenicManager",
component: (resolve) => require(['@/views/scenic/index.vue'], resolve),
meta: {
title: '景区管理',
menu: "scenic"
}
},
//景区
{
path: 'detail',
name: 'scenicDetail',
hidden: true,
component: (resolve) => require(['@/views/scenic/components/detail.vue'], resolve),
meta: {
title: '景区详情',
menu: "scenic",
}
},
{
path: 'manage/detail',
name: "scenicManageDetail",
hidden: true,
component: (resolve) => require(['@/views/scenic/components/manageDetail.vue'], resolve),
meta: {
title: '管理详情',
menu: "scenic"
}
},
]
},
// 用户
{
path: '/User',
redirect: '/User/index',
component: () => import('@/views/layout/index.vue'),
meta: {
title: '会员',
menu: "member"
},
children: [
// 用户
{
path: 'index',
name: 'User',
component: (resolve) => require(['@/views/member/user/index.vue'], resolve),
meta: {
title: '用户',
menu: "user"
}
},
{
path: 'detail',
name: 'userDetail',
hidden: 'true',
component: (resolve) => require(['@/views/member/user/detail.vue'], resolve),
meta: {
title: '用户',
menu: "detail"
}
},
{
path: 'staff',
name: 'UserStaff',
component: (resolve) => require(['@/views/member/staff/index.vue'], resolve),
meta: {
title: '员工',
menu: "manager"
}
},
{
path: 'supplier',
name: 'UserSupplier',
component: (resolve) => require(['@/views/member/supplier/index.vue'], resolve),
meta: {
title: '供应商',
menu: "thirdPlat"
}
},
]
},
commit('setAsyncRouter', list)
},
},
modules: {},
getters: {
asyncRouters(state) {
return state.asyncRouters
}
}
})
第三步 路由守卫中拦截 和添加动态路由可在main.js 或者router/index.js
中写
// 关键 添加flag防止多次获取动态路由和栈溢出
let asyncRouterFlag = 0;
router.beforeEach(async (to, from, next) => {
const token = window.localStorage.getItem('token')
document.title = to.meta.title
if (to.path == '/login') {
next()
} else {
if (!token) {
next('/login')
} else {
if (!asyncRouterFlag) {
// 添加flag防止多次获取动态路由和栈溢出
asyncRouterFlag++
//同步调用获取菜单方法
await store.dispatch('SetAsyncRouter') //发请求获取菜单,并将菜单设置到vuex中,
const asyncRouters = store.getters['asyncRouters'];
var roleList = store.state.rolelist || []
if (roleList.length > 0) {
// 自写方法 根据关键词匹配
addRouter(asyncRouters, roleList)
} else {
await api.LoginInfo().then(res => {
console.log(res, '数据')
if (res.code == 200) {
roleList = res.data.roles
store.commit('setRoleList', roleList)
console.log(4)
addRouter(asyncRouters, roleList)
} else {
Message.error(res.data.message || res.statusText);
}
}).catch(err => {
next('/login')
})
}
next({ ...to, replace: true })
} else {
next()
}
}
}
})
// 筛选出满足条件的路由 这里因人而异
function addRouter(asyncRouters, roleList) {
asyncRouters.map(item => {
if (roleList.indexOf(item.meta.menu) > -1) {
let temp = cloneLoop(item)
delete temp.children
if (item.children.length > 0) {
temp.children = []
item.children.map(item1 => {
if (roleList.indexOf(item1.meta.menu) > -1) {
temp.children.push(item1)
// 最终路由存放至vuex中
store.commit('setFinallyRouters', temp)
}
})
}
router.addRoute(temp)
}
})
// 最后 加入* 重定向404
router.addRoute({
path: '*',
redirect: "/404",
})
}
最后在实现侧边栏
<template>
<div>
<el-menu :default-active="this.$route.path" active-text-color='#13C479' class="el-menu-vertical-demo" router>
<!-- 首页 -->
<el-menu-item index="/">
// 图标 可自定义
<i class="el-icon-s-home"></i>
<span slot="title" style="margin-left:10px">首页</span>
</el-menu-item>
<el-submenu :index="item.path" v-for="(item,index) in routeList" :key="index">
<template slot="title">
<i class="el-icon-s-home"></i>
<span slot="title" style="margin-left:10px" v-if="item.meta">{{item.meta.title}}</span>
</template>
<template v-if="item.children">
<div v-for="(item1,index1) in item.children" :key="index1">
<el-menu-item :index="`${item.path}/${item1.path}`" v-if="!item1.hidden">
<i class="el-icon-s-home"></i>
<span slot="title" style="margin-left:10px" >{{item1.meta.title}}</span>
</el-menu-item>
</div>
</template>
</el-submenu>
</el-menu>
</div>
</template>
<script>
export default {
data() {
return {
routeList: []
};
},
computed: {},
watch: {},
mounted() {
// 这里把无需权限的路由复制过来
var tempRouter = [
// 订单
{
path: "/order",
component: () => import("@/views/layout/index.vue"),
redirect: "/order/index",
meta: {
title: "订单"
},
children: [
{
path: "index",
name: "orderTickets",
component: () => import("@/views/order/tickets.vue"),
meta: {
title: "系统门票订单"
}
},
{
path: "seasonTickets",
name: "orderSeasonTickets",
component: () => import("@/views/order/seasonTickets.vue"),
meta: {
title: "套餐门票订单"
}
}
]
},
// 优惠券
{
path: "/coupon",
component: () => import("@/views/layout/index.vue"),
redirect: "/coupon/index",
meta: {
title: "优惠券"
},
children: [
{
path: "index",
name: "coupon",
component: () => import("@/views/coupon/index.vue"),
meta: {
title: "优惠券"
}
}
]
}
];
// 把筛选出来的权限列表和无需权限的列表组合起来
this.routeList = [...this.$store.state.finallyRouters, ...tempRouter];
console.log(this.routeList, "全部");
},
methods: {}
};
</script>
<style lang='scss' scoped>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
/deep/ .el-menu {
background: none;
}
</style>
第四步 登录页
login() {
this.username = "";
this.password = "";
if (!this.loginForm.username) {
this.username = "请输入账号";
} else if (!this.loginForm.password) {
this.password = "请输入密码";
} else {
this.loading = true;
api
.login(this.loginForm)
.then(res => {
// console.log(res, "登陆");
if (res.code === 200) {
window.localStorage.setItem("token", res.data.token);
this.$store.commit("setRoleList", res.data.roles);
window.localStorage.setItem(
"buttenpremissions",
JSON.stringify(res.data.permissions)
);
this.$router.push("/");
}
})
.catch(err => {
console.log(err);
});
}
}
第五步 token过期后端没有返回refush-token
时,退出登录切换账号我们需要清除已经注册的路由,防止其他用户获得到已经注册好了的路由。
router.replace({path: '/login'});
window.location.reload();
service.interceptors.response.use((res) => {
console.log(res, '我是拦截')
// if(res.)
nprogress.done()
return res.data
}, err => {
let status = err.response.status
if (err.response && err.response.status) {
console.log(err.response)
if (status == 401) {
Message.error('登录失效,请刷新后重试')
router.replace({path: '/login'});
window.location.reload();
}
}
return Promise.reject(err.response)
更多推荐
已为社区贡献10条内容
所有评论(0)