问题描述:
pro 后台在没有勾选二级菜单下的一个菜单时,用子管理员登录直接进入了 403 页面;
可能原因:
1. 后台没有返回对应的菜单权限(可行性较小,已经勾选对应菜单)
2. 后台登录后跳转问题(很有可能是跳转到了没有权限的菜单内导致直接进入了 403,可能性贴别大)
最终问题:
由于前台路由定义,大路由组上都自带有重定向到子路由上的功能,导致在进入某个大菜单下直接跳转进入重定向的路由上导致的。这个问题完全吻合问题 2 的可能性。
处理方式:
修改所有路由组的自动重定向功能,禁用掉;
这样修改后却出现了进入后台没有底部菜单,也没有左侧菜单的问题
那么这是由于什么问题导致的呢?
如下图,发现顶部菜单是在 main.js 中的 watch 监听路由中设置的。
注意:getHeaderName 方法时为了从当前路由找到当前顶部菜单到底是谁
而这时 headerName 却为 null 导致顶部菜单根本无法设置;
1. 没有找到顶部菜单,那么就是路由调整的地址有问题,没有在当前权限菜单的路由里面导致没有找到;
2. 登录的时候进行了跳转不会是,登录的时候跳转的路由地址有问题;
3. 如果调整登录的处理跳转地址,是否能解决此问题。答案是肯定的;
经过了如上分析,发现根本原因就是:登录跳转的路径不对。进入 403 页面后返回主页的跳转路由也是不对导致。进入 403 后,就成了死循环。
最终处理方式:
1. 修改路由组中的重定向,下图中的文件内,注释掉重定向
如下图
这样就处理掉了,没有勾选子菜单的第一个菜单导致出现的 403 问题
2. 修改登录写入订单和侧边菜单和返回主页条状路径
import { getHeaderName, getHeaderSider, getMenuSider } from '@/libs/system';
getChilden(data) {
if(data.length && data[0].children) {
return this.getChilden(data[0].children)
}
return data[0].path
},
AccountLogin({
account: this.formInline.username,
pwd: this.formInline.password,
imgcode: this.formInline.code}).then(async res => {
msg();
if (!res.data.unique_auth.length)
return this.$Message.error('您暂无任何菜单权限');
this.$store.dispatch('admin/account/setPageTitle')
let expires = res.data.expires_time;
// 记录用户登陆信息
util.cookies.set('uuid', res.data.user_info.id, {
expires: expires
});
util.cookies.set('token', res.data.token, {
expires: expires
});
util.cookies.set('expires_time', res.data.expires_time, {
expires: expires
});
const db = await this.$store.dispatch('admin/db/database', {
user: true
});
// 保存菜单信息
// db.set('menus', res.data.menus).set('unique_auth', res.data.unique_auth).set('user_info', res.data.user_info).write();
db.set('unique_auth', res.data.unique_auth).set('user_info', res.data.user_info).write();
const menuSider = res.data.menus;
### 写入菜单
this.$store.commit('admin/menus/getmenusNav', menuSider);
let headerSider = getHeaderSider(res.data.menus);
### 写入顶级菜单
this.$store.commit('admin/menu/setHeader', headerSider);
### 找到当前菜单一个跳转的子菜单
let toPath = this.getChilden(res.data.menus);
// 获取侧边栏菜单
const headerName = getHeaderName({
path: toPath,
query:{},
params:{},
}, menuSider);
const filterMenuSider = getMenuSider(menuSider, headerName);
// 指定当前显示的侧边菜单
this.$store.commit('admin/menu/setSider', filterMenuSider[0].children);
//设置首页path
this.$store.commit('admin/menus/setIndexPath', toPath);
// 记录用户信息
this.$store.dispatch('admin/user/set', {
name: res.data.user_info.account,
avatar: res.data.user_info.head_pic,
access: res.data.unique_auth,
logo: res.data.logo,
logoSmall: res.data.logo_square,
version: res.data.version,
newOrderAudioLink: res.data.newOrderAudioLink
});
// if (this.jigsaw) this.jigsaw.reset();
### 调整的地址也需要调整 toPath就是当前跳转的第一个子菜单
return this.$router.replace({ path: this.$route.query.redirect || toPath || '/admin/' });}).catch(res => { console.log(res); msg(); let data = res === undefined ? {} : res; this.errorNum++; this.captchas(); this.$Message.error(data.msg || '登录失败');});
复制代码
手机号登录的时候需要修改成相同的逻辑
3. 修改获取顶部菜单条状的 path 路径,文件路径:/src/store/modules/admin/modules/menu.js
/**
* @description 根据 user 里登录用户权限,对顶栏菜单进行鉴权过滤
*
*/
filterHeader(state, getters, rootState) {
function getChilden(data) {
if(data.children) {
return getChilden(data.children[0])
}
return data.path
}
// 之前是获取了一级跳转路径,现在改为获取子菜单的第一个菜单路径,
// 这样在点击顶部菜单的时候,跳转路径保证正确
// 调用递归函数
state.header.forEach(item => {
item.path = getChilden(item)
})
// @权限
const userInfo = rootState.admin.user.info;
const access = userInfo.access;
if (access && access.length) {
return state.header.filter(item => {
let state = true;
if (item.auth && !includeArray(item.auth, access)) state = false;
return state;
});
} else {
return state.header.filter(item => {
let state = true;
if (item.auth && item.auth.length) state = false;
return state;
});
}
},
复制代码
4. 修改进入 403 页面返回首页的路径
/src/store/modules/admin/modules/menus.js
export default {
namespaced: true,
state: {
menusName: getMenusName(),
//返回首页path
indexPath: '',
},
mutations: {
getmenusNav (state, menuList) {
state.menusName = menuList;
let storage = window.localStorage;
storage.setItem('menuList', JSON.stringify(menuList));
},
/**
* @description 设置返回首页path
* @param {Object} state vuex state
* @param {Array} menu menu
*/
setIndexPath(state, data) {
state.indexPath = data;
},
},
getters:{
//增加了返回首页的条状路径获取,在登录的页面已经设置过。
indexPath(state, getters) {
const menus = state.menusName;
if (menus.length && !state.indexPath) {
let getChilden = function(data) {
if(data.length && data[0].children) {
return getChilden(data[0].children)
}
return data[0].path
}
let toPath = getChilden(menus);
state.indexPath = toPath;
} else if (!menus.length && !state.indexPath) {
return '/admin/home'
}
return state.indexPath;
},
},
}
复制代码
然后可以修改 403 页面的跳转路径
/src/pages/system/error/403/index.vue
<template>
<div>
<Exception type="403" img-color :desc="$t('page.exception.e403')" :back-text="$t('page.exception.btn')" :redirect="indexPath"/>
</div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
data(){
return {
}
},
computed: {
...mapGetters('admin/menus', [
'indexPath'
])
},
}
</script>
复制代码
修改完成后大功告成,设置的子菜单第一个菜单不用设置也能进入后台了。
源码附件已经打包好上传到百度云了,大家自行下载即可~
链接: https://pan.baidu.com/s/14G-bpVthImHD4eosZUNSFA?pwd=yu27
提取码: yu27
复制代码
百度云链接不稳定,随时可能会失效,大家抓紧保存哈。
如果百度云链接失效了的话,请留言告诉我,我看到后会及时更新~
开源地址
码云地址:http://github.crmeb.net/u/defu
Github 地址:http://github.crmeb.net/u/defu
评论