1. 程式人生 > >vue之前端鑑權

vue之前端鑑權

  vue專案前端鑑權方式常用的有以下三種:

    1、渲染選單時控制模組按鈕的顯示隱藏(不足:直接輸入連結仍然可以訪問模組)

    2、在路由導航守衛中攔截,針對沒有許可權的模組進行重定向(不足:每次訪問模組都需要鑑定許可權,模組數量過多時會影響系統性能)

    3、藉助vue-router 2.x版本新加的API addRouters動態新增路由資訊(不足:首次載入需要解析和新增,多跳轉一次路由)

  綜上所述,權衡之後選擇了addRoutes動態新增,首屏載入時間可能會多出0.5s左右,載入一次之後後續就不需要再進行處理,可以提升系統的可靠性與穩定性。具體使用如下:

    1、定義固定路由,用於路由初始化,如:登入頁、404頁面等

const router = new Router({
    // mode: 'history',
    // base: base,
    routes: [
        {
            path: '/',
            name: '',
            component: () => import('@/views/login/login') ,
            meta:{label: '登入'}
        }
    ],
    scrollBehavior(to, from, savedPosition) {
        if (savedPosition) {
            return savedPosition
        } else {
            return {
                x: 0,
                y: 0
            }
        }
    }
});    

    2、路由導航守衛前置攔截

      為了方便,將路由許可權資訊儲存到vuex中,在路由跳轉時,判斷state中是否存在menu資訊,如果不存在,則向後端請求許可權資訊,此部分需要阻塞頁面的跳轉,改為同步執行;

      針對一般選單巢狀路由,需要對路由資訊最好進行扁平化處理,否則可能導致路由重複新增或者新增失敗(上級有父元件會導致重複新增,上級沒有元件單純巢狀會導致新增失敗)

//重新整理頁面後,會導致動態生成的路由失效,需要重新走下新增路由操作
let registerRouteRefresh = true;

router.beforeEach(async (to, from, next) => {
    //如果不存在選單資訊,則走動態授權
    if (store.state.menus.length === 0) {
        //確保初始化資訊完成後才會執行下一步動作
        await init();
        let nodesList = [];
        //遞迴獲取許可權選單列表
        initNodes(menuNodes, nodesList);
        store.commit('UPDATE_DATA', {
            key: 'menus',
            value: nodesList
        });
        //獲取路由許可權資訊
        const asyncNodes = getAsyncNodes(nodesList, []);
        //新增擁有許可權的路由資訊
        router.addRoutes(asyncNodes);
        registerRouteRefresh = false;
        next({
            ...to,
            replace: true
        })
    }else {
        //如果是頁面重新整理,需要重新載入下動態路由
        if (registerRouteRefresh) {
            let nodesList = [];
            //遞迴獲取許可權選單列表
            initNodes(menuNodes, nodesList);
            //獲取路由許可權資訊
            const asyncNodes = getAsyncNodes(nodesList, []);
            //新增擁有許可權的路由資訊
            router.addRoutes(asyncNodes);
            registerRouteRefresh = false;
            //確保路由載入完成
            next({
                ...to,
                replace: true
            })
        }
        next()
    }
});

  注意:

    1、由於路由時動態新增的,儲存在記憶體中,頁面重新整理之後記憶體中變數也會消失,動態新增的路由也會隨之消失,所以每次重新整理頁面需要重新走一遍新增路由的流程

    2、由於路由是動態新增的,在路由跳轉時,新增的路由並沒有生效,所以還需要多跳轉一次頁面

  除此之外,按鈕的鑑權可以通過自定義指令,動態傳入條件引數來實現按鈕的顯示隱藏,指令封裝如下:

/**
 * 節點鑑權
 * {code: menuCode, flag:條件生效取反}
 */
Vue.directive('permission', {
    bind(el, binding) {
        let vv = binding.value;
        if (vv.flag) {
            el.style.display = hasPermission(vv.code) ? 'none' : 'block';
        } else {
            el.style.display = hasPermission(vv.code) ? 'block' : 'none';
        }
    }
});

  使用方法:

<button v-permission="{code: 123}"></button >