(一)页面级权限:
1. 原理是基于vue-router的router.addRoutes(routes)动态路由添加。
2. src/router/index.js:初始化vue-router实例,做路由拦截。
import Vue from 'vue'
import VueRouter from 'vue-router'
import { commonRoutes } from './router'
import store from '@/store/index.js'
Vue.use(VueRouter)
const router = new VueRouter({
routes: commonRoutes
})
router.beforeEach((to, from, next) => {
const token = '123'
if (to.path === '/login') {
next()
}
if (token) {
if (!store.state.router.hasGetRules) {
store.dispatch('getRules').then(rules => { // 调用接口 获取后端返回的路由权限页面/按钮/组件
store.dispatch('concatRoutes', rules.page).then(routes => { // 合并页面
router.addRoutes(routes)
next({ ...to, replace: true }) // ...to避免routes还没有合并完整,replace:true路由跳转和替换之前路由
}).catch((err) => {
console.log(err)
next({ path: '/login' })
})
})
} else {
next()
}
} else {
next({ path: '/login' })
}
})
export default router
3. src/router/router.js:配置路由页面,区分不需要权限页面和需要权限页面。
import Login from '../views/login.vue'
export const commonRoutes = [ // 不需要权限的页面
{
path: '/',
redirect: '/login'
},
{
path: '/login',
name: 'Login',
component: Login
}, {
path: '*',
name: '404',
component: () => import('@/views/404.vue')
}
]
export const routerMap = [ // 需要权限页面,需要根据后端接口返回的权限做筛选
{
path: '/home',
name: 'Home',
component: () => import('@/views/home.vue')
}, {
path: '/index1',
name: 'Index1',
component: () => import('@/views/index1.vue')
}, {
path: '/index2',
name: 'Index2',
component: () => import('@/views/index2.vue')
}, {
path: '/index3',
name: 'Index3',
component: () => import('@/views/index3.vue')
}
]
4. src/store/module/router.js:单独用来做路由权限的vuex全局状态管理。
import { commonRoutes, routerMap } from '@/router/router'
import axios from 'axios'
const state = {
routers: commonRoutes,
hasGetRules: false, // 是否接口获取路由权限页面
token: '123',
componentRoutes: null // 存放组件按钮级别的权限
}
const mutations = {
concatRules (state, data) {
state.routers = data.concat(commonRoutes) // commonRoutes再数组得到后面,即把接口返回的权限页面进行筛选之后,与通同不需要权限的页面进行
state.hasGetRules = true
},
setComponentRoutes (state, data) {
state.componentRoutes = data
}
}
const filterArr = (routes, rules) => { //将再本地配置的权限路由中筛选出后端接口返回的权限匹配满足后端接口返回需要的
return routes.filter(item => {
if (rules[item.name]) {
if (item.children) {
item.children = filterArr(item.children, rules)
}
return true
} else {
return false
}
})
}
const actions = {
concatRoutes ({ commit }, rules) {
return new Promise((resolve, reject) => {
try {
let arr = []
if (Object.entries(rules).every(item => item[1])) { // Object.entries可以将对象转换为二维数组,如rules={name:1,age:2},Object.entries(rules)=[['name',1],['age',2]]
arr = routerMap /// /every 遍历 数组中每个元素为true就返回true只要有一个元素不为true就返回false
} else {
arr = filterArr(routerMap, rules)
}
commit('concatRules', arr)
resolve(state.routers)
} catch (err) {
reject(err)
}
})
},
getRules ({ commit }) {
return new Promise((resolve, reject) => {
// 发送请求调用接口
const token = state.token
axios.get('get/jurisdiction/resoure', null, { header: { token: token } }).then(res => {
let result = res || { //返回的数据格式如默认,page是页面级权限,componet是组件按钮级权限。
page: {
Home: true,
Index1: false,
Index2: true,
Index3: true
},
component: {
edit_detail_btn: false,
edit_add_btn: true
}
}
commit('setComponentRoutes', result.component)
resolve(result)
}).catch(err => {
reject(err)
})
})
}
}
export default {
state,
mutations,
actions
}
5. src/store/index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import router from './module/router'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
router
}
})
(二)组件按钮级权限:
1. 接口返回组件按钮级别的权限,通过全局状态管理存储,再通过v-if判断是否显示改权限按钮。
页面2
2. 接口返回组件按钮级别的权限,通过自定义指令去判断是否显示。
2.1 src/directive/permission.js:
import store from '@/store'
const permission = { // v-permission="['edit_detail_btn']"
inserted (el, binding) { // el是挂载改自定义指令的dom元素,binding为对当前指令的解析得对象,如v-if的binding={name:"if",expression:'ishow==true',value:true}
const { value: pRoles } = binding // {value: pRoles}是解构binding.value并取别名为pRoles
const isShowEl = pRoles.some(item => store.state.router.componentRoutes[item])
if (!isShowEl) { // 如果没有权限,就删除改标签
el.parentNode && el.parentNode.removeChild(el)
}
}
}
export default permission
2.2 再main.js中全局挂载自定义指令:
import vPermission from '@/directive/permission.js'
Vue.directive('permission', vPermission)
2.3 组件按钮中使用:
页面2