Util應用框架快速入門(5) - 許可權入門

何鎮汐發表於2023-10-28

本文將引導你執行Util許可權管理模組,並對UI按鈕和API操作進行訪問控制.

Util平臺介紹

Util應用框架是一組類庫,它們提供了有用的功能.

雖然Util配套程式碼生成器能夠幫助你建立專案基架,但直接使用它們的成本依然高昂.

第一個擋在前面的障礙是許可權功能,它是任何業務專案的基石.

為了減輕使用Util應用框架的負擔,我們建立了該專案, 名為 Util Platform, 即 Util平臺.

Util平臺處於起步階段,目前提供了基於資源和角色的許可權模組,可以控制前端選單和按鈕,並能同時控制API的訪問.

後續將持續更新,新增更多基礎功能.

開源協議: MIT

可以在商業專案隨意使用.

歡迎參與貢獻

你如果感興趣,可以參與該專案的開發, 共同建立基礎業務功能,為 .NET 生態添磚加瓦.

  • Util應用框架交流QQ群(24791014)

Util平臺專案介紹

為了滿足單體架構微服務架構的需求, Util平臺分為三套專案.

  • Util.Platform.Single

    Util.Platform.Single 是Util平臺單體架構版本.

  • Util.Platform.Dapr

    Util.Platform.Dapr 是Util平臺微服務架構版本.

  • Util.Platform.Share

    Util.Platform.Share 是Util平臺的共享庫,抽取單體架構版本和微服務架構版本的共享程式碼,併發布到Nuget供兩個版本使用.

Util平臺功能列表

  • 系統功能

    • 登入
    • 退出登入
  • 許可權管理模組

    • 應用程式管理
    • 宣告管理
    • 資源管理
      • 模組資源管理
      • 操作資源管理
      • 身份資源管理
      • Api資源管理
    • 使用者管理
    • 角色管理
      • 將使用者新增到角色
      • 從角色移除使用者
    • 許可權管理
      • 授予角色操作許可權
      • 拒絕角色操作許可權
      • 授予角色API許可權
      • 拒絕角色API許可權

準備

拉取 Util.Platform.Single 專案程式碼.

git clone https://gitee.com/util-core/Util.Platform.Single.git

如果已拉取,請更新到最新程式碼.

執行專案

開啟 Util.Platform.Single.sln 解決方案.

資料遷移

設定 Util.Platform.Api 為啟動專案.

開啟 appsettings.Development.json 開發配置檔案.

DatabaseType 配置項用於指定當前使用的資料庫型別,可選值為:

  • SqlServer
  • PgSql
  • MySql

Util.Platform.Single 目前支援以上三種資料庫,如果需要支援其它資料庫,請告知.

檢查你使用的資料庫連線字串是否正確.

F5 鍵,啟動 Util.Platform.Api 專案.

啟動時,會自動執行 EntityFrameworkCore 遷移命令,建立遷移檔案目錄.

會同時建立三種資料庫專案遷移檔案目錄.

如果沒有配置MySql連線字串,或 MySql 連線失敗, 則無法建立MySql遷移檔案目錄,並會產生一個異常,不用理會它.

檢視資料庫,可以看到資料庫已建立.

使用 Swagger 測試 Web Api 訪問控制

啟動完成, 彈出 Swagger 頁面.

下面選擇一個最簡單的操作進行測試,執行 Application 的 /api/Application/enabled 操作.

返回訊息 code 為 2.

Code 是 Util 應用框架約定的返回結果程式碼, 2 代表未授權 .

Util.Platform.Api 專案預設開啟了API訪問控制,需要先進行登入認證.

Util.Platform.Api 專案的 Swagger 已經配置好 OAuth 認證.

點選 Swagger Authorize 按鈕.

彈出 Available authorizations 對話方塊,點選 Authorize 按鈕.

進入登入頁面,如下所示.

資料遷移預設建立兩個使用者: admin 和 test .

admin使用者是管理員,test是普通使用者.

輸入使用者 test , 密碼 test ,使用普通使用者登入.

登入成功,跳回 Swagger 頁面,點選 Close 按鈕關閉對話方塊.

