快轉到主要內容

如何在 ASP.NET Core 網站中使用聲明 Claim 做權限管理 Authorization

· 5062 字 · 8 分鐘
黃紅橙
作者
黃紅橙
現為軟體工程師,偶爾做遊戲影片
目錄

如何在 ASP.NET Core 網站中使用聲明 Claim 做權限管理 Authorization
#

最近在用 ASP.NET Core 開發自己的點餐網站時,需要加入會員登入系統,同時限制使用者對 API 的存取權限。如果使用者未經授權,則回傳 401 Unauthorized;若權限不足,則回傳 403 Forbidden,以防止未授權的用戶惡意存取或更改後端資料庫。這時候就需要用到 Claim (中文翻作聲明) 來做 Authorization (授權)。

認證與授權的概念
#

  1. Authenticate(認證)
    用來驗證使用者身份的方式,通常有 Cookie Authentication、JWT Bearer Authentication、OAuth 2.0(單一登入 SSO)。因這部分非本文重點,暫不討論。

  2. Authorization(授權)
    在使用者驗證完成後,根據資料庫中的使用者資訊,賦予不同的操作權限。


實現權限管理
#

以下我用一個簡單的範例教大家如何設定 Claim,賦予使用者權限~

var userName = "Hendrix";
var permission = "reader";
var claims = new[] {
    new Claim(ClaimTypes.Name, userName),
    new Claim(ClaimTypes.Role, permission)
};
var identity = new ClaimsIdentity(claims, permission);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);

各種 Claim 的介紹
#

看完以後會發現很像俄羅斯娃娃,一層包一層😆,以下我一個個講解:

  • Claim
    這是指使用者的各式資訊,包含姓名、生日、性別、權限角色,是使用者的基本資訊單位。在此例中,建立了兩個 ClaimNameRole,並指定角色為 reader

  • ClaimsIdentity
    將多個 Claim 資訊打包,就像一張身份證,上面會有使用者不同的資訊。

  • ClaimsPrincipal
    代表一組證件的集合,如同一個人可能擁有市民卡、健保卡等多種證件。就像對政府來說,你所擁有的所有證件就會充份代表你這個人,Principal就是這樣的概念。

  • AuthenticationTicket
    但是有了這麼多證件,要驗證你到底是誰、你的證件是否正確,方式有很多種。有的可能是看你身份證照片跟你本人像不像,有的會拿紫外光照一下身份證看是不是證本,AuthenticationTicket就是一個明確包含指定驗證過程(如 Cookie 或 JWT 驗證)的文件/票卷,內含:

    • AuthenticationScheme:驗證方式。
    • Principal:驗證的使用者身份。
    • Properties:驗證票證的其他屬性(如票證到期時間)。
  • AuthenticateResult
    本身包含以下內容:

    • 有效的通關文件(AuthenticationTicket)。
    • 身分(ClaimPrincipal)。
    • 驗證資訊(AuthenticationProperties)。
    • 驗證結果(AuthenticateResult)。

    我這邊直接使用 AuthenticateResult.Success,是因為我自定義了我的驗證方式,並且確認輸入的 userNamepermission 都有其值且有效。

    如果有使用情境是傳來的 Token 無效,可以考慮使用以下方式:

    • Fail:表示驗證失敗。
    • NoResult:表示無法判斷驗證結果。

注意:如果使用的是 .NET 預設的 Cookie 認證,不需要手動返回 AuthenticateResult.Success,因為框架會自動處理認證的檢查和結果返回。


使用 Claim 跟傳統認證方式的差別
#

傳統的認證方式通常由每個應用程式自行設計,使用各自的使用者資料庫,但這種方式有局限性,難以滿足需多種認證的需求。

基於 Claim 的認證,就能把認證與授權分離為獨立服務,授權服務只需驗證 Claims 即可,就無需在意具體的認證方式。


Controller 控制器方法的 Role 角色授權
#

以下範例使用 Roles 授權,只需在方法上加上 [Authorize(Roles = "你允許使用的角色")] 即可。

這樣 .NET 會直接從使用者的 ClaimsPrincipal 中的角色(ClaimTypes.Role)進行檢查,確保只有符合角色條件的使用者能夠執行該方法。

  1. 只有 editer 可以新增文章

    [HttpPost]
    [Authorize(Roles = "editer")]
    public async Task<ActionResult<ArticleDto>> Add([FromBody] ArticleDto dto) {
        var createdArticle = await _articleService.AddAsync(dto);
        return CreatedAtAction(nameof(GetById), new { id = createdArticle.ArticleId }, createdArticle);
    }
    
  2. readerediter 都可以查詢文章

    [HttpGet("{id}")]
    [Authorize(Roles = "reader, editer")]
    public async Task<ActionResult<ArticleDto>> GetById(int id) {
        var article = await _articleService.GetByIdAsync(id);
        return Ok(article);
    }
    

結語
#

我下一篇再繼續打 Policy 授權 以及 自定義 AuthenticationScheme 的部份,第一次打教學文,看別人教學文感覺很簡單,但自己打真的一片空白,而且自己查完資料才發現原來我使用的Authorization 方法和別人不太一樣。

原本我是用自定義一個自己的 AuthenticationScheme,一直試錯後誤打誤撞到授權成功,發現別人都是用預設的 Cookie Authentication後,對自己用的土炮方法傻眼… 算是邊打教學文邊教學自己🤣