Vue-Access-Control:前端用戶許可權控制解決方案

来源:http://www.cnblogs.com/refined-x/archive/2017/12/01/7942276.html
-Advertisement-
Play Games

Vue-Access-Control是一套基於Vue/Vue-Router/axios 實現的前端用戶許可權控制解決方案,通過對路由、視圖、請求三個層面的控制,使開發者可以實現任意顆粒度的用戶許可權控制。 ...


原文地址:http://refined-x.com/2017/11/28/Vue2.0用戶許可權控制解決方案/

 

Vue-Access-Control是一套基於Vue/Vue-Router/axios 實現的前端用戶許可權控制解決方案,通過對路由、視圖、請求三個層面的控制,使開發者可以實現任意顆粒度的用戶許可權控制。

整體思路

會話開始之初,先初始化一個只有登錄路由的Vue實例,在根組件created鉤子里將路由定向到登錄頁,用戶登錄成功後前端拿到用戶token,設置axios實例統一為請求headers添加{"Authorization":token}實現用戶鑒權,然後獲取當前用戶的許可權數據,主要包括路由許可權和資源許可權,之後動態添加路由,生成菜單,實現許可權指令和全局許可權驗證方法,併為axios實例添加請求攔截器,至此完成許可權控制初始化。動態載入路由後,路由組件將隨之載入並渲染,而後展現前端界面。

為解決瀏覽器刷新路由重置的問題,拿到token後要將其保存到sessionStorage,根組件的created鉤子負責檢查本地是否已有token,如果有則無需登錄直接用該token獲取許可權並初始化,如果token有效且當前路由有權訪問,將載入路由組件並正確展現;若當前路由無權訪問將按路由設置跳轉404;如果token失效,後端應返回4xx狀態碼,前端統一為axios實例添加錯誤攔截器,遇到4xx狀態碼執行退出操作,清除sessionStorage數據並跳轉到登錄頁,讓用戶重新登錄。

最小依賴原則

Vue-Access-Control的定位是單一領域解決方案,除了Vue/Vue-Router/axios之外沒有其他依賴,理論上可以無障礙的應用到任何有許可權控制需求的Vue項目中,項目基於webpack 模板開發構建,大多數新項目可以直接基於檢出代碼繼續開發。需要說明的是,項目額外引入的Element-UICryptoJS僅用於開發演示界面,他們不是必須且與許可權控制毫無關係,項目應用中可以自行取捨。

目錄結構

