业务背景
开发后端管理系统要点就是权限控制和安全性
一切从登录开始
从用户想进入管理系统输入账户和密码,然后发送到后端进行账户和密码的正确性验证,如果账户和密码正确,后端就会返回一个独一无二的属于该用户的token,这个时候我们要做的就是把token存起来,存到cookie、session、localStorage、vuex看自己的需求,我这里根据项目要求存到是vuex,vuex配合的是sessionStorage来保持页面刷新不丢失vuex中的数据
使用token换取用户信息
后端的设计一般都是有了token之后在调用获取用户信息接口来拿到登录者的相关信息,比如登录名,头像,对于后端管理系统,还有权限信息列表,这个是后面做权限控制的主要依据
开始权限控制-vue-router的导航守卫
- 方案一:
获取到权限列表之后,计算出对应权限的路由组成路由表,然后使用router.addRoutes()动态挂载路由,参考自花裤衩https://juejin.im/post/591aa14f570c35006961acac
使用这个方案带来的问题就是如果用户刷新浏览器,保存在vuex甚至保存在sessionStorage和localStorage都会失效,失效原因是在用户刷新页面的时候,vue整个程序程序加载,重新执行了main.js这样的话router也被初始化了,初始化成了那些不需要权限的页面路由,但是我们的也可以在main.js再次检测需要权限的路由,重新使用addRouters添加动态路由,但是会报一个路由命名重复的警告,可是我代码逻辑有问题,这个bug我解决不了就找了公司大佬,大佬给我方案二的思路
- 方案二
直接在路由配置文件的时候就把所有需要权限的页面使用路由meta属性写好,然后在main.js加载的时候判断是否有权限进入改页面,不使用addRouter动态添加,这样就能保证即使用户刷新页面,router初始化的时候也把所有路由初始化好了,我们只需要在导航守卫的回掉函数里面进行权限鉴定即可,而且这个守卫权限鉴定是全局的,只要有路由变化,都会进行权限鉴定
main.js文件
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './vuex/store'
import '@/reqConfig/index.js'
import token from '@/reqConfig/token.js'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import '@/assets/reset.css'
Vue.use(ElementUI)
Vue.config.productionTip = false
// [skip 跳转登录页面]
function skip () {
// 异常退出清理session和token
sessionStorage.clear()
token.clearToken()
window.location.href = process.env.VUE_APP_LOGOUT_URL
}
// 全局路由导航守卫
router.beforeEach((to, from, next) => {
let userInfo = store.state.userinfo.userInfo
if (userInfo) {
if (userInfo.account_available) {
let roles = userInfo.permissions
// 判断该用户是否有权限进入页面
if (to.meta.role) {
let isHasPermission = to.meta.role.every(item => {
return roles.includes(item)
})
if (isHasPermission) {
next()
} else {
ElementUI.Message.error('暂无权限访问该页面,请于管理人员联系')
}
} else {
next()
}
} else {
ElementUI.Message({
type: 'error',
message: '暂无权限访问该系统,请于管理人员联系',
onClose: function () {
skip()
}
})
}
} else {
let key = sessionStorage.getItem('sso-token')
if (!key) {
skip()
} else {
store.dispatch('getXStreamId').then(() => {
store.dispatch('getUserInfo').then(res => {
userInfo = store.state.userinfo.userInfo
if (userInfo.account_available) {
let roles = userInfo.permissions
// 判断该用户是否有权限进入页面
if (to.meta.role) {
let isHasPermission = to.meta.role.every(item => {
return roles.includes(item)
})
if (isHasPermission) {
next()
} else {
ElementUI.Message.error('暂无权限访问该页面,请于管理人员联系')
}
} else {
next()
}
} else {
ElementUI.Message({
type: 'error',
message: '暂无权限访问该系统,请于管理人员联系',
onClose: function () {
skip()
}
})
}
})
}).catch(() => {
skip()
})
}
}
})
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
路由配置文件
import Vue from 'vue'
import Router from 'vue-router'
import A from '@/views/A.vue'
import B from '@/views/B.vue'
import C from '@/views/C.vue'
import D from '@/views/D.vue'
Vue.use(Router)
export const routerMap = [
{
path: '/',
name: 'A',
component: A
},
{
path: '/b',
name: 'B',
component: B,
meta: { role: ['权限标志字段,比如需要是admin才能访问'] }
},
{
path: '/c',
name: 'C',
component: C,
meta: { role: [权限标志字段,比如需要是super admin才能访问] }
},
{
path: '/d',
name: 'D',
component: D,
meta: { role: [权限标志字段,比如需要是boss才能访问] }
}
]
export default new Router({
routes: routerMap
})