vue系列之動態路由【原創】

開題

最近用vue來構建了一個小項目,因爲項目是以iframe的形式嵌套在別的項目中的,因此對於登陸的驗證就比較的麻煩,索性後端大佬們基於如今的問題提出瞭解決的方案,在看到他們的解決方案以前,我先畫了一個比較標準的單系統的解決方案。前端

本文目錄:

一: 設想

簡單解釋下上圖就是:vue

首先前端從cookie獲取token,若是沒有token就跳轉到登陸頁面登陸,登陸驗證以後生成token存在數據庫中並返回給前端;前端將這個token保存下來,爲了讓在瀏覽器新的tab頁時不須要登陸,咱們前端須要將這個token保存到cookie之中。ajax

若是用戶已經有了token,那麼再驗證是否有用戶信息,若是沒有去請求用戶信息的接口,後臺讀取用戶的基本信息返回給前端,前端根據後臺返回的用戶權限生成固定的路由表用於頁面攔截。vue-router

在用戶token和權限都有的狀況下,進入本身權限內的頁面而且攜帶token訪問後臺進行交互。vuex

用戶在退出時,請求後臺接口,清除token數據。數據庫

二: 討論

因爲公司的項目更加的複雜,屬於基於原來的系統開發新的系統模塊,可是這些模塊又爲了之後主體功能的更新下次迭代須要保持相對的獨立性,預計之後的老系統只起一個用戶中心的功能,因此如今是基於實現單點登陸的能力去迭代更新如今的新的項目。後端

今天上午對於登陸的實現進行了相關討論,因爲公司項目保密考慮只是單單作相關的介紹:api

現有的老項目將慢慢向用戶中心轉換,而之前的新項目須要去這個用戶中心獲取登陸信息。具體的實現是:瀏覽器

登陸新項目b.exaplem.com經過session檢測到未登陸時(這裏說下新的項目和老項目在同一個一級域名下),跳轉到a.exaplem.com?returnUrl='b.exaplem.com',在a.exaplem.com下成功登陸後生成一個ticket給到b.exaplem.com,b.exaplem.com將這個ticket存在session裏面來保持登陸狀態。cookie

由於如今基本上是先登陸a.exaplem.com而後再去登陸b.exaplem.com,因此當咱們第一次進入b.exaplem.com系統時,b.exaplem.com會向a.exaplem.com系統發送請求來獲取ticket,而且生成session來維持登陸狀態。

三:實現

當時想經過引入vuex並經過cookie來保存token的狀態,可是因爲如今的項目仍是後端以session的形式來維持用戶的登陸狀態因此仍是沒有引入vuex。

基本實現以下:

main.js增長引入的permission.js文件以下:

import Vue from 'vue'
import router from './router'
import { asyncRouterMap, constantRouterMap } from './router'
  
function hasPermission(roles, route) {  //
    if (route.meta && route.meta.role) {
        return roles.some(role => role === route.meta.role)
    } else {
        return true
    }
}

function filterAsyncRouter(asyncRouterMap, roles) {

    const accessedRouters = asyncRouterMap.filter(route => {
        if (hasPermission(roles, route)) {
            if (route.children && route.children.length) {
                route.children = filterAsyncRouter(route.children, roles)
            }
            return true
        }
        return false
    })

    return accessedRouters
}

//  加載頁面以前
router.beforeEach((to, from, next) => {
    NProgress.start() // 開啓Progress
    if (to.path == '/ContractAduit/Error') {
        next()
    } else if (!Vue.prototype.hasRoute) {

        Vue.prototype.$ajax.get(Vue.prototype.$api.getModuleHost("用戶信息接口地址"), {})
            .then(data => {
                if (data.code == 1000) {
                    let menus = data.menu
                    let roles = menus.map((menu, index) => {
                        return parseInt(menu.url);
                    })
                    const accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
                    router.addRoutes(accessedRouters)
                    Vue.prototype.userInfo = {
                        id: data.id,
                        realname: data.realname
                    }
                    Vue.prototype.hasRoute = true;
                    next({...to })
                } else {
                    router.push({ name: 'ErrorPageRouter' });
                }
            })
            .catch(err => console.log(err))
    } else {
        next()
    }
});

route.js文件以下:

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export const constantRouterMap = [{
        path: '/404',
        name: 'NoFoundPagetRouter',
        component: require('../views/404.page'),
        meta: {
            title: '404',
        }
    },
    {
        path: '/ContractAduit/NoAccess',
        name: 'NoAccessPageRouter',
        component: require('../views/no-access.page'),
        meta: {
            title: '無權限',
        }
    },
    {
        path: '/ContractAduit/Error',
        name: 'ErrorPageRouter',
        component: require('../views/error.page'),
        meta: {
            title: '內部錯誤',
        }
    }
]

export default new Router({
    mode: 'history',
    routes: constantRouterMap
})

export const asyncRouterMap = [{ 
        path: '/ContractAduit/Supplier/List',
        name: 'SupplierListPageRouter',
        component: require('../views/supplier/supplier-list.page.vue'),
        meta: {
            title: '某某列表頁',
            role: 10001
        }
    },
    ...
    {
        path: '/',
        redirect: '/ContractAduit/Supplier/List',
        hidden: true,
        meta: {
            title: '某某列表頁',
            role: 10001
        }
    }, {
        path: '*',
        redirect: '/404',
        hidden: true
    }
]

由於沒有引入vuex因此須要在VUE構造函數的原型對象上聲明變量來判斷是否已經拉取了用戶的基本信息,由於咱們後端的權限是配置的頁面級權限(即不是按照角色來安排哪一個前端頁面來可訪問,而是根據後臺返回的頁面代碼來判斷哪一個前端頁面可訪問)。

四:總結

由於咱們的項目不可能達到千篇一概的狀況,選擇適合本身項目的解決方案纔是最重要的,不要爲了用某個技術而去用某個技術。

相關文章
相關標籤/搜索