vue權限問題解決方案

前言

最近一直在忙着一個用vue來作的權限管理的項目,其實在此以前,我也研究過vue的權限如何實現,而且也爲之寫過一篇博客,但當真正應用在項目中的時候,仍是發現了許多問題,因此此篇也會就着我在項目中遇到的一些問題,拿出來和你們分享一下,固然示例代碼仍是個人github倉庫中的ant-design-vue-msvue

權限問題解決思路

對於一個先後端分離的項目而言,權限再也不是僅僅靠後端來控制,後端只能控制接口的權限,前臺的頁面顯示仍是須要咱們來控制,針對vue的項目,首先我想的是當權限很少,而且都是單個權限的狀況下,咱們徹底沒有必要使用vue中提供的addRoutes的方法,可使用動態組件來作,即咱們根據後端返回的角色,來細度控制動態組件的顯示內容,所謂動態組件其實就是vue內置提供的component組件webpack

<component :is="currentComponent"/>
複製代碼

相信看到這裏,熟悉的同窗應該已經想起來了,這樣的話,咱們就不須要用到vuex,以及路由配置等等複雜的問題,單純靠後臺返回的角色名稱就能解決全部的問題了,看到這裏是否是以爲今天的內容就這些了,彆着急,下面還有「好看的」。git

權限設置中的問題

這樣雖然能解決一些簡單權限的問題,可是針對稍微複雜一些的權限應用,就顯得有些力不從心了,當角色過多,而且還包含了混合角色的權限的話,則會衍生出不少問題,這裏也是列舉我遇到的一些問題,同窗們能夠細細推敲一下。github

  • 若是是混合角色的話,動態組件的路由跳轉實際都是跳轉到一個頁面,可是混合角色確定會一個頁面中跳到不一樣角色的頁面,這樣可能咱們要多寫不少層的判斷,權限混合越多,就越難以去判斷。
  • 動態組件擴展性比較差,若是咱們再添加一個權限呢,就要再多加一個動態組件的內容,而且出現混合權限的話,那改動的地方就更多了

因此綜上所述,最終我仍是選擇了傳統的addRoutes,那麼確定會有同窗問了,既然這個方案不行,那幹嗎還要用呢。問得好,其實動態組件就是一種嘗試,只有知道錯了,不知足需求了,咱們才能更知道爲何會去使用傳統的addRoutes的權限方案。web

權限問題解決方法

因此咱們來看看addRoutes帶來的一些「好處」:vuex

  • 一次配置,多處使用,咱們配置好了動態路由之後,不論後期添加多少權限,都能很好的顯示路由跳轉等等,而且也不須要改動代碼,只須要添加新增角色的模塊就能夠了。
  • 遇到混合角色的問題,若是內容佈局相似的話,咱們可使用自定義指令來區分要顯示的模塊,這樣的話若是一個帳號同時擁有不少角色的話,那麼包含這個角色的模塊則會相應的顯示出來,就不會出現須要判斷究竟顯示哪一個模塊了,也不須要單獨爲某個角色去設置一個頁面來顯示了。

相信作過權限的同窗對上面的內容仍是有一些心得的,而後咱們按照該有的步驟一步一步來,這些步驟在上面個人github中已經有了,你們能夠對照一下。後端

  1. 全局導航守衛的設置,此處設置全局導航守衛,我以爲更可能是爲了數據持久化,你們都知道,vuex雖然很是好用,可是會有刷新丟失數據的狀況,所以針對這種狀況,咱們使用導航守衛,每次刷新的時候,會從新請求後臺的接口來獲取角色信息。
if (store.getters.roles.length === 0) {
        store
          .dispatch('GetInfo')
          .then(res => {
            const roles = res.data.resultData && res.data.resultData.roles
            store.dispatch('GenerateRoutes', { roles }).then(() => {
              // 根據roles權限生成可訪問的路由表
              // 動態添加可訪問路由表
              router.addRoutes(store.getters.addRouters)
            })
          })
          .catch(() => {
            store.dispatch('Logout').then(() => {
              next({ path: '/user/login', query: { redirect: to.fullPath } })
            })
          })
      } else {
        next()
      }
複製代碼

這裏代碼作了簡化,主要給你們看下上面會有一個角色判斷長度,主要是當咱們不刷新的狀況,頁面角色信息不回丟失,所以咱們也就沒有必要去請求後臺獲取角色信息了,來節省請求數量。 2. 經過上面的代碼能夠看到,咱們首先是請求的角色信息,而後請求了生成路由的GenerateRoutes的方法,方法是寫在vuex中的action裏面的,這部分的內容由於網上有不少教程,其實主要概括一下,就是對路由進行遞歸過濾,過濾出符合角色的路由,而後將靜態路由和過濾出來的動態路由連接起來bash

