在 ASP.NET Core 中授權 Authorize 屬性簡介和自訂使用方式

在 ASP.NET Core 的授權中,控制器、動作和 Razor Page 可以使用 [Authorize] 屬性(Attribute) 限制只有通過驗證的使用者才能存取,相對的也可以使用 [AllowAnonymous] 屬性開放給所有人存取。 而在角色型授權中更是可以利用 Authorize 屬性進一步指定只有特定的角色 (Roles) 或權限 (Policy) 能夠存取,指定的方式如下:
    
[Authorize(Roles = "Administrator")]
public IActionResult Create()
{
	// 只有具有 Administrator 角色才能存取
    return View();
}

[Authorize(Roles = "Administrator,ProjectManager")]
public IActionResult Create()
{
	// 具有 Administrator 或 ProjectManager 角色才能存取
    return View();
}

[Authorize(Roles = "Administrator")]
[Authorize(Roles = "ProjectManager")]
public IActionResult Create()
{
	// 具有 Administrator 和 ProjectManager 角色才能存取
    return View();
}
    

而權限的話和上面基本上相同,只是將 Authorize 內的 Roles 替換成 Policy
    
[Authorize(Policy = "CreateData")]
public IActionResult Create()
{
	// 只有具有 CreateData 權限才能存取
    return View();
}
    

目前可以發現不論是角色還是權限,都需要以字串的形式傳入。而我們為了方便修改和避免寫錯,通常會使用類別內包含常數 (const) 的方式儲存固定的角色和權限。
    
    public static class Permissions
    {
        public const string CreateData = "CreateData";
        public const string EditData = "EditData";
    }
    

延伸閱讀: C# 列舉(enum)不能儲存字串?!那我們用反射自己做一個

這樣就不用再使用 "CreateData" 這樣的角色和權限字串了
    
[Authorize(Policy = Permissions.CreateData)]
public IActionResult Create()
{
	// 只有具有 CreateData 權限才能存取
    return View();
}
    

不過還記得上面提到的 A 或 B 的權限該如何用 Authorize 表達嗎?需要使用逗號區隔,如果目前使用逗號直接間格會拋出下面的錯誤:
    
[Authorize(Policy = Permissions.CreateData, Permissions.EditData)]

// 錯誤訊息: Attribute arguments must precede property assignment
    

需要切換成下面的其中一種方式或直接寫成字串等才可以正常使用:
    
// 方式一
[Authorize(Policy = Permissions.CreateData + "," + Permissions.EditData)]

// 方式二
[Authorize(Policy = $"{Permissions.CreateData},{Permissions.EditData}")]
    

要解決也很簡單,就是使用自訂屬性。直接繼承 AuthorizeAttribute ,在建構子中使用 params 關鍵字改寫
    
/// <summary>
/// 可以傳入多個權限的自訂權限授權屬性
/// </summary>
public class AuthorizePolicy : AuthorizeAttribute
{
    public AuthorizePolicy(params string[] policy)
    {
        Policy = string.Join(",", policy);
    }
}
    

Roles 當然也可以如法炮製。

這樣我們就可以使用逗號區隔了
    
[AuthorizePolicy(Permissions.CreateData, Permissions.EditData)]
public IActionResult Create()
{
	// 具有 CreateData 或 EditData 權限就可以存取
    return View();
}
    


註:筆者在上方使用靜態類別加上常數儲存是因為權限名稱中可能包含英文句號或是其他特殊符號,若為單純英文加上數字即可使用下面的方式以最簡易的方式定義角色跟權限還可以限制自訂屬性中只能傳入該列舉值:
    
/// <summary>
/// 自訂角色
/// </summary>
public enum Roles
{
    SuperAdmin,
    Basic,
}

/// <summary>
/// 可以傳入多個自訂角色的自訂角色授權屬性
/// </summary>
public class AuthorizeRoles : AuthorizeAttribute
{
    public AuthorizeRoles(params Roles[] roles)
    {
        Roles = string.Join(",", roles);
    }
}
    


參考資料:
Microsoft.Learn - Role-based authorization in ASP.NET Core

留言