重新執行 Application 的 /api/Application/enabled 操作.

可以看到,成功返回資料,說明已經授權成功.

那麼是不是隻要登入,就能操作所有API介面?

下面執行 Application 的 POST /api/Application 操作,它表示建立應用程式.

返回結果程式碼為 2,表明未授權,無法訪問 API,因為沒有給 test 使用者設定建立應用程式的許可權.

執行管理後臺UI

進入 Util.Platform.Single\src\Util.Platform.Ui.Identity\ClientApp 目錄.

執行命令,還原 npm 並啟動 Angular 開發伺服器.

.\start.ps1

設定 Util.Platform.Ui.IdentityUtil.Platform.Api 為啟動專案.

F5 鍵啟動專案.

彈出 Api Swagger 和 Angular UI 頁面.

Angular UI 已經開啟了授權路由守衛,未授權則跳轉到登入頁面.

使用 admin 使用者名稱登入,密碼 admin.

登入成功,進入管理後臺UI,如下所示.

檢視許可權管理模組

檢視應用程式

應用程式用於支援多個業務子系統的訪問控制.

點選左側 應用程式 選單項,如下所示.

資料遷移預設建立的應用程式,名為 管理系統.

你可以新增新的應用程式,點選 建立 按鈕,開啟 建立應用程式 對話方塊.

應用程式還用於管理 Identity Server 身份伺服器客戶端資訊.

檢視宣告

宣告是登入認證後可以在使用者會話中訪問的資訊項.

宣告非常簡單,使用表格列表進行編輯.

檢視資源

資源是任何需要訪問控制的東西.

它是許可權管理模組的核心.

點選左側 資源 選單項,如下所示.

檢視模組資源

模組資源 用於按功能模組進行分層設定, 同時也顯示為前端的 選單.

UI 左側選單即是由模組資源配置的.

並不是所有的模組資源都會在選單上顯示,比如資源選單下的內部導航選單,也可以在模組資源中配置,但不會在選單上顯示.

點選 建立 按鈕,彈出 建立模組 對話方塊.

父模組是一個下拉樹元件,如下所示.

我們順便看看 Util UI對下拉樹繫結這類常見需求提供的支援.

首先檢視 html 程式碼.

開啟 Util.Platform.Ui.Identity/Pages/Routes/Identity/Module/Edit.cshtml 檔案,如下所示.

Razor TagHelper 標籤設定url直接發起web api請求.

這並非 Angular 推薦用法, 而是從之前 EasyUI 保留下來的經驗,對於常規專案,這樣能大幅提升開發效率.

對於更復雜的場景,你可以使用 Angular 標準玩法,建立獨立的服務,使用服務載入資料,並繫結到元件上.

<util-tree-select for="ParentId" query-param="queryParam" load-mode="Sync" url="module/tree" default-expand-all="true"
    sort="SortId" label-text="identity.module.parentId" control-span="8">
</util-tree-select>

下面來檢視 Angular 元件 typescript 指令碼程式碼.

開啟 Util.Platform.Ui.Identity/ClientApp/src/app/routes/identity/module/module-edit.component.ts 檔案,如下所示.

可以看到,程式碼非常簡單,沒有載入父模組下拉樹元件的程式碼.

/**
 * 模組編輯頁
 */
@Component({
    selector: 'module-edit',
    templateUrl: environment.production ? './html/edit.component.html' : '/view/routes/identity/module/edit'
})
export class ModuleEditComponent extends TreeEditComponentBase<ModuleViewModel> {
    /**
     * 查詢引數
     */
    queryParam: ResourceQuery;
    /**
     * 應用程式標識
     */
    @Input() applicationId;
    /**
     * 應用程式名稱
     */
    @Input() applicationName;

    /**
     * 初始化模組編輯頁
     * @param injector 注入器
     */
    constructor(injector: Injector) {
        super(injector);
        let param = this.util.dialog.getData<any>();
        if (param) {
            this.applicationId = param.applicationId;
            this.applicationName = param.applicationName;
        }
    }

    /**
     * 初始化
     */
    ngOnInit() {
        super.ngOnInit();
        this.model.applicationId = this.applicationId;
        this.queryParam = this.createQuery();
    }

