Spring Cloud實戰 | 第十一篇:Spring Cloud Gateway 網關實現對RESTful介面許可權控制和按鈕許可權控制

一. 前言

hi,大家好,這應該是農曆年前的關於開源項目有來商城 的最後一篇文章了。

有來商城 是基於 Spring Cloud OAuth2 + Spring Cloud Gateway + JWT實現的統一認證鑒權,Spring Cloud & Alibaba + vue-element-admin實現的微服務前後端分離的全棧開源項目。

有來商城 的許可權設計主要是為了實現以下幾點目標:

  • 實現RBAC模式的許可權管理設計

  • 實現基於 vue-element-admin 後台菜單許可權管理系統

  • Spring Cloud Gateway 網關針對RESTful介面許可權控制

  • Vue 自定義指令實現按鈕級別許可權控制

二. 項目介紹

1. 項目簡介

有來商城 是基於Spring Boot 2.4、Spring Cloud 2020 & Alibaba、Vue、element-ui、uni-app快速構建的一套全棧開源商城平台,包括微服務應用、管理平台、微信小程式及APP應用。

2. 項目地址

項目預覽地址: //www.youlai.store

微信小程式體驗碼

源碼地址:

項目名稱 Github 碼雲
微服務後台 youlai-mall youlai-mall
管理前端 youlai-mall-admin youlai-mall-admin
微信小程式 youlai-mall-weapp youlai-mall-weapp
APP應用 youlai-mall-app youlai-mall-app

3. 項目往期文章

後台微服務

  1. Spring Cloud實戰 | 第一篇:Windows搭建Nacos服務
  2. Spring Cloud實戰 | 第二篇:Spring Cloud整合Nacos實現註冊中心
  3. Spring Cloud實戰 | 第三篇:Spring Cloud整合Nacos實現配置中心
  4. Spring Cloud實戰 | 第四篇:Spring Cloud整合Gateway實現API網關
  5. Spring Cloud實戰 | 第五篇:Spring Cloud整合OpenFeign實現微服務之間的調用
  6. Spring Cloud實戰 | 第六篇:Spring Cloud Gateway+Spring Security OAuth2+JWT實現微服務統一認證授權
  7. Spring Cloud實戰 | 最七篇:Spring Cloud Gateway+Spring Security OAuth2集成統一認證授權平台下實現註銷使JWT失效方案
  8. Spring Cloud實戰 | 最八篇:Spring Cloud +Spring Security OAuth2+ Vue前後端分離模式下無感知刷新實現JWT續期
  9. Spring Cloud實戰 | 最九篇:Spring Security OAuth2認證伺服器統一認證自定義異常處理
  10. Spring Cloud實戰 | 第十篇 :Spring Cloud + Nacos整合Seata 1.4.1最新版本實現微服務架構中的分散式事務,進階之路必須要邁過的檻

後台管理前端

  1. vue-element-admin實戰 | 第一篇: 移除mock接入微服務介面,搭建SpringCloud+Vue前後端分離管理平台
  2. vue-element-admin實戰 | 第二篇: 最小改動接入後台實現根據許可權動態載入菜單

微信小程式

  1. vue+uni-app商城實戰 | 第一篇:從0到1快速開發一個商城微信小程式,無縫接入Spring Cloud OAuth2認證授權登錄

應用部署

  1. Docker實戰 | 第一篇:Linux 安裝 Docker
  2. Docker實戰 | 第二篇:Docker部署nacos-server:1.4.0
  3. Docker實戰 | 第三篇:IDEA集成Docker插件實現一鍵自動打包部署微服務項目,一勞永逸的技術手段值得一試
  4. Docker實戰 | 第四篇:Docker安裝Nginx,實現基於vue-element-admin框架構建的項目線上部署
  5. Docker實戰 | 第五篇:Docker啟用TLS加密解決暴露2375埠引發的安全漏洞,被黑掉三台雲主機的教訓總結

三. 資料庫設計

RBAC(Role-Based Access Control)基於角色訪問控制,目前使用最為廣泛的許可權模型。

此模型有三個角色用戶角色許可權,在傳統的許可權模型用戶直接關聯加了角色層,解耦了用戶和許可權,使得許可權系統有了更清晰的職責劃分和更高的靈活度。

以下是有來系統關於RBAC許可權模型的資料庫

重點說許可權,系統許可權分3類,如下表:

