ASP.NET Core 中的角色型授權

建立身分識別時,它可能屬於一或多個角色。 例如,Tracy 可能屬於 AdministratorUser 角色,而 Scott 可能只屬於 User 角色。 這些角色的建立和管理方式取決於授權程式的備份存放區。 角色會透過 IsInRole 類別上的 ClaimsPrincipal 方法向開發人員公開。 AddRoles 必須新增至角色服務。

雖然角色是宣告,但並非所有宣告都是角色。 根據身分識別簽發者的不同,角色可能是可以套用群組成員宣告的使用者集合,以及身分識別的實際宣告。 不過,宣告是個別使用者的相關資訊。 使用角色將宣告新增至使用者,可能會混淆使用者與其個別宣告之間的界限。 這也是 SPA 範本並非圍繞角色所設計的原因。 此外,對於從內部部署舊版系統移轉的組織而言,這些年來角色的激增可能表示角色宣告太大,無法包含在 SPA 可使用的權杖內。 若要保護 SPA,請參閱 使用 Identity 來保護 SPA 的 Web API 後端。

將角色服務新增至 Identity

透過使用應用程式的 Identity 組態中的角色類型呼叫 AddRoles,在 Program.cs 中註冊角色型授權服務。 下列範例中的角色類型為 IdentityRole

builder.Services.AddDefaultIdentity<IdentityUser>( ... )
    .AddRoles<IdentityRole>()
    ...

新增角色檢查

角色型授權檢查:

  • 是宣告式的,並指定目前使用者必須是其成員才能存取所要求資源的角色。
  • 會套用至控制器內的 Razor Pages、控制器或動作。
  • 無法在 Razor Page 處理常式層級被套用,而必須套用至 Page。

例如,下列程式碼會將 AdministrationController 上的任何動作存取限制為屬於 Administrator 角色成員的使用者:

[Authorize(Roles = "Administrator")]
public class AdministrationController : Controller
{
    public IActionResult Index() =>
        Content("Administrator");
}

多個角色可以指定為逗號分隔清單:

[Authorize(Roles = "HRManager,Finance")]
public class SalaryController : Controller
{
    public IActionResult Payslip() =>
                    Content("HRManager || Finance");
}

SalaryController 僅可由 HRManager 角色Finance 角色成員的使用者存取。

在套用多個屬性時,存取使用者必須是指定之所有角色的成員。 以下範例要求使用者必須同時PowerUserControlPanelUser 角色的成員:

[Authorize(Roles = "PowerUser")]
[Authorize(Roles = "ControlPanelUser")]
public class ControlPanelController : Controller
{
    public IActionResult Index() =>
        Content("PowerUser && ControlPanelUser");
}

在動作層級套用其他角色授權屬性,即可限制動作的存取:

[Authorize(Roles = "Administrator, PowerUser")]
public class ControlAllPanelController : Controller
{
    public IActionResult SetTime() =>
        Content("Administrator || PowerUser");

    [Authorize(Roles = "Administrator")]
    public IActionResult ShutDown() =>
        Content("Administrator only");
}

在上述 ControlAllPanelController 控制器中:

  • Administrator 角色或 PowerUser 角色的成員可以存取控制器和 SetTime 動作。
  • 只有 Administrator 角色的成員可以存取 ShutDown 動作。

控制器可以被鎖定,但允許匿名、未經驗證的個別動作存取:

[Authorize]
public class Control3PanelController : Controller
{
    public IActionResult SetTime() =>
        Content("[Authorize]");

    [AllowAnonymous]
    public IActionResult Login() =>
        Content("[AllowAnonymous]");
}

針對 Razor Pages,[Authorize] 可以透過下列其中一項進行套用:

[Authorize(Policy = "RequireAdministratorRole")]
public class UpdateModel : PageModel
{
    public IActionResult OnPost() =>
         Content("OnPost RequireAdministratorRole");
}

重要

篩選屬性 (包括 AuthorizeAttribute) 只能套用至 PageModel,而且無法套用至特定的頁面處理常式方法。

原則型角色檢查

您也可以使用原則語法來表示角色需求,其中開發人員會在應用程式啟動時註冊原則,作為授權服務組態的一部分。 這通常發生在 Program.cs 檔案中:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("RequireAdministratorRole",
         policy => policy.RequireRole("Administrator"));
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthentication();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

原則會使用 [Authorize] 屬性上的 Policy 屬性來套用:

[Authorize(Policy = "RequireAdministratorRole")]
public IActionResult Shutdown()
{
    return View();
}

若要在需求中指定多個允許的角色,請將這些角色指定為 RequireRole 方法的參數:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("ElevatedRights", policy =>
          policy.RequireRole("Administrator", "PowerUser", "BackupAdministrator"));
});

var app = builder.Build();

