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

本文將引導你運行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] 的方法跳過權限檢測,無需登錄,無需授權.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章