許可權名稱 表名 欄位 許可權標識
菜單許可權 sys_menu
介面許可權 sys_permission type=1 PUT_/users/**
按鈕許可權 sys_permission type=2 system:user:add

其實了解過目前主流開源系統的許可權設計,大概率的把菜單和按鈕放一塊然後根據類別欄位區分,以下就關於這種方式優劣發表下個人意見,僅供大家參考下不必較真:

優勢:

  1. 理論上合理,按鈕肯定屬於某個菜單之下
  2. 省去了許可權表(sys_permission)和關聯中間表這兩張表

劣勢:

  1. 菜單模組變的複雜了,菜單表多了和菜單無關聯的類型欄位和許可權標識欄位
  2. 菜單和按鈕查詢要區分類型,給程式碼開發帶來複雜和影響查詢性能
  3. 不能同時滿足按鈕許可權控制和網關根據請求路徑Ant匹配鑒權(具體下文說)

四. 許可權系統管理介面

先看下vue-element-admin下的RBAC模型下的後台許可權管理介面,體驗地址://www.youlai.store

  • 菜單許可權管理

  • 角色分配許可權

五. RESTful介面許可權控制

1. 介面和按鈕的許可權標識的區別

上文說到的關於許可權表的拆分,菜單單獨一張表,按鈕許可權和介面許可權合為一張表根據類型type欄位區分,之所以這樣因為介面和按鈕許可權有些共性,都有一個許可權標識欄位。

至於按鈕和介面為什麼要區分呢?都使用system:user:add許可權標識不可以嗎?

具體做法是介面方法加上Spring Security的註解@PreAuthorize(“hasPermission(‘system:user:add’)”),在執行方法前判斷用戶時候擁有該許可權。

答案是一般場景這樣設計絕對沒問題。但這裡使用網關作為統一鑒權的入口,肯定希望網關一次性把鑒權的活做的乾脆利落,這樣就不需要在各個微服務單獨的把Spring Security許可權模組引入鑒權,通過網關鑒權能把職責分工明確,減少開發工作量,無許可權的請求直接被網關攔截返回,不會走到微服務那裡再被告知無權訪問,提高請求效率。

Spring Cloud Gateway網關使用請求路徑Ant匹配請求標識進行許可權判斷的,例如/users/1經過Ant匹配到許可權標識/users/**,而/users/**是被用戶所持有的許可權標識,這就標識用戶允許訪問/users/1的請求,所以和按鈕的許可權標識system:user:add是有區別的。

這樣就完事了嗎?當然還沒,因為 有來系統 較於其他系統它是比較嚴格遵守REST介面設計規範,所以如果僅僅是上面根據請求路徑URL判斷許可權肯定是不合理的,/users/1這個請求路徑在RESTful介面下可能是GET類型的請求也有可能是PUT類型的請求,那該如何處理?

所以在sys_permission表裡還有一個method欄位來標識請求方法類型,值可能會是、GET、POST、PUT、PATCH、DELETE等HTTP請求方法類型,其中是不限請求方法類型的意思,然後將請求方法類型和請求路徑組合得到介面的許可權標識是這樣的PUT_users/1

接下來就通過對 有來系統 的實戰操作來演示網關如何細粒度對RESTful介面的許可權控制。

2. 添加許可權

新增用戶管理的增刪改查許可權

3. 角色授權

賦予系統管理員(admin)用戶查詢許可權,無其他許可權

4. 載入角色許可權規則數據至快取

項目啟動查看Redis中的角色許可權規則:

看到系統管理員這個角色是沒有用戶修改許可權的。你可以給角色添加用戶修改許可權後嘗試是否可以修改成功。

5. 介面許可權控制演示

admin系統管理員登錄執行一個用戶修改的提交的請求,看一下網關鑒權的流程:

結果可想而知,系統管理員不具有修改用戶PUT_/youlai-admin/v1/users/2許可權,從快取查詢只有超級管理員具有該介面請求方法訪問許可權。頁面結果顯示如下:

六. 按鈕許可權控制

1. 什麼是Vue自定義指令?

Vue除了核心功能默認內置的指令 (v-model 和 v-show),Vue 也允許註冊自定義指令。

這裡主要使用Vue.directive註冊一個全局自定義指令v-has- permission用於許可權判斷,然後在模板中的任何元素使用v-has- permission屬性。

自定義指令學習傳送門

2. 添加按鈕許可權

3. 角色授權

4. 載入角色按鈕許可權數據

完整程式碼:youlai-mall-admin

登錄成功時獲取用戶資訊,其中包含該用戶擁有的許可權字元串集合如下:

這裡將用戶許可權擁有的字元串集合快取到vuex的perms屬性中:

5. 自定義和註冊全局指令

有來管理前端 是基於vue-element-admin後台前端解決方案,在vue-element-admin項目我們可以看到自定義指令的應用。如下:

然後複製一份permission.js重命名為hasPermission.js,修改後如下:

import store from '@/store'

// 校驗用戶是否擁有按鈕許可權

function hasPermission(el, binding) {
  const {value} = binding
  const perms = store.getters && store.getters.perms
  if (value && value instanceof Array) {
    if (value.length > 0) {
      const requiredPerms = value
      const hasPermission = perms.some(perm => {
        return requiredPerms.includes(perm)
      })
      if (!hasPermission) {
        el.parentNode && el.parentNode.removeChild(el)
      }
    }
  } else {
    throw new Error(`need perms! Like v-has-permission="['system:user:add','system:user:edit']"`)
  }
}

export default {
  inserted(el, binding) {
    hasPermission(el,binding)
  },
  update(el, binding) {
    hasPermission(el,binding)
  }
}

註冊hasPermission至全局指令:

指令在組件上的應用:

6. 按鈕許可權控制演示

系統管理員是沒有修改按鈕的許可權的,結果如下頁面不顯示修改按鈕。

那給系統管理員添加修改按鈕的許可權,再看看用戶頁面的顯示情況

此時用戶頁面的修改按鈕已經顯示出來了,至此完成了系統的按鈕許可權控制。

七. 結語

本篇通過實戰的方式講述如何基於Spring Cloud Gateway + vue-element-admin技術設計一套符合RBAC規範的許可權管理系統,通過網關就可以輕易實現RESTful介面方法細粒度的控制,無需將Spring Security模組引入各個微服務;以及使用Vue的自定義指令在組件中使用實現細粒度的按鈕許可權控制。

如果你對此系統許可權設計有更好的建議,歡迎留言給我,在此感謝!如果對項目感興趣的話,歡迎加我微信和項目交流群。

最後預祝大家新年愉快,有個完美充實的小假期。