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

2023-02-27 09:00:23

前言

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

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

其他框架是怎麼做的

1、完全不處理

不處理的結果就是無存取許可權的頁面大概率會進入 404 頁面的邏輯。

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

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

2、稍稍處理

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

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

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

我是怎麼做的

先稍微思考一下方案,首先剛才第一種方案剔除無存取許可權的路由肯定不行,無存取許可權的路由必須得註冊,這樣才能和 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'
        }
      }
    ]
  }
]

實際效果就是這樣:

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

這就夠了麼?

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

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

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

而我希望是能和 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'
    }
  }
]

最終效果如下:

總結

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

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

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