    /**
     * 建立模型
     */
    createModel() {
        let result = new ModuleViewModel();
        result.enabled = true;
        return result;
    }

    /**
     * 建立查詢引數
     */
    protected createQuery() {
        let result = new ResourceQuery();
        result.applicationId = this.applicationId;
        return result;
    }

    /**
     * 獲取基地址
     */
    protected getBaseUrl() {
        return "module";
    }

    /**
     * 選擇圖示
     */
    selectIcon(icon) {
        this.model.icon = icon;
    }
}

最後,檢視 Web Api 控制器的程式碼.

開啟 Util.Platform.Api/Controllers/Identity/ModuleController.cs 檔案,如下所示.

模組控制器從 NgZorroTreeControllerBase 基類繼承,已經封裝將樹形資料轉換成 Ng Zorro 樹形元件需要的資料格式.

NgZorroTreeControllerBase 基類提供的 QueryAsync 方法用於為樹形表格提供資料,TreeQueryAsync 方法為樹形或下拉樹形提供資料.

檢視操作資源

點選 模組資源 列表 資源設定 按鈕,開啟 操作資源 列表, 如下所示.

操作資源 列表是一個內嵌表格,為模組資源提供細粒度訪問控制,比如控制頁面上的按鈕.

資源還有兩種常見型別, 資源和 行集 資源.

資源用來控制顯示的欄位.

行集 資源用來控制不同角色顯示不同的內容,俗稱資料許可權.

行集資源需要使用規約物件封裝查詢條件,並接入 Util 授權體系.

這兩種資源尚未實現,待基礎功能完善以後提供,如果你的專案對資料許可權控制有需求,可以告知,我們將提前實現它.

點選 操作資源 建立 按鈕,開啟 建立操作許可權 對話方塊.

操作名稱輸入框提示常用操作,可以從中選擇,或手工輸入.

資源最重要的屬性是標識.

對於UI按鈕的控制,可以使用有意義的標識, 比如 application.create, 表示建立應用程式.

資源的定義由開發人員根據控制粒度決定,除了在管理系統新增資源資料,還需要修改相應程式碼.

設定操作許可權

下面以 建立應用程式 操作為例,介紹控制 UI 按鈕和 API 需要的步驟.

  • 新增 建立應用程式 操作資源.

    資料遷移已經建立了該資源,標識為 application.create.

  • UI 按鈕訪問控制

    開啟 Util.Platform.Ui.Identity/Pages/Routes/Identity/Application/Index.cshtml 檔案,如下所示.

只需要把 application.create 操作資源標識設定到 acl 屬性即可.

