1.動的ルーティングの分析
- 動的ルーティングの生成ロジックは次のとおりです。
- ユーザーロールの
@router
読み取りasyncRoutes
とconstantRoutes
取得からroles
、roles
を含めるかどうかを決定しますadmin
。 - に保存されたフィルター
roles
が含まれている場合。admin
asyncRoutes
vuex
roles
含まれていない場合はadmin
、トラバースroutes
してアクセスルートかどうかを判断します。そうでない場合は、トラバースを続けますroutes
。その場合、ルートが含まれてchildren
いるかどうかを確認します。含まれている場合はchildren
、トラバースchildren
、フィルタリングchildren
、更新tmp.children
してからパスインして、ルートが含まれてchildren
いるかどうかを判断します。そうでない場合はchildren
、に保存されres
たフィルターへのルート。asyncRoutes
vuex
- フィルター
asyncRoutes
に保存されvuex
、中央、asyncRoutes
およびconstantRoutes
マージ。
第二に、動的ルーティングの実現
- キーは、ルーティング動的生成する方法である
premission.js
にgenerateRoutes
次のようにコードである、方法。
const actions = {
// 生成动态路由的关键方法
generateRoutes({
commit }, roles) {
// 返回 Promise 对象
return new Promise(resolve => {
let accessedRoutes
if (roles.includes('admin')) {
// 如果角色中包含 admin,则直接跳过判断,直接将 asyncRoutes 全部返回
accessedRoutes = asyncRoutes || []
} else {
// 如果角色中不包含 admin,则调用 filterAsyncRoutes 过滤路由
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
}
// 将路由保存到 vuex 中
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
}
}
mutations
でSET_ROUTES
次のように、コードは次のとおりです。
const mutations = {
SET_ROUTES: (state, routes) => {
// 将 routes 保存到 state 中的 addRoutes
state.addRoutes = routes
// 将 routes 集成到 src/router/index.js 中的 constantRoutes 中
state.routes = constantRoutes.concat(routes)
}
}
- ルートフィルタリングの方法
filterAsyncRoutes
、コードは次のとおりです。
/**
* @param routes 异步加载的路由
* @param roles 用户的角色,数组形式
*/
// 路由过滤
export function filterAsyncRoutes(routes, roles) {
const res = []
// 遍历全部的路由
routes.forEach(route => {
// 对路由进行浅拷贝,注意 children 不会拷贝,因为不需要对 children 进行判断,所有可以直接使用
const tmp = {
...route }
// 检查用户角色是否具备访问路由的权限
if (hasPermission(roles, tmp)) {
// 当路由具备访问的权限时,判断路由是否具备 children 属性
if (tmp.children) {
// 当路由包含 children 时,对 children 迭代调用 filterAsyncRoutes 方法
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
// 当路由具有访问权限时,将 tmp 保存到 res 中
res.push(tmp)
}
})
return res
}
- 権限を確認する方法
hasPermission
、コードは次のとおりです。
// 检查权限的方法
function hasPermission(roles, route) {
// 检查路由是否包含 meta 和 meta.roles 属性
if (route.meta && route.meta.roles) {
// 判断 route.meta.roles 中是否包含用户角色 roles 中的任何一个权限,如果包含则返回 true
return roles.some(role => route.meta.roles.includes(role))
} else {
// 如果路由没有 meta 或 meta.roles 属性,则视为该路由不需要进行权限控制,所有用户对该路由可访问
return true
}
}
- 完全なコアコードは次のとおりです
。premission.js
import {
asyncRoutes, constantRoutes } from '@/router'
// 检查权限的方法
function hasPermission(roles, route) {
// 检查路由是否包含 meta 和 meta.roles 属性
if (route.meta && route.meta.roles) {
// 判断 route.meta.roles 中是否包含用户角色 roles 中的任何一个权限,如果包含则返回 true
return roles.some(role => route.meta.roles.includes(role))
} else {
// 如果路由没有 meta 或 meta.roles 属性,则视为该路由不需要进行权限控制,所有用户对该路由可访问
return true
}
}
// 路由过滤
export function filterAsyncRoutes(routes, roles) {
const res = []
// 遍历全部的路由
routes.forEach(route => {
// 对路由进行浅拷贝,注意 children 不会拷贝,因为不需要对 children 进行判断,所有可以直接使用
const tmp = {
...route }
// 检查用户角色是否具备访问路由的权限
if (hasPermission(roles, tmp)) {
// 当路由具备访问的权限时,判断路由是否具备 children 属性
if (tmp.children) {
// 当路由包含 children 时,对 children 迭代调用 filterAsyncRoutes 方法
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
// 当路由具有访问权限时,将 tmp 保存到 res 中
res.push(tmp)
}
})
return res
}
const state = {
routes: [],
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
// 将 routes 保存到 state 中的 addRoutes
state.addRoutes = routes
// 将 routes 集成到 src/router/index.js 中的 constantRoutes 中
state.routes = constantRoutes.concat(routes)
}
}
const actions = {
// 生成动态路由的关键方法
generateRoutes({
commit }, roles) {
// 返回 Promise 对象
return new Promise(resolve => {
let accessedRoutes
if (roles.includes('admin')) {
// 如果角色中包含 admin,则直接跳过判断,直接将 asyncRoutes 全部返回
accessedRoutes = asyncRoutes || []
} else {
// 如果角色中不包含 admin,则调用 filterAsyncRoutes 过滤路由
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
}
// 将路由保存到 vuex 中
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
user.js
import {
login, logout, getInfo } from '@/api/user'
import {
getToken, setToken, removeToken } from '@/utils/auth'
import router, {
resetRouter } from '@/router'
const state = {
token: getToken(),
name: '',
avatar: '',
introduction: '',
roles: []
}
const mutations = {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_INTRODUCTION: (state, introduction) => {
state.introduction = introduction
},
SET_NAME: (state, name) => {
state.name = name
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
SET_ROLES: (state, roles) => {
state.roles = roles
}
}
const actions = {
login({
commit }, userInfo) {
const {
username, password } = userInfo
return new Promise((resolve, reject) => {
login({
username: username.trim(), password: password }).then(response => {
const {
data } = response
commit('SET_TOKEN', data.token)
setToken(data.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
getInfo({
commit, state }) {
return new Promise((resolve, reject) => {
getInfo(state.token).then(response => {
const {
data } = response
if (!data) {
reject('Verification failed, please Login again.')
}
const {
roles, name, avatar, introduction } = data
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)
})
})
},
logout({
commit, state, dispatch }) {
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken()
resetRouter()
dispatch('tagsView/delAllViews', null, {
root: true })
resolve()
}).catch(error => {
reject(error)
})
})
},
resetToken({
commit }) {
return new Promise(resolve => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken()
resolve()
})
},
async changeRoles({
commit, dispatch }, role) {
const token = role + '-token'
commit('SET_TOKEN', token)
setToken(token)
const {
roles } = await dispatch('getInfo')
resetRouter()
const accessRoutes = await dispatch('permission/generateRoutes', roles, {
root: true })
router.addRoutes(accessRoutes)
dispatch('tagsView/delAllViews', null, {
root: true })
}
}
export default {
namespaced: true,
state,
mutations,
actions
}