src/
  |-- api/                  //介面文件
  |     |-- index.js             //輸出通用axios實例
  |     |-- account.js           //按業務模塊組織的介面文件,所有介面都引用./index提供的axios實例
  |-- assets/
  |-- components/
  |-- router/
  |     |-- fullpath.js         //完整路由數據,用於匹配用戶的路由許可權得到實際路由
  |     `-- index.js            //輸出基礎路由實例
  |-- views/
  |-- App.vue
  ·-- main.js

 

數據格式約定

  • 路由許可權數據必須是如下格式的對象數組,idparent_id相同的兩個路由具有上下級關係,如果希望使用自定義格式的路由數據,需要修改路由控制的相關實現,詳見路由控制數據格式約定

  • [
        {
          "id": "1",
          "name": "菜單1",
          "parent_id": null,
          "route": "route1"
        },
        {
          "id": "2",
          "name": "菜單1-1",
          "parent_id": "1",
          "route": "route2"
        }
      ]  
  • 資源許可權數據必須是如下格式的對象數組,每個對象代表一個RESTful請求,支持帶參數的url,具體格式說明見請求控制

     [
        {
          "id": "2c9180895e172348015e1740805d000d",
          "name": "賬號-獲取",
          "url": "/accounts",
          "method": "GET"
        },
        {
          "id": "2c9180895e172348015e1740c30f000e",
          "name": "賬號-刪除",
          "url": "/account/**",
          "method": "DELETE"
        }
    ]
    

     

路由控制

路由控制包括動態註冊路由和動態生成菜單兩部分。

動態註冊路由

最初實例化的路由僅包括登錄和404兩個路徑,我們期待完整的路由是這樣的:

[{
  path: '/login',
  name: 'login',
  component: (resolve) => require(['../views/login.vue'], resolve)
}, {
  path: '/404',
  name: '404',
  component: (resolve) => require(['../views/common/404.vue'], resolve)
}, {
  path: '/',
  name: '首頁',
  component: (resolve) => require(['../views/index.vue'], resolve),
  children: [{
    path: '/route1',
    name: '欄目1',
    meta: {
      icon: 'icon-channel1'
    },
    component: (resolve) => require(['../views/view1.vue'], resolve)
  }, {
    path: '/route2',
    name: '欄目2',
    meta: {
      icon: 'ico-channel2'
    },
    component: (resolve) => require(['../views/view2.vue'], resolve),
    children: [{
      path: 'child2-1',
      name: '子欄目2-1',
      meta: {
        
      },
      component: (resolve) => require(['../views/route2-1.vue'], resolve)
    }]
  }]
}, {
  path: '*',
  redirect: '/404'
}]

  


那麼接下來就需要獲取首頁以及其子路由們,思路是事先在本地存一份整個項目的完整路由數據,然後根據用戶許可權對完整路由進行篩選。

篩選的實現思路是先將後端返回的路由數據處理成如下哈希結構:

let hashMenus = {
   "/route1":true,
   "/route1/route1-1":true,
   "/route1/route1-2":true,
   "/route2":true,
   ...
}

  

然後遍歷本地完整路由,在迴圈中將路徑拼接成上述結構中的key格式,通過hashMenus[route]就可以判斷路由是否匹配,具體實現見App.vue文件中的getRoutes()方法。

如果後端返回的路由許可權數據與約定不同,就需要自行實現篩選邏輯,只要能得到實際可用的路由數據就可以,最終使用addRoutes()方法將他們動態添加到路由實例中,註意404頁面的模糊匹配一定要放在最後。

動態菜單

路由數據可以直接用來生成導航菜單,但路由數據是在根組件中得到的,導航菜單存在於index.vue組件中,顯然我們需要通過某種方式共用菜單數據,方法有很多,一般來說首先想到的是Vuex,但菜單數據在整個用戶會話過程中不會發生改變,這並不是Vuex的最佳使用場景,而且為了儘量減少不必要的依賴,這裡用了最簡單直接的方法,把菜單數據掛在根組件data.menuData上,在首頁里用this.$parent.menuData獲取。

另外,導航菜單很可能會有添加欄目圖標的需求,這可以通過在路由中添加meta數據實現,例如將圖標class或unicode存到路由meta里,模板中就可以訪問到meta數據,用來生成圖標標簽。

在多角色系統中可能遇到的一個問題是,不同角色有一個名字相同但功能不同的路由,比如說系統管理員企業管理員都有”賬號管理”這個路由,但他們的操作許可權和目標不同,實際上是兩個完全不同的界面,而Vue不允許多個路由同名,因此路由的name必須做區分,但把區分後的name顯示在前端菜單上會很不美觀,為了讓不同角色可以享有同一個菜單名稱,我們只要將這兩個路由的meta.name都設置成”賬號管理”,在模板迴圈時優先使用meta.name就可以了。

菜單的具體實現可以參考views/index.vue

視圖控制

視圖控制的目標是根據當前用戶許可權決定界面元素顯示與否,典型場景是對各種操作按鈕的顯示控制。實現視圖控制的本質是實現一個許可權驗證方法,輸入請求許可權,輸出是否獲准。然後配合v-ifjsx或自定義指令就能靈活實現各種視圖控制。

全局驗證方法

驗證方法的的實現本身很簡單,無非是根據後端給出的資源許可權做判斷,重點在於優化方法的輸入輸出,提升易用性,經過實踐總結最終使用的方案是,將許可權跟請求同時維護,驗證方法接收請求對象數組為參數,返回是否具有許可權的布爾值。

請求對象格式:

//獲取賬戶列表
const request = {
  p: ['get,/accounts'],
  r: params => {
    return instance.get(`/accounts`, {params})
  }
}

許可權驗證方法$_has()的調用格式:

v-if="$_has([request])"

  

許可權驗證方法的具體實現見App.vueVue.prototype.$_has方法。

將許可權驗證方法全局混入,就可以在項目中很容易的配合v-if實現元素顯示控制,這種方式的優點在於靈活,除了可以校驗許可權外,還可以在判斷表達式中加入運行時狀態做更多樣性的判斷,而且可以充分利用v-if響應數據變化的特點,實現動態視圖控制。

具體實現細節參考基於Vue實現後臺系統許可權控制中的相關章節。

自定義指令

v-if的響應特性是把雙刃劍,因為判斷表達式在運行過程中會頻繁觸發,但實際上在一個用戶會話周期內其許可權並不會發生變化,因此如果只需要校驗許可權的話,用v-if會產生大量不必要的運算,這種情況只需在視圖載入時校驗一次即可,可以通過自定義指令實現:

//許可權指令
Vue.directive('has', {
  bind: function(el, binding) {
    if (!Vue.prototype.$_has(binding.value)) {
      el.parentNode.removeChild(el);
    }
  }
});

  

自定義指令內部仍然是調用全局驗證方法,但優點在於只會在元素初始化時執行一次,多數情況下都應該使用自定義指令實現視圖控制。

請求控制

請求控制是利用axios攔截器實現的,目的是將越權請求在前端攔截掉,原理是在請求攔截器中判斷本次請求是否符合用戶許可權,以決定是否攔截。

普通請求的判斷很容易,遍歷後端返回的的資源許可權格式,直接判斷request.methodrequest.url是否吻合就可以了,對於帶參數的url需要使用通配符,這裡需要根據項目需求前後端協商一致,約定好通配符格式後,攔截器中要先將帶參數的url處理成約定格式,再判斷許可權,方案中已經實現了以下兩種通配符格式:

1. 格式:/resources/:id
   示例:/resources/1
   url: /resources/**
   解釋:一個名詞後跟一個參數,參數通常表示名詞的id
   
2. 格式:/store/:id/member
   示例:/store/1/member
   url:/store/*/member
   解釋:兩個名詞之間夾帶一個參數,參數通常表示第一個名詞的id

  

對於第一種格式需要註意的是,如果你要發起一個url為"/aaa/bbb"的請求,預設會被處理成"/aaa/**"進行許可權校驗,如果這裡的”bbb”並不是參數而是url的一部分,那麼你需要將url改成"/aaa/bbb/",在最後加一個”/“表示該url不需要轉化格式。

攔截器的具體實現見App.vue中的setInterceptor()方法。

如果你的項目還需要其他的通配符格式,只需要在攔截器中實現對應的檢測和轉化方法就可以了。

演示及說明

演示說明:

DEMO項目中演示了動態菜單、動態路由、按鈕許可權、請求攔截。

演示項目後端由rap2生成mock數據,登錄請求通常應該是POST方式,但因為rap2的編程模式無法獲取到非GET的請求參數,因此只能用GET方式登錄,實際項目中不建議仿效;

另外登錄後獲取許可權的介面本來不需要攜帶額外參數,後端可以根據請求頭攜帶的token信息實現用戶鑒權,但因為rap2的編程模式獲取不到headers數據,因此只能增加一個”Authorization”參數用於生成模擬數據。

測試賬號:

1. username: root
   password: 任意
2. username: client
   password: 任意

  

演示地址:

vue-access-control.refined-x.com

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • CodePen 需要使用色 ec6337(當然可以是任意顏色),解決問題:記住密碼定製 CheckBox,解釋全在註釋里 主要使用到 ::before 或 ::after 偽類處理,偽裝成內部的那個勾 html CSS(LESS) CodePen ...
  • 很多人對正則表達式的印象都是用來做表單驗證的,這其實是不大準確的。正則表達式目前在很多軟體中都得到了廣泛的應用,包括Linux,Unix等操作系統,VBScript,Java,PHP等開發環境中,以及很多應用軟體都能應用到正則表達式。 ...
  • cu主題是由瘋狂的大叔設計,界面簡潔大方是它最大的特點之一。 手殘君也比較喜愛這款主題,在使用的過程中,根據手殘君的個人習慣,對其進行了優化。 標題居中顯示 增加標題div背景色 標題div平滑優化 相關代碼: tags頁面增加標簽彙總(隨著標簽越來越多,原有的tags頁面滿足不了數據索引的需求) ...
  • 公司突然組織需要重新搭建一個基於 的論壇系統,前端採用 ,上網找了一些腳手架,或多或少不能滿足自己的需求,最終在基於 的`react`腳手架 "generator react webpack" 上搭建改造,這裡作為記錄。 代碼在這裡: "github" 另外推薦地址: "react starter ...
  • 圖片隱寫術就是利用圖片來隱藏某些數據,讓人一眼看去以為是很普通很正常的圖片,但其實裡面隱藏著某些“機密”數據。我們可以用它來保護某些機密圖片或者隱藏特殊的文字信息。 ...
  • Angular2官網通過http請求模擬API 來請求hero 數據,感覺有點繁瑣,很讓人理解不了,我們不採用它的辦法,直接展示怎麼使用http請求來獲取我們的數據 ,直截了當。 第一、準備工作,創建一個WebApi 創建一個webapi(這裡我使用MVC4 WebApi ,你可以選擇其他途徑提供j ...
  • 具體步驟請參考:http://blog.csdn.net/a727911438/article/details/70834467 打包時出現了不少問題,逐一記錄下來以供其他人參考。 package.json文件內容 main.js文件內容 安裝好打包神器後,在執行 electron-packager ...
  • 當已知要載入圖片時方能使用,提升網頁的流暢性。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...