acl 屬性是 Ng Alain 提供的訪問控制指令 *aclIf, 已經將 acl 屬性全域性新增到 Util UI所有 TagHelper 標籤.

  • Api 訪問控制

    開啟 Util.Platform.Api/Controllers/Identity/ApplicationController.cs 檔案,程式碼簡化如下.

    /// <summary>
    /// 應用程式控制器
    /// </summary>
    [Acl( "application.view" )]
    public class ApplicationController : CrudControllerBase<ApplicationDto, ApplicationQuery> {
      /// <summary>
      /// 初始化應用程式控制器
      /// </summary>
      /// <param name="service">應用程式服務</param>
      public ApplicationController( IApplicationService service ) : base( service ) {
          ApplicationService = service;
      }
    
      /// <summary>
      /// 應用程式服務
      /// </summary>
      protected IApplicationService ApplicationService { get; }
    
      /// <summary>
      /// 建立
      /// </summary>
      /// <param name="request">建立引數</param>
      [HttpPost]
      [Acl( "application.create" )]
      public new async Task<IActionResult> CreateAsync( ApplicationDto request ) {
          return await base.CreateAsync( request );
      }
    }
    

    注意 ApplicationController 控制器上面的 [Acl( "application.view" )] 特性.

    Asp.Net Core 自帶了一個授權特性 [Authorize] ,它預設的行為是隻要登入認證成功,就能進行任何操作.

    Authorize 特性可以設定 Roles 屬性, 設定硬編碼的角色列表,這不太靈活.

    Authorize 特性還能設定 Policy 自定義授權策略, 這是一種靈活的授權方式,但每個需要授權的API都要設定 Policy 很費力.

    Util Acl 特性從 Authorize 繼承,並封裝了特定的授權策略.

    與 Authorize 的 Roles 不同的是, Acl 並不設定角色,因為角色是動態的,可能隨時增加減少,所以設定角色是一種不太靠譜的方法,只適合角色固定的專案.

    Acl 特性設定的是資源標識, 資源標識是固定不變的,理解這一點是將許可權從業務邏輯中剝離出來的關鍵.

    application.view 是檢視應用程式操作資源.

    任何功能頁面都需要檢視許可權,如果沒有細粒度控制需求,對整個頁面和API進行控制即可.

    現在只要某個角色擁有 application.view 操作資源,他就能對控制器中所有方法進行訪問.

    當需要進行更加細粒度的控制時,只需要在某個控制器方法上新增 [Acl] 特性,並設定相應的資源標識即可.

    CreateAsync 方法新增了 [Acl( "application.create" )] 特性,這說明只有擁有 application.create 資源的角色才能進行建立操作.

    統一 UI 按鈕與 API 操作的資源標識是許可權設定的最佳實踐.

    另一種方法是UI按鈕與API操作使用不同的資源標識,再將API資源繫結到UI按鈕,這種方式更復雜且容易出錯.

    如果僅對 Web Api 進行訪問控制, 可以使用API資源, 資源標識為 Api 地址,不需要在每個控制器打上 [Acl] 特性,Util 還提供了Acl過濾器,可以全域性啟用訪問控制.

    擁有細粒度操作資源的角色必須擁有檢視資源.

    對於本例,如果需要訪問 CreateAsync 操作,Asp.Net Core首先驗證 application.view 資源是否能訪問,如果透過才會繼續驗證 application.create 資源.

  • 授予許可權

    一旦建立操作資源,並在 UI 和 API 進行了Acl設定,就可以為角色授權.

    資料遷移預設建立了兩個角色,admin 和 test,並已將使用者 test 關聯到 test 角色,以及將使用者 admin 關聯到 admin角色.

    點選左側 角色 選單,開啟角色列表.

    角色列表中點選 test 角色 許可權設定 連結,如下所示.

    彈出 角色許可權設定對話方塊,如下所示.

    預設 test 角色只能檢視應用程式.

驗證操作許可權

下面來驗證許可權控制是否生效.

驗證 UI 按鈕許可權

滑鼠移到右上方頭像,彈出選單點選 退出登入 連結.

使用 test 使用者登入,密碼 test .

可以看到,只有一個應用程式選單,並且操作按鈕也消失了.

為 test 角色授予建立許可權

退出登入,使用 admin 使用者登入.

開啟 test 角色 許可權設定 視窗,勾選 授予 應用程式建立 核取方塊,點選確定按鈕,如下所示.

還支援拒絕許可權,如果使用者的某個角色擁有拒絕資源,則無法訪問該資源.

退出登入,使用 test 使用者登入.

開啟應用程式頁面,可以看到建立按鈕已經顯示出來.

驗證 Api 許可權

開啟 Swagger ,之前已經測試過建立應用程式 API 介面無法訪問,下面再來試試.

提交下面的資料.

{
  "code": "test",
  "name": "test",
  "enabled": true
}

提交返回操作成功訊息,說明許可權設定生效.

全域性關閉訪問控制

一旦 Web Api 控制器新增了 [Acl] 特性,許可權就已經啟用.

對於某些場景可能相當麻煩,比如 Web Api 整合測試.

許可權是由 Identity Server 提供的,你的整合測試需要從 Identity Server 獲取令牌,這造成了不必要的負擔.

Util應用框架支援全域性關閉訪問控制,如下所示.

.AddAcl( t => t.AllowAnonymous = true )

AddAcl 配置 Util訪問控制相關的服務依賴,AllowAnonymous讓所有新增了 [Acl] 的方法跳過許可權檢測,無需登入,無需授權.

相關文章