const permission = {
  state: {
    routers: constRouterMap,
    addRouters: []
  },
  mutations: {
    SET_ROUTERS: (state, routers) => {
      state.addRouters = routers
      state.routers = constRouterMap.concat(routers)
    }
  },
  actions: {
    GenerateRoutes({ commit }, data) {
        //略
    }
  }
}
複製代碼
  1. 設置咱們的路由文件,這部分放到這裏來講,主要由於這裏還有個小坑,因此也是特意拿出來和你們分享一下
export const constRouterMap = [
    {
        path: '/',
        redirect: '/index',
        component: BasicLayout,
        children: [
            {
                path: '/index',
                name: 'index',
                // route level code-splitting
                // this generates a separate chunk (about.[hash].js) for this route
                // which is lazy-loaded when the route is visited.
                component: () => import(/* webpackChunkName: "about" */ '@/views/About.vue'),
                meta: {
                    title: '儀表盤'
                }
            },
            {
                path: '/home',
                name: 'home',
                component: () => import(/* webpackChunkName: "home" */ '@/views/Home.vue'),
                meta: {
                    title: '表單頁'
                }
            },
            {
                path: '/pattern',
                name: 'pattern',
                component: () => import(/* webpackChunkName: "pattern" */ '@/views/DesignPattern.vue')
            },
            {
                path: '/map',
                name: 'map',
                component: () => import(/* webpackChunkName: "map" */ '@/views/DataMap.vue'),
                meta: {
                    title: '地圖組件'
                }
            },
        ]
    },
    {
        path: '/user',
        redirect: '/login',
        component: UserLayout,
        children: [
            {
                path: '/login',
                name: 'login',
                component: () => import(/* webpackChunkName: "login" */ '@/views/user/Login.vue')
            },
            {
                path: '/register',
                name: 'register',
                component: () => import(/* webpackChunkName: "login" */ '@/views/user/Register.vue')
            }
        ]
    },
    //須要注意這裏,404的路由必定要寫在靜態路由中
    {
        path: '/404',
        component: () => import(/* webpackChunkName: "not_found" */ '@/views/NotFound.vue')
    }
]

export const asyncRouterMap = [
    {
        path: '/',
        redirect: '/index',
        component: BasicLayout,
        children: [
            {
                path: '/controls',
                name: 'controls',
                component: () => import(/* webpackChunkName: "controls" */ '@/views/Controls.vue'),
                meta: {
                    title: '權限設置',
                    permission: ['admin']
                }
            }
        ]
    },
    //捕獲未定義的路由配置
    {
        path: '*',
        redirect: '/404',
        hidden: true
    }
]

複製代碼

上面關於404頁面的定義順序很是重要,若是在靜態路由中定義了捕獲的路由path:"*",而在動態路由中定義了404路由的話,則當導航鉤子中判斷比較複雜的話,會出現一些意想不到的錯誤,我就是當時寫反了順序,而且還在導航鉤子中作了一些複雜的麪包屑的判斷,一旦刷新頁面的話,則會出現如下錯誤前後端分離

這種錯誤的產生,多是由於刷新時,導航鉤子發現動態添加進來的路由找不到一直進行獲取動態路由的方法,致使最後調用棧溢出所致使,所以你們在使用的時候必定要很是當心。 4. 當咱們生成路由後,退出應用的切換新的角色帳號進行登陸時,必定要記得的兩件事,第一就是清空vuex裏面的角色信息,在不刷新的狀況下,這些信息是不會丟失的,當不一樣角色的帳號登陸時,原來的角色依然存在,那麼確定會出現問題,其次則是在跳轉會登陸頁的時候,須要設置刷新頁面的代碼

window.location.reload();
this.$router.push({name: 'login'});
複製代碼

先刷新之後再跳轉到登陸頁,這個則是由於addRoutes生成的路由在不刷新的狀況下會一直存在,即便下個不一樣角色的帳號登陸時,依然會拿以前存在的路由信息去進行過濾,這樣過濾的結果必然是當前角色的路由一個都不存在,所以生成的路由信息仍是上個角色的路由,因此在完成了以前這些步驟時,必定不要忘記了作這兩步,這樣也纔是一個完整的權限解決方案async

尾聲

以上也是我在項目中一些收貨吧,拿出來和你們分享,也是但願你們少走一些彎路,留心咱們開發中遇到的每一個看似很小的問題,其實每每是咱們最後解決問題的關鍵,不管是從動態組件仍是動態路由,問題的出現也是咱們不斷去完善本身的過程。

相關文章
相關標籤/搜索