上述程式碼會授權屬於 AdministratorPowerUserBackupAdministrator 角色的使用者。

建立身分識別時,它可能屬於一或多個角色。 例如,Tracy 可能屬於系統管理員和使用者角色,而 Scott 可能只屬於使用者角色。 這些角色的建立和管理方式取決於授權程式的備份存放區。 角色會透過 IsInRole 類別上的 ClaimsPrincipal 方法向開發人員公開。

我們建議不要使用角色作為宣告,而是使用宣告。 使用單頁應用程式時,請參閱 使用 Identity 來保護 SPA 的 Web API 後端。

新增角色檢查

角色型授權檢查:

  • 為宣告式。
  • 會套用至控制器內的 Razor Pages、控制器或動作。
  • 無法在 Razor Page 處理常式層級被套用,而必須套用至 Page。

角色型授權檢查會指定目前使用者必須屬於哪些角色,才能存取要求的資源。

例如,下列程式碼會將 AdministrationController 上的任何動作存取限制為屬於 Administrator 角色成員的使用者:

[Authorize(Roles = "Administrator")]
public class AdministrationController : Controller
{
    public IActionResult Index() =>
        Content("Administrator");
}

多個角色可以指定為逗號分隔清單:

[Authorize(Roles = "HRManager,Finance")]
public class SalaryController : Controller
{
    public IActionResult Payslip() =>
                    Content("HRManager || Finance");
}

只有屬於 HRManager 角色 Finance 角色成員的使用者才能存取控制器 SalaryController

如果您套用多個屬性,則存取使用者必須是所有指定角色的成員。 下列範例要求使用者必須是 PowerUserControlPanelUser 角色的成員:

[Authorize(Roles = "PowerUser")]
[Authorize(Roles = "ControlPanelUser")]
public class ControlPanelController : Controller
{
    public IActionResult Index() =>
        Content("PowerUser && ControlPanelUser");
}

您可以藉由在動作層級套用其他角色授權屬性來進一步限制存取:

[Authorize(Roles = "Administrator, PowerUser")]
public class ControlAllPanelController : Controller
{
    public IActionResult SetTime() =>
        Content("Administrator || PowerUser");

    [Authorize(Roles = "Administrator")]
    public IActionResult ShutDown() =>
        Content("Administrator only");
}

如果在控制器和動作層級套用多個屬性,則所有屬性都必須通過,才能授與存取權:

[Authorize(Roles = "Administrator")]
public class ControlAllPanelController2 : Controller
{
    public IActionResult SetTime() =>
        Content("Administrator only");

    [Authorize(Roles = "PowerUser")]
    public IActionResult ShutDown() =>
        Content("Administrator && PowerUser");
}

在上述 ControlAllPanelController 控制器中:

  • Administrator 角色或 PowerUser 角色的成員可以存取控制器和 SetTime 動作。
  • 只有 Administrator 角色的成員可以存取 ShutDown 動作。

您也可以鎖定控制器,但允許匿名、未經驗證的個別動作存取。

[Authorize]
public class Control3PanelController : Controller
{
    public IActionResult SetTime() =>
        Content("[Authorize]");

    [AllowAnonymous]
    public IActionResult Login() =>
        Content("[AllowAnonymous]");
}

針對 Razor Pages,[Authorize] 可以由下列其中一項進行套用:

[Authorize(Policy = "RequireAdministratorRole")]
public class UpdateModel : PageModel
{
    public ActionResult OnPost()
    {
    }
}

重要

篩選屬性 (包括 AuthorizeAttribute) 只能套用至 PageModel,而且無法套用至特定的頁面處理常式方法。

原則型角色檢查

角色需求也可以使用新的原則語法來表示,其中開發人員會在啟動時註冊原則以作為授權服務設定的一部分。 這通常發生在您 Startup.cs 檔案的 ConfigureServices() 中。

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();

    services.AddAuthorization(options =>
    {
        options.AddPolicy("RequireAdministratorRole",
             policy => policy.RequireRole("Administrator"));
    });
}

原則會使用 [Authorize] 屬性上的 Policy 屬性來進行套用:

[Authorize(Policy = "RequireAdministratorRole")]
public IActionResult Shutdown()
{
    return View();
}

如果您想要在需求中指定多個允許的角色,您可以將這些角色指定為 RequireRole 方法的參數:

options.AddPolicy("ElevatedRights", policy =>
                  policy.RequireRole("Administrator", "PowerUser", "BackupAdministrator"));

此範例會授權屬於 AdministratorPowerUserBackupAdministrator 角色的使用者。

將角色服務新增至 Identity

附加 AddRoles 以新增角色服務:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDefaultIdentity<IdentityUser>()
        .AddRoles<IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>();

    services.AddControllersWithViews();
    services.AddRazorPages();
}