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构造函数的原型对象上声明变量来判断是否已经拉取了用户的基本信息,由于咱们后端的权限是配置的页面级权限(即不是按照角色来安排哪一个前端页面来可访问,而是根据后台返回的页面代码来判断哪一个前端页面可访问)。

四:总结

由于咱们的项目不可能达到千篇一概的状况,选择适合本身项目的解决方案才是最重要的,不要为了用某个技术而去用某个技术。

相关文章
相关标签/搜索