ASP.NET Core でのロール ベースの認可

ID が作成されると、1 つまたは複数のロールに属することができます。 たとえば、Tracy は Administrator ロールと User ロールに属していて、Scott は User ロールのみに属している場合があります。 これらのロールを作成および管理する方法は、認可プロセスのバッキング ストアによって異なります。 ロールは、ClaimsPrincipal クラスの IsInRole メソッドを介して開発者に提示されます。 AddRoles は、ロール サービスに追加する必要があります。

ロールは要求ですが、すべての要求がロールであるとは限りません。 ID 発行者に応じて、ロールは、グループ メンバーに対する要求を適用できるユーザーのコレクションである場合もあれば、ID に対する実際の要求である場合もあります。 ただし、要求は、個々のユーザーに関する情報として使用されます。 ロールを使用してユーザーに要求を追加すると、ユーザーと個々の要求の境界が混同されるおそれがあります。 このような混乱が、SPA テンプレートがロールを中心に設計されていない理由です。 さらに、オンプレミスのレガシ システムから移行する組織では、ロールが何年にもわたって急増しているということは、ロール要求が大きすぎて、SPA で使用できるトークン内に含めることができない場合があることを意味します。 SPA をセキュリティで保護する方法については、ASP.NET Core でのシングル ページ アプリの認証の概要に関するページを参照してください。

Identity にロール サービスを追加する

アプリの Identity 構成のロールの種類を使用して AddRoles を呼び出して、ロールベースの承認サービスを Program.cs に登録します。 次の例のロールの種類は、IdentityRole です。

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

ロール チェックの追加

ロールベースの承認チェックとは:

  • 宣言型で、現在のユーザーが要求されたリソースにアクセスするためにメンバーである必要があるロールを指定します。
  • コントローラー内の Razor Pages、コントローラー、またはアクションに適用されます。
  • 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 ロール SalaryControllerFinance ロールのメンバーからアクセスできるのは SalaryController だけです。

複数の属性が適用されている場合、アクセスするユーザーは、指定された "すべて" のロールのメンバーである必要があります。 次の例では、ユーザーが "と" ロールの "両方" のメンバーである必要があります。

[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();

上記のコードは、AdministratorPowerUser または BackupAdministrator ロールに属しているユーザーを承認します。

ID が作成されると、1 つまたは複数のロールに属することができます。 たとえば、Tracy は管理者ロールとユーザー ロールに属していて、一方、Scott はユーザー ロールのみに属している場合があります。 これらのロールを作成および管理する方法は、認可プロセスのバッキング ストアによって異なります。 ロールは、ClaimsPrincipal クラスの IsInRole メソッドを介して開発者に提示されます。

ロールを要求として使用するのではなく、要求を使用することをお勧めします。 シングルページ アプリケーション (SPA) を使用する場合は、ASP.NET Core でのシングル ページ アプリの認証の概要に関するページを参照してください。

ロール チェックの追加

ロールベースの承認チェックとは:

  • 宣言型です。
  • コントローラー内の Razor Pages、コントローラー、またはアクションに適用されます。
  • 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 ロール SalaryControllerFinance ロールのメンバーからアクセスできるのはコントローラー 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");
}

上記の ControlAllPanelController コントローラーのでは次のようになります:

  • Administrator ロールまたは PowerUser ロールのメンバーはコントローラーと SetTime アクションにアクセスできます。
  • Administrator ロールのメンバーだけが ShutDown アクションにアクセスできます。

コントローラーをロック ダウンするけれども、個々のアクションへの匿名の認証されていないアクセスを許可することもできます。

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

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

Razor ページの場合、[Authorize] は次のいずれかの方法で適用できます。

  • 規則の使用、または
  • [Authorize]PageModel インスタンスに適用する:
[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"));

この例では、AdministratorPowerUser、または BackupAdministrator ロールに属しているユーザーを認可します。

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();
}