CREMB Pro 后台子管理员403问题分析

123 阅读2分钟

问题描述:

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>

修改完成后大功告成,设置的子菜单第一个菜单不用设置也能进入后台了。