使用的是vue-admin基础版本,所以使用者要对登录过滤等流程相当熟悉
//登录界面 src/views/login/index.vue
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">Login</el-button>
//登录方法
handleLogin() {
this.$router.push({ path: this.redirect || '/' })
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
// $store 跳到 src/store/modules/user.js 中的login方法中
this.$store.dispatch('user/login',this.loginForm).then(() => {
this.$router.push({ path: this.redirect || '/' });
this.loading = false
}).catch(() => {
this.loading = false
})
} else {
console.log('error submit!!');
return false
}
})
}
src/store/modules/user.js
// user login
login({ commit }, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
//此处的login 是 src/api/user.js中的login方法
login({
loginname: username.trim(),
pwd: password
})
.then(response => {
// console.log(response);
const { data } = response
commit('SET_TOKEN', data)
setToken(data)
resolve()
}).catch(error => {
reject(error)
})
})
},
// get user info
getInfo({ commit, state }) {
return new Promise((resolve, reject) => {
//src/api/user.js中的getInfo方法
getInfo().then(response => {
// console.log(response);
const { data } = response;
if (!data) {
reject('Verification failed, please Login again.')
}
const { roles, name, avatar, introduction } = data;
// console.log(roles);
// roles must be a non-empty array
if (!roles || roles.length <= 0) {
reject('getInfo: roles must be a non-null array!')
}
commit('SET_ROLES', roles)
commit('SET_NAME', name)
commit('SET_AVATAR', avatar)
commit('SET_INTRODUCTION', introduction)
resolve(data)
}).catch(error => {
reject(error)
})
})
},
//src/api/user.js中的login、getInfo方法
export function login(data) {
return request({
url: '/adminlogin',
method: 'post',
params:data
})
}
export function getInfo() {
return request({
url: '/lbo/Admin/getadmininfo',
method: 'post',
})
}
src/permission.js全局的路由守卫
import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login'] // no redirect whitelist
router.beforeEach(async(to, from, next) => {
// start progress bar
NProgress.start()
// set page title
document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
// if is logged in, redirect to the home page
next({ path: '/' })
NProgress.done()
} else {
// const hasGetUserInfo = store.getters.name <-vue-admin基础模板的内容
/*更改后的语句 需要注意store.getters.roles 基础模板中没有提供,所以getters不到roles,在src/store/getters中自己加入*/
// ---------------------此部分不在permission.js中 --------------------
const getters = {
sidebar: state => state.app.sidebar,
device: state => state.app.device,
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
roles: state => state.user.roles, //此条为添加内容
}
export default getters
//-----------------------------------------------------------------------
const hasRoles = store.getters.roles && store.getters.roles.length > 0
//通过打印测试
// console.log(store.getters.roles);
// console.log(store.getters.roles.length);
if (hasRoles) {
next()
} else {
try {
// get user info
// await store.dispatch('user/getInfo')
const {roles}=await store.dispatch('user/getInfo');
// console.log(roles); //已经获取到["root", __ob__: Observer]
// generate accessible routes map based on roles
const accessRoutes = await store.dispatch('permission/generateRoutes', roles);
// console.log(accessRoutes);
// dynamically add accessible routes
router.addRoutes(accessRoutes);
// hack method to ensure that addRoutes is complete
// set the replace: true, so the navigation will not leave a history record
next({ ...to, replace: true })
// next()
} catch (error) {
// remove token and go to login page to re-login
await store.dispatch('user/resetToken')
Message.error(error || 'Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) {
// in the free login whitelist, go directly
next()
} else {
// other pages that do not have permission to access are redirected to the login page.
next(`/login?redirect=${to.path}`);
NProgress.done()
}
}
});
router.afterEach(() => {
// finish progress bar
NProgress.done()
})
src/store/modules/permission.js (需要新建)
import { asyncRoutes, constantRoutes } from '@/router' //需要引入
/**
* Use meta.role to determine if the current user has permission
* 通过meta.role判断是否与当前用户权限匹配
* @param roles
* @param route
*/
function hasPermission(roles, route) {
if (route.meta && route.meta.roles) {
// return roles.some(role => route.meta.roles.includes(role))
return roles.some(role => route.meta.roles.includes(role))
} else {
return true
}
}
/**
* Filter asynchronous routing tables by recursion
* 递归过滤异步路由表,返回符合用户角色权限的路由表
* @param routes asyncRoutes
* @param roles
*/
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
}
const state = {
routes: [],
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
console.log(state.addRoutes);
state.routes = constantRoutes.concat(routes)
console.log(state.routes);
}
}
const actions = {
generateRoutes({ commit }, roles) {
return new Promise(resolve => {
let accessedRoutes;
// if (roles.includes('admin')) {
// console.log(roles.indexOf('root'));
if (roles.includes('root')) { //此处的root根据自己需求填写
accessedRoutes = asyncRoutes || []
} else {
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
}
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
src/router/index
最关键的部分普通路由跟动态路由
meta: { roles:[‘root’,‘editor’] }, 通过roles进行设置权限控制
/**
* Note: sub-menu only appear when route children.length >= 1
* Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
*
* hidden: true if set true, item will not show in the sidebar(default is false)
* alwaysShow: true if set true, will always show the root menu
* if not set alwaysShow, when item has more than one children route,
* it will becomes nested mode, otherwise not show the root menu
* redirect: noRedirect if set noRedirect will no redirect in the breadcrumb
* name:'router-name' the name is used by <keep-alive> (must set!!!)
* meta : {
roles: ['admin','editor'] control the page roles (you can set multiple roles)
title: 'title' the name show in sidebar and breadcrumb (recommend set)
icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
}
*/
/**
* constantRoutes
* a base page that does not have permission requirements
* all roles can be accessed
*/
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [{
path: 'dashboard',
name: '519后台管理',
component: () => import('@/views/dashboard/index'),
meta: { title: '519后台管理', icon: 'dashboard' }
}]
},
]
export const asyncRoutes = [
{
path: '/example',
component: Layout,
redirect: '/example/table',
name: '招新管理',
meta: { title: '招新管理', icon: 'el-icon-s-help',roles:['root','editor'] },
children: [
{
path: 'application',
name: '申请加入学员',
component: () => import('@/views/application/index'),
meta: {
title: '申请加入学员',
icon: 'table',
roles:['root']
}
},
{
path: 'student',
name: '学员列表',
component: () => import('@/views/student/index'),
meta: { title: '学员列表',
icon: 'table',
roles:['root','editor']
}
},
{
path: 'addStud',
name: '添加学员',
component: () => import('@/views/addStud/index'),
meta: { title: '添加学员', icon: 'tree',roles:['root'] },
},
{
path: 'attend',
name: '学员考勤',
component: () => import('@/views/attend/index'),
meta: { title: '学员考勤', icon: 'tree',roles:['root','editor'] }
},
{
path: 'studentTime',
name: '学员学习时间',
hidden: true,
component: () => import('@/views/studentTime/index'),
meta: { title: '学员学习时间', icon: 'tree',roles:['root','editor'] }
}
]
},
// 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true }
]
最后就是在全局的permission中
const accessRoutes = await store.dispatch('permission/generateRoutes', roles);
console.log(accessRoutes);
此时就遇到问题啦控制台可以打印,但是页面没有渲染上去
通过对mode/permission中路由进行分析
通过打印控制台输出发现routes存进去啦,问题就又回到了getters上
//是mode/permission
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
console.log(state.addRoutes);
state.routes = constantRoutes.concat(routes)
console.log(state.routes);
}
}
通过分析集成版的vue-admin发现
src/store/getters
const getters = {
sidebar: state => state.app.sidebar,
size: state => state.app.size,
device: state => state.app.device,
visitedViews: state => state.tagsView.visitedViews,
cachedViews: state => state.tagsView.cachedViews,
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
introduction: state => state.user.introduction,
roles: state => state.user.roles,
<---------------------------------->
permission_routes: state => state.permission.routes,
<---------->
errorLogs: state => state.errorLog.logs
}
export default getters
光标移动到permission_routes中按住ctrl+鼠标点击
发现了奥秘,鼠标点击进入到src/layout/components/Sidebar/index中,
发现了路由没有渲染到页面的原因
最后问题解决😀