這樣在管理後臺裡實現 403 頁面實在是太優雅了

胡尐睿丶發表於2023-02-27

前言

403 頁面通常表示無許可權訪問,與 404 頁面代表著不同含義。而大部分管理後臺框架僅提供了 404 頁面的支援,但卻忽略了對 403 頁面的處理,有的框架雖然也有對 403 頁面的處理,但處理效果卻不盡人意。

那怎麼樣的 403 頁面才是即好用,又優雅呢?

其他框架是怎麼做的

1、完全不處理

不處理的結果就是無訪問許可權的頁面大機率會進入 404 頁面的邏輯。

因為這類框架通常在路由註冊前就把無訪問許可權的路由直接剔除了,所以當使用者訪問了一個無訪問許可權的路由,對系統來說,它就是一個不存在的路由,從而進入到 404 頁面。

那弊端是什麼呢?那就是使用者沒辦法區分他想訪問的這個頁面,到底是因為許可權不夠,還是地址錯誤,會給使用者造成一定的使用困惑。

2、稍稍處理

稍稍處理的方式和第一種思路不太一樣,這類框架在路由註冊前並不會對路由資料做處理,而是在路由導航守衛裡去判斷是否有許可權訪問路由,如果沒有許可權則進入到預先註冊好的 403 頁面地址。

這種方案的優勢在於它區分了 404 和 403 頁面,因為即便是無訪問許可權的路由,也是真實註冊到了路由例項上,只是在訪問時做了鑑權和重定向。

那弊端又是什麼呢?那就是使用者雖然知道了當前頁面無訪問許可權,但卻看不到頁面的真實地址,因為已經被重定向到 403 頁面上了,使用者體驗稍微欠缺了一點,就像下圖這樣:

111.gif

我是怎麼做的

先稍微思考一下方案,首先剛才第一種方案剔除無訪問許可權的路由肯定不行,無訪問許可權的路由必須得註冊,這樣才能和 404 頁面做出區分;其次第二種方案在導航守衛裡做重定向也不行,不能重定向,要保證路由地址還是原來的地址,但頁面要展示 403 頁面的內容。

於是,方案就出來了,那就是 在路由註冊前,將無訪問許可權的路由的 component 直接替換成 403 頁面元件 不就可以了麼。這麼一來,路由還是那個路由,只是對應的頁面元件不一樣了,既區分了 404 和 403 頁面,還保留 403 頁面的原始路由地址。

用程式碼來描述大致就是:

// 原始路由資料
[
  {
    path: '/permission',
    component: () => import('@/layouts/index.vue'),
    children: [
      {
        path: 'index',
        component: () => import('@/views/list1.vue'),
        meta: {
          auth: 'admin' // 鑑權欄位,如果為 admin 時則可以訪問
        }
      }
    ]
  }
]

// 假設使用者許可權為 test ,處理過後的路由資料
[
  {
    path: '/permission',
    component: () => import('@/layouts/index.vue'),
    children: [
      {
        path: 'index',
        component: () => import('@/views/403.vue'), // 注意看這裡,替換成了 403 頁面元件
        meta: {
          auth: 'admin'
        }
      }
    ]
  }
]

實際效果就是這樣:

Kapture 2023-02-26 at 00.13.57.gif

可以看到,當賬號從 admin 切換到 test 後,由於 test 賬號不具備訪問許可權,所以頁面顯示為 403 頁面,與此同時,頁面的 URL 地址依舊還是原始的地址,達到了預期的效果。

這就夠了麼?

當然沒有,因為 404 頁面是透過以下方式做的兜底處理:

{
  path: '/:all(.*)*',
  component: () => import('@/views/404.vue')
}

由於它並不是一個多級路由的結構,這就導致 404 頁面和 403 頁面的展示有一點差別,404 頁面是整頁顯示,403 頁面是區域性顯示:

222.gif

而我希望是能和 404 頁面保持一致,也就是讓 403 頁面也進行整屏顯示。

處理起來也不復雜,無非是在路由註冊前,將無訪問許可權的多級路由轉成一級路由就可以啦,當然處理過程會使用到遞迴,以及需要將多級路由的 path 進行合併,從程式碼來描述大致就是這樣:

// 原始路由資料
[
  {
    path: '/permission',
    component: () => import('@/layouts/index.vue'),
    children: [
      {
        path: 'index',
        component: () => import('@/views/list1.vue'),
        meta: {
          auth: 'admin' // 鑑權欄位,如果為 admin 時則可以訪問
        }
      }
    ]
  }
]

// 假設使用者許可權為 test ,處理過後的路由資料
[
  {
    path: '/permission/index', // 註冊看這裡,將多級路由的 path 合併成一級
    component: () => import('@/layouts/403.vue'),
    meta: {
      auth: 'admin'
    }
  }
]

最終效果如下:

333.gif

總結

403 頁面是個重要程度並不那麼高的功能,對於一般框架來說,文章一開始提到了兩個方案都可以做到「讓許可權不足的使用者禁止訪問頁面」的需求。

而我的方案則是在滿足使用需求的前提下,儘可能最佳化使用者體驗,雖然沒有提供實際的程式碼,但相信看到這的大家應該都能理解,可以在業務中去自行實踐下。

至於優雅麼?至少目前我覺得在同類產品裡,還是挺優雅的?

其他

我在研究上面第2個方案示例圖裡的那個框架時發現,它切換賬號時不會重新整理頁面,體驗還挺絲滑的。

當然這得益於它所選的方案,因為路由不需要隨著使用者許可權或賬號的變化而變化,所以也就不需要透過重新整理頁面或者重新登入的方式去更新路由。

或許我還能再最佳化最佳化,讓這個方案再優雅一點?如果你有好的建議,也可以在下面留言討論下。

最後

如果你對文章中我的這款 Fantastic-admin 框架感興趣,可以點這裡瞭解一下,這是一款『開箱即用,能為你提供舒適開發體驗』的管理系統框架。

同時文章中我的方案也已經整合進了框架中,想了解實際程式碼是如何實現的,也可以透過閱讀原始碼瞭解。


以下是我往期寫的一些關於管理後臺的文章,感興趣可以繼續閱讀:

相關文章