From bdd38fb5f985e29c83e069c82956f562dc9dbd0a Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Wed, 1 Apr 2026 10:56:22 -0400 Subject: [PATCH 1/7] Claim-based authz article overhaul --- aspnetcore/blazor/security/index.md | 2 +- .../mvc/security/authorization/claims.md | 136 +++++ .../security/authorization/claims.md | 211 ++++++++ aspnetcore/security/authorization/claims.md | 479 +++++++----------- aspnetcore/security/authorization/policies.md | 2 +- .../policies/includes/policies5.md | 2 +- aspnetcore/security/authorization/roles.md | 41 +- aspnetcore/toc.yml | 6 +- 8 files changed, 556 insertions(+), 323 deletions(-) create mode 100644 aspnetcore/mvc/security/authorization/claims.md create mode 100644 aspnetcore/razor-pages/security/authorization/claims.md diff --git a/aspnetcore/blazor/security/index.md b/aspnetcore/blazor/security/index.md index fc654cbb51d6..ce0a1f516a15 100644 --- a/aspnetcore/blazor/security/index.md +++ b/aspnetcore/blazor/security/index.md @@ -1275,7 +1275,7 @@ To handle the case where the user must satisfy several policies simultaneously, ``` -Claims-based authorization is a special case of policy-based authorization. For example, you can define a policy that requires users to have a certain claim. For more information, see . +Claim-based authorization is a special case of policy-based authorization. For example, you can define a policy that requires users to have a certain claim. For more information, see . If both and are set, authorization succeeds only when both conditions are satisfied. That is, the user must belong to at least one of the specified roles *and* meet the requirements defined by the policy. diff --git a/aspnetcore/mvc/security/authorization/claims.md b/aspnetcore/mvc/security/authorization/claims.md new file mode 100644 index 000000000000..80e55e1b2481 --- /dev/null +++ b/aspnetcore/mvc/security/authorization/claims.md @@ -0,0 +1,136 @@ +--- +title: Claim-based authorization in ASP.NET Core MVC +author: wadepickett +description: Learn how to add claims checks for authorization in an ASP.NET Core MVC app. +ms.author: wpickett +monikerRange: '>= aspnetcore-3.1' +ms.date: 04/01/2026 +uid: security/authorization/claims +ai-usage: ai-assisted +--- +# Claim-based authorization in ASP.NET Core MVC + +When an identity is created for an app user upon signing into an app, the identity provider may assign one or more [claims](xref:System.Security.Claims.Claim#remarks) to the user's identity. A claim is a name value pair that represents what the subject (a user, an app or service, or a device/computer) is, not what the subject can do. A claim can be evaluated by the app to determine access rights to data and other secured resources during the process of authorization and can also be used to make or express authentication decisions about a subject. An identity can contain multiple claims with multiple values and can contain multiple claims of the same type. This article explains how to add claims checks for authorization in an ASP.NET Core app. + +This article uses MVC examples and focuses on MVC scenarios. For Blazor and Razor Pages guidance, see the following resources: + +* +* + +## Sample app + +The sample app for this article is the [`WebAll` sample app (`dotnet/AspNetCore.Docs.Samples` GitHub repository)](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/security/authorization/claims) ([how to download](xref:index#how-to-download-a-sample)). For more information, see the sample's README file (`README.md`). + +## Adding claims checks + +Claim-based authorization checks are declarative and applied to controllers or actions within a controller. + +Claims in code specify claims which the current user must possess, and optionally the value the claim must hold to access the requested resource. Claims requirements are policy based. The developer must build and register a policy expressing the claims requirements. + +The simplest type of claim policy looks for the presence of a claim and doesn't check the value. + +:::moniker range=">= aspnetcore-7.0" + +Build and register the policy and call (place the call after the line that calls ). Registering the policy takes place as part of the Authorization service configuration, typically in the `Program` file: + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/7.x/WebAll/Program.cs" id="snippet" highlight="6-7,21"::: + +:::moniker-end + +:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" + +Build and register the policy and call (place the call after the line that calls ). Registering the policy takes place as part of the Authorization service configuration, typically in the `Program` file: + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/6.x/WebAll/Program.cs" id="snippet" highlight="6-9,23"::: + +:::moniker-end + +:::moniker range="< aspnetcore-6.0" + +Build and register the policy in `Startup.ConfigureServices` (`Startup.cs`) in the Authorization service's configuration: + +```csharp +services.AddAuthorization(options => +{ + options.AddPolicy("EmployeeOnly", + policy => policy.RequireClaim("EmployeeNumber")); +}); +``` + +Call in `Startup.Configure` (`Startup.cs`) immediately after is called: + +```csharp +app.UseAuthorization(); +``` + +:::moniker-end + +Apply the policy using the `Policy` property on the [`[Authorize]`](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) attribute to specify the policy name. In the following example, the `EmployeeOnly` policy checks for the presence of an `EmployeeNumber` claim on the current identity: + + + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/7.x/WebAll/Controllers/Home2Controller.cs" id="snippet" highlight="1"::: + +The `[Authorize]` attribute can be applied to an entire controller, in which case only identities matching the policy are allowed access to any action on the controller: + + + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/7.x/WebAll/Controllers/VacationController.cs" id="snippet" highlight="1"::: + +If you have a controller that's protected by the `[Authorize]` attribute but want to allow anonymous access to a particular action, apply the [`[AllowAnonymous]` attribute](xref:System.Web.Mvc.AllowAnonymousAttribute): + + + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/7.x/WebAll/Controllers/VacationController.cs" id="snippet" highlight="14"::: + +You can specify a list of allowed values when creating a policy. The following policy only passes for employees whose employee number is 1, 2, 3, 4, or 5: + +:::moniker range=">= aspnetcore-7.0" + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/7.x/WebAll/Program.cs" id="snippet2" highlight="6-8"::: + +:::moniker-end + +:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/6.x/WebAll/Program.cs" id="snippet2" highlight="6-10"::: + +:::moniker-end + +:::moniker range="< aspnetcore-6.0" + +```csharp +services.AddAuthorization(options => +{ + options.AddPolicy("Founders", policy => + policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5")); +}); +``` + +:::moniker-end + +### Add a generic claim check + +If the claim value isn't a single value or a transformation is required, use . For more information, see . + +## Multiple Policy Evaluation + +If multiple policies are applied at the controller and action levels, ***all*** policies must pass before access is granted: + + + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/7.x/WebAll/Controllers/SalaryController.cs" id="snippet" highlight="1,14"::: + +In the preceding example, any identity that fulfills the `EmployeeOnly` policy can access the `Payslip` action, as that policy is enforced on the controller. However, in order to call the `UpdateSalary` action, the identity must fulfill *both* the `EmployeeOnly` policy and the `HumanResources` policy. + +If you want more complicated policies, such as taking a date of birth claim, calculating an age from it then checking the age is 21 or older then you need to write [custom policy handlers](xref:security/authorization/policies). + +## Claim case sensitivity + +Claim *values* are compared using [`StringComparison.Ordinal`](xref:System.StringComparison?displayProperty=nameWithType). This means `Admin` (uppercase `A`) and `admin` (lowercase `a`) are always treated as different roles, regardless of which authentication handler created the identity. + +Separately, the claim *type* comparison (used to locate role claims by their claim type, such as `http://schemas.microsoft.com/ws/2008/06/identity/claims/role`) may be case-sensitive or case-insensitive depending on the implementation. With `Microsoft.IdentityModel` in ASP.NET Core 8.0 or later (used by , , , and /), is produced during token validation, which uses case-sensitive claim type matching. + +The default provided by the .NET runtime (used in most cases, including all cookie-based flows) still uses case-insensitive claim type matching. + +In practice, this distinction rarely matters for role authorization because the role claim type is set once during identity creation and matched consistently. Always use consistent casing for role names and claim types to avoid subtle issues. diff --git a/aspnetcore/razor-pages/security/authorization/claims.md b/aspnetcore/razor-pages/security/authorization/claims.md new file mode 100644 index 000000000000..c2cdb64fb97c --- /dev/null +++ b/aspnetcore/razor-pages/security/authorization/claims.md @@ -0,0 +1,211 @@ +--- +title: Claim-based authorization in ASP.NET Core Razor Pages +author: wadepickett +description: Learn how to add claims checks for authorization in an ASP.NET Core Razor Pages app. +ms.author: wpickett +monikerRange: '>= aspnetcore-3.1' +ms.date: 04/01/2026 +uid: security/authorization/claims +ai-usage: ai-assisted +--- +# Claim-based authorization in ASP.NET Core + +When an identity is created for an app user upon signing into an app, the identity provider may assign one or more [claims](xref:System.Security.Claims.Claim#remarks) to the user's identity. A claim is a name value pair that represents what the subject (a user, an app or service, or a device/computer) is, not what the subject can do. A claim can be evaluated by the app to determine access rights to data and other secured resources during the process of authorization and can also be used to make or express authentication decisions about a subject. An identity can contain multiple claims with multiple values and can contain multiple claims of the same type. This article explains how to add claims checks for authorization in an ASP.NET Core app. + +This article uses Razor Pages examples and focuses on Razor Pages authorization scenarios. For Blazor and MVC guidance, see the following resources: + +* +* + +Examples throughout this article apply claim-based authorization via one or more [`[Authorize]` attributes](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) on `PageModel` classes. Alternatively, claim-based authorization can be applied using *conventions*. For more information, see . + +## Sample app + +The sample app for this article is the [`WebAll` sample app (`dotnet/AspNetCore.Docs.Samples` GitHub repository)](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/security/authorization/claims) ([how to download](xref:index#how-to-download-a-sample)). For more information, see the sample's README file (`README.md`). + +## Adding claims checks + +Claim-based authorization checks: + +* Are declarative. +* Are applied to Razor Pages, MVC controllers, or actions within a controller. +* Can't be applied at the Razor Page handler level. They must be applied to the page model class. + +Claims in code specify claims which the current user must possess, and optionally the value the claim must hold to access the requested resource. Claims requirements are policy based. The developer must build and register a policy expressing the claims requirements. + +The simplest type of claim policy looks for the presence of a claim and doesn't check the value. + +:::moniker range=">= aspnetcore-7.0" + +Build and register the policy and call (place the call after the line that calls ). Registering the policy takes place as part of the Authorization service configuration, typically in the `Program` file: + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/7.x/WebAll/Program.cs" id="snippet" highlight="6-7,21"::: + +:::moniker-end + +:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" + +Build and register the policy and call (place the call after the line that calls ). Registering the policy takes place as part of the Authorization service configuration, typically in the `Program` file: + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/6.x/WebAll/Program.cs" id="snippet" highlight="6-9,23"::: + +:::moniker-end + +:::moniker range="< aspnetcore-6.0" + +Build and register the policy in `Startup.ConfigureServices` (`Startup.cs`) in the Authorization service's configuration: + +```csharp +services.AddAuthorization(options => +{ + options.AddPolicy("EmployeeOnly", + policy => policy.RequireClaim("EmployeeNumber")); +}); +``` + +Call in `Startup.Configure` (`Startup.cs`) immediately after is called: + +```csharp +app.UseAuthorization(); +``` + +:::moniker-end + +Apply the policy using the `Policy` property on the [`[Authorize]`](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) attribute to specify the policy name. In the following example, the `EmployeeOnly` policy checks for the presence of an `EmployeeNumber` claim on the current identity: + + + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/7.x/WebAll/Pages/Index.cshtml.cs" id="snippet" highlight="1"::: + +Filter attributes, including the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute), can only be applied to the entire `PageModel` class and can't be applied to specific page handler methods. If you need to implement different authorization rules for different page handlers, adopt either of the following approaches. + +* Use separate Razor Pages for operations requiring different authorization levels, using [partial views](xref:mvc/views/partial) for shared content. + +* Inject and manually check the authorization policy by calling within handler methods. If authorization fails, the handler returns a `Forbid` result (). + + The following example demonstrates the approach: + + * The page's `OnGet` handler requires a Sid claim via the `RequireSidClaim` policy. + * The page's `OnPostAsync` handler requires an email claim via the `RequireEmailClaim` policy. + + > [!NOTE] + > Constructor injection of in the following example is supported with [primary constructors](/dotnet/csharp/whats-new/tutorials/primary-constructors) in C# 12 (.NET 8) or later. + + ```csharp + public class AuthPageHandlersExampleModel( + IAuthorizationService authorizationService) : PageModel + { + public async Task OnGet() + { + var authResult = + await authorizationService.AuthorizeAsync(User, "RequireSidClaim"); + + if (!authResult.Succeeded) + { + return Forbid(); + } + + // Authorized logic + + return Page(); + } + + public async Task OnPostAsync() + { + var authResult = + await authorizationService.AuthorizeAsync(User, "RequireEmailClaim"); + + if (!authResult.Succeeded) + { + return Forbid(); + } + + // Authorized logic + + return Page(); + } + } + ``` + + Alternatively, page handler methods can check claims directly by calling : + + ```csharp + public async Task OnGet() + { + if (!User.HasClaim(c => c.Type == ClaimTypes.Sid)) + { + return Forbid(); + } + + // Authorized logic + // await ... + + return Page(); + } + + public async Task OnPostAsync() + { + if (!User.HasClaim(c => c.Type == ClaimTypes.Email)) + { + return Forbid(); + } + + // Authorized logic + // await ... + + return Page(); + } + ``` + + > [!NOTE] + > is in the namespace. + +You can specify a list of allowed values when creating a policy. The following policy only passes for employees whose employee number is 1, 2, 3, 4, or 5: + +:::moniker range=">= aspnetcore-7.0" + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/7.x/WebAll/Program.cs" id="snippet2" highlight="6-8"::: + +:::moniker-end + +:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/6.x/WebAll/Program.cs" id="snippet2" highlight="6-10"::: + +:::moniker-end + +:::moniker range="< aspnetcore-6.0" + +```csharp +services.AddAuthorization(options => +{ + options.AddPolicy("Founders", policy => + policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5")); +}); +``` + +:::moniker-end + +### Add a generic claim check + +If the claim value isn't a single value or a transformation is required, use . For more information, see . + +## Multiple Policy Evaluation + +If multiple policies are applied at the controller and action levels, ***all*** policies must pass before access is granted. In the following sample, both page handler methods must fulfill *both* the `EmployeeOnly` policy and the `HumanResources` policy: + + + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/7.x/WebAll/Pages/X/Salary.cshtml.cs" id="snippet" highlight="1,2"::: + +If you want more complicated policies, such as taking a date of birth claim, calculating an age from it then checking the age is 21 or older then you need to write [custom policy handlers](xref:security/authorization/policies). + +## Claim case sensitivity + +Claim *values* are compared using [`StringComparison.Ordinal`](xref:System.StringComparison?displayProperty=nameWithType). This means `Admin` (uppercase `A`) and `admin` (lowercase `a`) are always treated as different roles, regardless of which authentication handler created the identity. + +Separately, the claim *type* comparison (used to locate role claims by their claim type, such as `http://schemas.microsoft.com/ws/2008/06/identity/claims/role`) may be case-sensitive or case-insensitive depending on the implementation. With `Microsoft.IdentityModel` in ASP.NET Core 8.0 or later (used by , , , and /), is produced during token validation, which uses case-sensitive claim type matching. + +The default provided by the .NET runtime (used in most cases, including all cookie-based flows) still uses case-insensitive claim type matching. + +In practice, this distinction rarely matters for role authorization because the role claim type is set once during identity creation and matched consistently. Always use consistent casing for role names and claim types to avoid subtle issues. diff --git a/aspnetcore/security/authorization/claims.md b/aspnetcore/security/authorization/claims.md index 34f09ff4ad99..cf080c8db82a 100644 --- a/aspnetcore/security/authorization/claims.md +++ b/aspnetcore/security/authorization/claims.md @@ -1,418 +1,268 @@ --- -title: Claims-based authorization in ASP.NET Core +title: Claim-based authorization in ASP.NET Core author: wadepickett description: Learn how to add claims checks for authorization in an ASP.NET Core app. ms.author: wpickett monikerRange: '>= aspnetcore-3.1' -ms.date: 01/22/2026 +ms.date: 04/01/2026 uid: security/authorization/claims ai-usage: ai-assisted --- -# Claims-based authorization in ASP.NET Core +# Claim-based authorization in ASP.NET Core - +When an identity is created for an app user upon signing into an app, the identity provider may assign one or more [claims](xref:System.Security.Claims.Claim#remarks) to the user's identity. A claim is a name value pair that represents what the subject (a user, an app or service, or a device/computer) is, not what the subject can do. A claim can be evaluated by the app to determine access rights to data and other secured resources during the process of authorization and can also be used to make or express authentication decisions about a subject. An identity can contain multiple claims with multiple values and can contain multiple claims of the same type. This article explains how to add claims checks for authorization in an ASP.NET Core app. -:::moniker range=">= aspnetcore-7.0" +This article uses Razor component examples and focuses on Blazor authorization scenarios. For additional Blazor guidance, see the [Additional resources](#additional-resources) section. For Razor Pages and MVC guidance, see the following resources: + +* +* -When an identity is created it may be assigned one or more claims issued by a trusted party. A claim is a name value pair that represents what the subject is, not what the subject can do. For example, you may have a driver's license, issued by a local driving license authority. Your driver's license has your date of birth on it. In this case the claim name would be `DateOfBirth`, the claim value would be your date of birth, for example `8th June 1970` and the issuer would be the driving license authority. Claims-based authorization, at its simplest, checks the value of a claim and allows access to a resource based upon that value. For example if you want access to a night club the authorization process might be: +## Sample app -The door security officer would evaluate the value of your date of birth claim and whether they trust the issuer (the driving license authority) before granting you access. +The Blazor Web App sample for this article is the [`BlazorWebAppAuthorization` sample app (`dotnet/AspNetCore.Docs.Samples` GitHub repository)](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/security/authorization/BlazorWebAppAuthorization) ([how to download](xref:index#how-to-download-a-sample)). The sample app uses seeded accounts with preconfigured claims to demonstrate most of the examples in this article. For more information, see the sample's README file (`README.md`). -An identity can contain multiple claims with multiple values and can contain multiple claims of the same type. +> [!CAUTION] +> This sample app uses an in-memory database to store user information, which isn't suitable for production scenarios. The sample app is intended for demonstration purposes only and shouldn't be used as a starting point for production apps. ## Adding claims checks Claim-based authorization checks: -* Are declarative. -* Are applied to Razor Pages, controllers, or actions within a controller. -* Can ***not*** be applied at the Razor Page handler level, they must be applied to the Page. +* Are declarative and specify claims via policies that the current user must present to access the requested resource. +* Are applied to Razor components (examples in this article), [Razor Pages](xref:razor-pages/security/authorization/claims), or [MVC controllers or actions within a controller](xref:mvc/security/authorization/claims). -Claims in code specify claims which the current user must possess, and optionally the value the claim must hold to access the requested resource. Claims requirements are policy based; the developer must build and register a policy expressing the claims requirements. +The component ([`AuthorizeView` component in Blazor documentation](xref:blazor/security/index#authorizeview-component)) supports *policy-based* authorization, where the policy requires one or more claims. Alternatively, a claims-based authorization via one or more policy checks can be set up using [`[Authorize]` attributes](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) in Razor components. The developer must build and register a policy expressing the claims requirements. This section covers basic concepts. For complete coverage, see . The simplest type of claim policy looks for the presence of a claim and doesn't check the value. -Build and register the policy and call . Registering the policy takes place as part of the Authorization service configuration, typically in the `Program.cs` file: - -[!code-csharp[](~/security/authorization/claims/samples/7.x/WebAll/Program.cs?name=snippet&highlight=6-7,21)] - -In this case the `EmployeeOnly` policy checks for the presence of an `EmployeeNumber` claim on the current identity. - -Apply the policy using the `Policy` property on the [`[Authorize]`](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) attribute to specify the policy name. - -[!code-csharp[](~/security/authorization/claims/samples/7.x/WebAll/Controllers/Home2Controller.cs?name=snippet&highlight=1)] - -The `[Authorize]` attribute can be applied to an entire controller or Razor Page, in which case only identities matching the policy are allowed access to any Action on the controller. - -[!code-csharp[](~/security/authorization/claims/samples/7.x/WebAll/Controllers/VacationController.cs?name=snippet&highlight=1)] - -The following code applies the `[Authorize]` attribute to a Razor Page: - -[!code-csharp[](~/security/authorization/claims/samples/7.x/WebAll/Pages/Index.cshtml.cs?name=snippet&highlight=1)] - -Policies can ***not*** be applied at the Razor Page handler level, they must be applied to the Page. - -If you have a controller that's protected by the `[Authorize]` attribute but want to allow anonymous access to particular actions, you apply the `AllowAnonymousAttribute` attribute. - -[!code-csharp[](~/security/authorization/claims/samples/7.x/WebAll/Controllers/VacationController.cs?name=snippet&highlight=14)] - -Because policies can ***not*** be applied at the Razor Page handler level, we recommend using a controller when policies must be applied at the page handler level. The rest of the app that doesn't require policies at the Razor Page handler level can use Razor Pages. - -Most claims come with a value. You can specify a list of allowed values when creating the policy. The following example would only succeed for employees whose employee number was 1, 2, 3, 4, or 5. +:::moniker range=">= aspnetcore-8.0" -[!code-csharp[](~/security/authorization/claims/samples/7.x/WebAll/Program.cs?name=snippet2&highlight=6-8)] +Registering the policy takes place as part of the Authorization service configuration in the app's `Program` file. In Blazor Web Apps (.NET 8 or later), calling isn't required: -### Add a generic claim check - -If the claim value isn't a single value or a transformation is required, use . For more information, see [Use a func to fulfill a policy](xref:security/authorization/policies#use-a-func-to-fulfill-a-policy). - -## Multiple Policy Evaluation - -If multiple policies are applied at the controller and action levels, ***all*** policies must pass before access is granted: - -[!code-csharp[](~/security/authorization/claims/samples/7.x/WebAll/Controllers/SalaryController.cs?name=snippet&highlight=1,14)] - -In the preceding example any identity which fulfills the `EmployeeOnly` policy can access the `Payslip` action as that policy is enforced on the controller. However, in order to call the `UpdateSalary` action the identity must fulfill *both* the `EmployeeOnly` policy and the `HumanResources` policy. - -If you want more complicated policies, such as taking a date of birth claim, calculating an age from it, and then checking that the age is 21 or older, then you need to write [custom policy handlers](xref:security/authorization/policies). - -In the following sample, both page handler methods must fulfill *both* the `EmployeeOnly` policy and the `HumanResources` policy: - -[!code-csharp[](~/security/authorization/claims/samples/7.x/WebAll/Pages/X/Salary.cshtml.cs?name=snippet&highlight=1,2)] +```csharp +builder.Services.AddAuthorizationBuilder() + .AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber")); +``` :::moniker-end -:::moniker range="= aspnetcore-6.0" - -When an identity is created it may be assigned one or more claims issued by a trusted party. A claim is a name value pair that represents what the subject is, not what the subject can do. For example, you may have a driver's license, issued by a local driving license authority. Your driver's license has your date of birth on it. In this case the claim name would be `DateOfBirth`, the claim value would be your date of birth, for example `8th June 1970` and the issuer would be the driving license authority. Claims-based authorization, at its simplest, checks the value of a claim and allows access to a resource based upon that value. For example if you want access to a night club the authorization process might be: - -The door security officer would evaluate the value of your date of birth claim and whether they trust the issuer (the driving license authority) before granting you access. +:::moniker range=">= aspnetcore-6.0" -An identity can contain multiple claims with multiple values and can contain multiple claims of the same type. +Registering the policy takes place as part of the Authorization service configuration in the app's `Program` file. In Blazor Server apps (not Blazor Web Apps), call (place the call after the line that calls ): -## Adding claims checks - -Claim-based authorization checks: - -* Are declarative. -* Are applied to Razor Pages, controllers, or actions within a controller. -* Can ***not*** be applied at the Razor Page handler level, they must be applied to the Page. - -Claims in code specify claims which the current user must possess, and optionally the value the claim must hold to access the requested resource. Claims requirements are policy based; the developer must build and register a policy expressing the claims requirements. - -The simplest type of claim policy looks for the presence of a claim and doesn't check the value. - -Build and register the policy and call . Registering the policy takes place as part of the Authorization service configuration, typically in the `Program.cs` file: +```csharp +builder.Services.AddAuthorizationBuilder() + .AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber")); -[!code-csharp[](~/security/authorization/claims/samples/6.x/WebAll/Program.cs?name=snippet&highlight=6-9,23)] +... -In this case the `EmployeeOnly` policy checks for the presence of an `EmployeeNumber` claim on the current identity. +app.UseAuthorization(); +``` -Apply the policy using the `Policy` property on the [`[Authorize]`](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) attribute to specify the policy name. +:::moniker-end -[!code-csharp[](~/security/authorization/claims/samples/6.x/WebAll/Controllers/Home2Controller.cs?name=snippet&highlight=1)] +:::moniker range="< aspnetcore-6.0" -The `[Authorize]` attribute can be applied to an entire controller or Razor Page, in which case only identities matching the policy are allowed access to any Action on the controller. +Registering the policy takes place as part of the Authorization service configuration in `Startup.ConfigureServices` (`Startup.cs`): -[!code-csharp[](~/security/authorization/claims/samples/6.x/WebAll/Controllers/VacationController.cs?name=snippet&highlight=1)] +```csharp +builder.Services.AddAuthorizationBuilder() + .AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber")); +``` -The following code applies the `[Authorize]` attribute to a Razor Page: +In Blazor Server apps (not Blazor Web Apps), call `Startup.Configure` (place the call after the line that calls ): -[!code-csharp[](~/security/authorization/claims/samples/6.x/WebAll/Pages/Index.cshtml.cs?name=snippet&highlight=1)] +```csharp +app.UseAuthorization(); +``` -Policies can ***not*** be applied at the Razor Page handler level, they must be applied to the Page. +:::moniker-end -If you have a controller that's protected by the `[Authorize]` attribute but want to allow anonymous access to particular actions, you apply the `AllowAnonymousAttribute` attribute. +Apply the policy using the `Policy` property on the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) to specify the policy name. In the following example, the `EmployeeOnly` policy checks for the presence of an `EmployeeNumber` claim on the current identity: -[!code-csharp[](~/security/authorization/claims/samples/6.x/WebAll/Controllers/VacationController.cs?name=snippet&highlight=14)] +For policy-based authorization using an component, use the parameter with a single policy name. -Because policies can ***not*** be applied at the Razor Page handler level, we recommend using a controller when policies must be applied at the page handler level. The rest of the app that doesn't require policies at the Razor Page handler level can use Razor Pages. +`Pages/PassEmployeeOnlyPolicyWithAuthorizeView.razor`: -Most claims come with a value. You can specify a list of allowed values when creating the policy. The following example would only succeed for employees whose employee number was 1, 2, 3, 4, or 5. +```razor +@page "/pass-employeeonly-policy-with-authorizeview" -[!code-csharp[](~/security/authorization/claims/samples/6.x/WebAll/Program.cs?name=snippet2&highlight=6-10)] +

Pass 'EmployeeOnly' policy with AuthorizeView

-### Add a generic claim check + + +

You satisfy the 'EmployeeOnly' policy.

+
+ +

You don't satisfy the 'EmployeeOnly' policy.

+
+
+``` -If the claim value isn't a single value or a transformation is required, use . For more information, see [Use a func to fulfill a policy](xref:security/authorization/policies#use-a-func-to-fulfill-a-policy). +Alternatively, apply the policy using the `Policy` property on the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) to specify the policy name. In the following example, the `EmployeeOnly` policy checks for the presence of an `EmployeeNumber` claim on the current identity: -## Multiple Policy Evaluation +`Pages/PassEmployeeOnlyPolicyWithAuthorizeAttribute.razor`: -If multiple policies are applied at the controller and action levels, ***all*** policies must pass before access is granted: +```razor +@page "/pass-employeeonly-policy-with-authorize-attribute" +@using Microsoft.AspNetCore.Authorization +@attribute [Authorize(Policy = "EmployeeOnly")] -[!code-csharp[](~/security/authorization/claims/samples/6.x/WebAll/Controllers/SalaryController.cs?name=snippet&highlight=1,14)] +

Pass 'EmployeeOnly' policy with [Authorize] attribute

-In the preceding example any identity which fulfills the `EmployeeOnly` policy can access the `Payslip` action as that policy is enforced on the controller. However, in order to call the `UpdateSalary` action the identity must fulfill *both* the `EmployeeOnly` policy and the `HumanResources` policy. +

You satisfy the 'EmployeeOnly' policy.

+``` -If you want more complicated policies, such as taking a date of birth claim, calculating an age from it, and then checking that the age is 21 or older, then you need to write [custom policy handlers](xref:security/authorization/policies). +You can specify a list of allowed values when creating a policy. The following policy only passes for employees whose employee number is 1, 2, 3, 4, or 5: -In the following sample, both page handler methods must fulfill *both* the `EmployeeOnly` policy and the `HumanResources` policy: +:::moniker range=">= aspnetcore-7.0" -[!code-csharp[](~/security/authorization/claims/samples/6.x/WebAll/Pages/X/Salary.cshtml.cs?name=snippet&highlight=1,2)] +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/7.x/WebAll/Program.cs" id="snippet2" highlight="6-8"::: :::moniker-end -:::moniker range="= aspnetcore-5.0" +:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" -When an identity is created it may be assigned one or more claims issued by a trusted party. A claim is a name value pair that represents what the subject is, not what the subject can do. For example, you may have a driver's license, issued by a local driving license authority. Your driver's license has your date of birth on it. In this case the claim name would be `DateOfBirth`, the claim value would be your date of birth, for example `8th June 1970` and the issuer would be the driving license authority. Claims-based authorization, at its simplest, checks the value of a claim and allows access to a resource based upon that value. For example if you want access to a night club the authorization process might be: - -The door security officer would evaluate the value of your date of birth claim and whether they trust the issuer (the driving license authority) before granting you access. - -An identity can contain multiple claims with multiple values and can contain multiple claims of the same type. - -## Adding claims checks - -Claim-based authorization checks are declarative - the developer embeds them within their code, against a controller or an action within a controller, specifying claims which the current user must possess, and optionally the value the claim must hold to access the requested resource. Claims requirements are policy based, the developer must build and register a policy expressing the claims requirements. - -The simplest type of claim policy looks for the presence of a claim and doesn't check the value. +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/6.x/WebAll/Program.cs" id="snippet2" highlight="6-10"::: -Build and register the policy. This takes place as part of the Authorization service configuration, which normally takes part in `ConfigureServices()` in your `Startup.cs` file. - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddControllersWithViews(); - services.AddRazorPages(); - - services.AddAuthorization(options => - { - options.AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber")); - }); -} -``` - -Call in `Configure`. The following code is generated by the ASP.NET Core web app templates: - -```csharp -public void Configure(IApplicationBuilder app, IWebHostEnvironment env) -{ - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - app.UseMigrationsEndPoint(); - } - else - { - app.UseExceptionHandler("/Error"); - app.UseHsts(); - } - - app.UseHttpsRedirection(); - app.UseStaticFiles(); - - app.UseRouting(); - - app.UseAuthentication(); - app.UseAuthorization(); - - app.UseEndpoints(endpoints => - { - endpoints.MapRazorPages(); - }); -} -``` - -In this case the `EmployeeOnly` policy checks for the presence of an `EmployeeNumber` claim on the current identity. +:::moniker-end -You then apply the policy using the `Policy` property on the `[Authorize]` attribute to specify the policy name; +:::moniker range="< aspnetcore-6.0" ```csharp -[Authorize(Policy = "EmployeeOnly")] -public IActionResult VacationBalance() +services.AddAuthorization(options => { - return View(); -} + options.AddPolicy("Founders", policy => + policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5")); +}); ``` -The `[Authorize]` attribute can be applied to an entire controller, in this instance only identities matching the policy will be allowed access to any Action on the controller. - -```csharp -[Authorize(Policy = "EmployeeOnly")] -public class VacationController : Controller -{ - public ActionResult VacationBalance() - { - } -} -``` +:::moniker-end -If you have a controller that's protected by the `[Authorize]` attribute, but want to allow anonymous access to particular actions you apply the `AllowAnonymousAttribute` attribute. +`Pages/PassFounderPolicyWithAuthorizeView.razor`: -```csharp -[Authorize(Policy = "EmployeeOnly")] -public class VacationController : Controller -{ - public ActionResult VacationBalance() - { - } - - [AllowAnonymous] - public ActionResult VacationPolicy() - { - } -} -``` +```razor +@page "/pass-founder-policy-with-authorizeview" -Most claims come with a value. You can specify a list of allowed values when creating the policy. The following example would only succeed for employees whose employee number was 1, 2, 3, 4 or 5. +

Pass 'Founder' policy with AuthorizeView

-```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddControllersWithViews(); - services.AddRazorPages(); - - services.AddAuthorization(options => - { - options.AddPolicy("Founders", policy => - policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5")); - }); -} + + +

You satisfy the 'Founder' policy.

+
+ +

You don't satisfy the 'Founder' policy.

+
+
``` ### Add a generic claim check -If the claim value isn't a single value or a transformation is required, use . For more information, see [Use a func to fulfill a policy](xref:security/authorization/policies#use-a-func-to-fulfill-a-policy). +If the claim value isn't a single value or a transformation is required, use . For more information, see . ## Multiple Policy Evaluation -If you apply multiple policies to a controller or action, then all policies must pass before access is granted. For example: - -```csharp -[Authorize(Policy = "EmployeeOnly")] -public class SalaryController : Controller -{ - public ActionResult Payslip() - { - } - - [Authorize(Policy = "HumanResources")] - public ActionResult UpdateSalary() - { - } -} -``` - -In the above example any identity which fulfills the `EmployeeOnly` policy can access the `Payslip` action as that policy is enforced on the controller. However in order to call the `UpdateSalary` action the identity must fulfill *both* the `EmployeeOnly` policy and the `HumanResources` policy. - -If you want more complicated policies, such as taking a date of birth claim, calculating an age from it then checking the age is 21 or older then you need to write [custom policy handlers](xref:security/authorization/policies). - -:::moniker-end - -:::moniker range="= aspnetcore-3.1" +Multiple policies are applied via multiple components. The inner component requires the user to pass it's policy and every policy of parent components. -When an identity is created it may be assigned one or more claims issued by a trusted party. A claim is a name value pair that represents what the subject is, not what the subject can do. For example, you may have a driver's license, issued by a local driving license authority. Your driver's license has your date of birth on it. In this case the claim name would be `DateOfBirth`, the claim value would be your date of birth, for example `8th June 1970` and the issuer would be the driving license authority. Claims-based authorization, at its simplest, checks the value of a claim and allows access to a resource based upon that value. For example if you want access to a night club the authorization process might be: -The door security officer would evaluate the value of your date of birth claim and whether they trust the issuer (the driving license authority) before granting you access. +The following example: -An identity can contain multiple claims with multiple values and can contain multiple claims of the same type. +* Requires the `Founder` policy, as demonstrated in the preceding [Adding claims checks](#adding-claims-checks) section. +* Also requires a `HumanResourcesMember` policy, which indicates that the user is in the organization's human resources department because they have a `Department` claim with a value of `Human Resources`. -## Adding claims checks - -Claim-based authorization checks are declarative - the developer embeds them within their code, against a controller or an action within a controller, specifying claims which the current user must possess, and optionally the value the claim must hold to access the requested resource. Claims requirements are policy based, the developer must build and register a policy expressing the claims requirements. - -The simplest type of claim policy looks for the presence of a claim and doesn't check the value. +:::moniker range=">= aspnetcore-7.0" -Build and register the policy. This takes place as part of the Authorization service configuration, which normally takes part in `ConfigureServices()` in your `Startup.cs` file. +In the app's `Program` file: ```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddControllersWithViews(); - services.AddRazorPages(); - - services.AddAuthorization(options => - { - options.AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber")); - }); -} +builder.Services.AddAuthorizationBuilder() + .AddPolicy("HumanResourcesMember", policy => + policy.RequireClaim("Department", "Human Resources")); ``` -In this case the `EmployeeOnly` policy checks for the presence of an `EmployeeNumber` claim on the current identity. +:::moniker-end + +:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" -You then apply the policy using the `Policy` property on the `[Authorize]` attribute to specify the policy name; +In the app's `Program` file: ```csharp -[Authorize(Policy = "EmployeeOnly")] -public IActionResult VacationBalance() -{ - return View(); -} +services.AddAuthorizationBuilder() + .AddPolicy("HumanResourcesMember", policy => + policy.RequireClaim("Department", "Human Resources")); ``` -The `[Authorize]` attribute can be applied to an entire controller, in this instance only identities matching the policy will be allowed access to any Action on the controller. +:::moniker-end -```csharp -[Authorize(Policy = "EmployeeOnly")] -public class VacationController : Controller -{ - public ActionResult VacationBalance() - { - } -} -``` +:::moniker range="< aspnetcore-6.0" -If you have a controller that's protected by the `[Authorize]` attribute, but want to allow anonymous access to particular actions you apply the `AllowAnonymousAttribute` attribute. +In `Startup.ConfigureServices` (`Startup.cs`): ```csharp -[Authorize(Policy = "EmployeeOnly")] -public class VacationController : Controller +services.AddAuthorization(options => { - public ActionResult VacationBalance() - { - } - - [AllowAnonymous] - public ActionResult VacationPolicy() - { - } -} + options.AddPolicy("HumanResourcesMember", policy => + policy.RequireClaim("Department", "Human Resources")); +}); ``` -Most claims come with a value. You can specify a list of allowed values when creating the policy. The following example would only succeed for employees whose employee number was 1, 2, 3, 4 or 5. +:::moniker-end -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddControllersWithViews(); - services.AddRazorPages(); - - services.AddAuthorization(options => - { - options.AddPolicy("Founders", policy => - policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5")); - }); -} +The following example uses components. + +`Pages/PassFounderAndHumanResourcesMemberPoliciesWithAuthorizeViews.razor`: + +```razor +@page "/pass-founder-and-humanresourcesmember-policies-with-authorizeviews" + +

Pass 'Founder' and 'HumanResourcesMember' policies with AuthorizeViews

+ + + +

User: @context.User.Identity?.Name

+ + +

+ You satisfy the 'Founder' and 'HumanResourcesMember' policies. +

+
+ +

+ You satisfy the 'Founder' policy, but you don't satisfy + the 'HumanResourcesMember' policy. +

+
+
+
+ +

+ You don't satisfy the 'Founder' policy. +

+
+
``` -### Add a generic claim check +The following example uses [`[Authorize]` attributes](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute). -If the claim value isn't a single value or a transformation is required, use . For more information, see [Use a func to fulfill a policy](xref:security/authorization/policies#use-a-func-to-fulfill-a-policy). +`Pages/PassFounderAndHumanResourcesMemberPoliciesWithAuthorizeAttributes.razor`: -## Multiple Policy Evaluation +```razor +@page "/pass-founder-and-humanresourcesmember-policies-with-authorize-attributes" +@using Microsoft.AspNetCore.Authorization +@attribute [Authorize(Policy = "Founder")] +@attribute [Authorize(Policy = "HumanResourcesMember")] -If you apply multiple policies to a controller or action, then all policies must pass before access is granted. For example: +

+ Pass 'Founder' and 'HumanResourcesMember' policies with [Authorize] attributes +

-```csharp -[Authorize(Policy = "EmployeeOnly")] -public class SalaryController : Controller -{ - public ActionResult Payslip() - { - } - - [Authorize(Policy = "HumanResources")] - public ActionResult UpdateSalary() - { - } -} +

+ You satisfy the 'Founder' and 'HumanResourcesMember' policies. +

``` -In the above example any identity which fulfills the `EmployeeOnly` policy can access the `Payslip` action as that policy is enforced on the controller. However in order to call the `UpdateSalary` action the identity must fulfill *both* the `EmployeeOnly` policy and the `HumanResources` policy. - If you want more complicated policies, such as taking a date of birth claim, calculating an age from it then checking the age is 21 or older then you need to write [custom policy handlers](xref:security/authorization/policies). -:::moniker-end - ## Claim case sensitivity Claim *values* are compared using [`StringComparison.Ordinal`](xref:System.StringComparison?displayProperty=nameWithType). This means `Admin` (uppercase `A`) and `admin` (lowercase `a`) are always treated as different roles, regardless of which authentication handler created the identity. @@ -422,3 +272,14 @@ Separately, the claim *type* comparison (used to locate role claims by their cla The default provided by the .NET runtime (used in most cases, including all cookie-based flows) still uses case-insensitive claim type matching. In practice, this distinction rarely matters for role authorization because the role claim type is set once during identity creation and matched consistently. Always use consistent casing for role names and claim types to avoid subtle issues. + +## Additional resources + +* +* +* +* +* +* +* +* [Extend or add custom claims, including role claims, using `IClaimsTransformation`](xref:security/authentication/claims#extend-or-add-custom-claims-using-iclaimstransformation) diff --git a/aspnetcore/security/authorization/policies.md b/aspnetcore/security/authorization/policies.md index fec7b941faa1..29008a4951a7 100644 --- a/aspnetcore/security/authorization/policies.md +++ b/aspnetcore/security/authorization/policies.md @@ -13,7 +13,7 @@ uid: security/authorization/policies :::moniker range=">= aspnetcore-6.0" -Underneath the covers, [role-based authorization](xref:security/authorization/roles) and [claims-based authorization](xref:security/authorization/claims) use a requirement, a requirement handler, and a preconfigured policy. These building blocks support the expression of authorization evaluations in code. The result is a richer, reusable, testable authorization structure. +Underneath the covers, [role-based authorization](xref:security/authorization/roles) and [claim-based authorization](xref:security/authorization/claims) use a requirement, a requirement handler, and a preconfigured policy. These building blocks support the expression of authorization evaluations in code. The result is a richer, reusable, testable authorization structure. An authorization policy consists of one or more requirements. Register it as part of the authorization service configuration, in the app's `Program.cs` file: diff --git a/aspnetcore/security/authorization/policies/includes/policies5.md b/aspnetcore/security/authorization/policies/includes/policies5.md index 54de0ec696f2..7f25640e8cf2 100644 --- a/aspnetcore/security/authorization/policies/includes/policies5.md +++ b/aspnetcore/security/authorization/policies/includes/policies5.md @@ -1,6 +1,6 @@ :::moniker range="< aspnetcore-6.0" -Underneath the covers, [role-based authorization](xref:security/authorization/roles) and [claims-based authorization](xref:security/authorization/claims) use a requirement, a requirement handler, and a pre-configured policy. These building blocks support the expression of authorization evaluations in code. The result is a richer, reusable, testable authorization structure. +Underneath the covers, [role-based authorization](xref:security/authorization/roles) and [claim-based authorization](xref:security/authorization/claims) use a requirement, a requirement handler, and a pre-configured policy. These building blocks support the expression of authorization evaluations in code. The result is a richer, reusable, testable authorization structure. An authorization policy consists of one or more requirements. It's registered as part of the authorization service configuration, in the `Startup.ConfigureServices` method: diff --git a/aspnetcore/security/authorization/roles.md b/aspnetcore/security/authorization/roles.md index c2735a715b9e..c018cff13a11 100644 --- a/aspnetcore/security/authorization/roles.md +++ b/aspnetcore/security/authorization/roles.md @@ -5,7 +5,7 @@ author: wadepickett description: Learn how to restrict ASP.NET Core Blazor Razor component access with the AuthorizeView component and by passing roles to the Authorize attribute. monikerRange: '>= aspnetcore-3.1' ms.author: wpickett -ms.date: 03/24/2026 +ms.date: 04/01/2026 uid: security/authorization/roles --- # Role-based authorization in ASP.NET Core @@ -14,12 +14,7 @@ When a user's identity is created after authentication, the user may belong to o While roles are claims, not all claims are roles. Depending on the identity issuer, a role may be a collection of users that may apply claims for group members, as well as an actual claim on an identity. However, claims are meant to be information about an individual user. Using roles to add claims to a user can confuse the boundary between the user and their individual claims. This confusion is why the single-page application (SPA) templates aren't designed around roles. In addition, for organizations migrating from an on-premises legacy system, the proliferation of roles over the years can mean a role claim may be too large to be contained within a token usable by a SPA. To secure SPAs, see . -This article uses Blazor Razor component examples and focuses on Blazor authorization scenarios. For additional Blazor guidance, see the following resources: - -* -* - -For Razor Pages and MVC guidance, which applies to all release versions of ASP.NET Core, see the following resources: +This article uses Razor component examples and focuses on Blazor authorization scenarios. For additional Blazor guidance, see the [Additional resources](#additional-resources) section. For Razor Pages and MVC guidance, see the following resources: * * @@ -32,7 +27,7 @@ Identity configuration changed with the release of .NET 6. Examples in this arti ## Sample app -The Blazor Web App sample for this article is the [`BlazorWebAppRolesWithIdentity` sample app (`dotnet/AspNetCore.Docs.Samples` GitHub repository)](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/security/authorization/BlazorWebAppRolesWithIdentity) ([how to download](xref:index#how-to-download-a-sample)). The sample app uses seeded accounts with preconfigured roles to demonstrate most of the examples in this article. For more information, see the sample's README file (`README.md`). +The Blazor Web App sample for this article is the [`BlazorWebAppAuthorization` sample app (`dotnet/AspNetCore.Docs.Samples` GitHub repository)](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/security/authorization/BlazorWebAppAuthorization) ([how to download](xref:index#how-to-download-a-sample)). The sample app uses seeded accounts with preconfigured roles to demonstrate most of the examples in this article. For more information, see the sample's README file (`README.md`). > [!CAUTION] > This sample app uses an in-memory database to store user information, which isn't suitable for production scenarios. The sample app is intended for demonstration purposes only and shouldn't be used as a starting point for production apps. @@ -83,14 +78,40 @@ services.AddIdentityCore() :::moniker-end +:::moniker range=">= aspnetcore-8.0" + +In Blazor Web Apps (.NET 8 or later), calling in the `Program` file isn't required. + +:::moniker-end + +:::moniker range=">= aspnetcore-6.0" + +In Blazor Server apps (not Blazor Web Apps), call in the `Program` file: + +```csharp +app.UseAuthorization(); +``` + +:::moniker-end + +:::moniker range="< aspnetcore-6.0" + +In Blazor Server apps (not Blazor Web Apps), call in `Startup.Configure` (`Startup.cs`): + +```csharp +app.UseAuthorization(); +``` + +:::moniker-end + ## Role-based authorization checks Role-based authorization checks: -* Are declarative and specify roles which the current user must be a member of to access the requested resource. +* Are declarative and specify roles that the current user must be a member of to access the requested resource. * Are applied to Razor components (examples in this article), [Razor Pages](xref:razor-pages/security/authorization/roles), or [MVC controllers or actions within a controller](xref:mvc/security/authorization/roles). -The component supports *role-based* authorization. This section covers basic concepts. For complete coverage, see . +The component ([`AuthorizeView` component in Blazor documentation](xref:blazor/security/index#authorizeview-component)) supports *role-based* authorization. This section covers basic concepts. For complete coverage, see . For role-based authorization of content in Razor components, use the parameter. diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 0d53f30c928f..19c1c775bc1a 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -575,6 +575,8 @@ items: uid: razor-pages/security/authorization/conventions - name: Role-based authorization uid: razor-pages/security/authorization/roles + - name: Claim-based authorization + uid: razor-pages/security/authorization/claims - name: MVC items: - name: Overview @@ -625,6 +627,8 @@ items: uid: mvc/security/authorization/iard - name: Role-based authorization uid: mvc/security/authorization/roles + - name: Claim-based authorization + uid: mvc/security/authorization/claims - name: Blazor items: - name: Overview @@ -2086,7 +2090,7 @@ items: uid: security/authorization/iard - name: Role-based authorization uid: security/authorization/roles - - name: Claims-based authorization + - name: Claim-based authorization uid: security/authorization/claims - name: Policy-based authorization uid: security/authorization/policies From b927ac88f951a4f8d4e82840f2a40dd8fd5283e0 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Wed, 1 Apr 2026 11:16:11 -0400 Subject: [PATCH 2/7] Updates --- aspnetcore/mvc/security/authorization/claims.md | 2 +- aspnetcore/razor-pages/security/authorization/claims.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aspnetcore/mvc/security/authorization/claims.md b/aspnetcore/mvc/security/authorization/claims.md index 80e55e1b2481..d48d3d1bec43 100644 --- a/aspnetcore/mvc/security/authorization/claims.md +++ b/aspnetcore/mvc/security/authorization/claims.md @@ -5,7 +5,7 @@ description: Learn how to add claims checks for authorization in an ASP.NET Core ms.author: wpickett monikerRange: '>= aspnetcore-3.1' ms.date: 04/01/2026 -uid: security/authorization/claims +uid: mvc/security/authorization/claims ai-usage: ai-assisted --- # Claim-based authorization in ASP.NET Core MVC diff --git a/aspnetcore/razor-pages/security/authorization/claims.md b/aspnetcore/razor-pages/security/authorization/claims.md index c2cdb64fb97c..5a46e52f39de 100644 --- a/aspnetcore/razor-pages/security/authorization/claims.md +++ b/aspnetcore/razor-pages/security/authorization/claims.md @@ -5,10 +5,10 @@ description: Learn how to add claims checks for authorization in an ASP.NET Core ms.author: wpickett monikerRange: '>= aspnetcore-3.1' ms.date: 04/01/2026 -uid: security/authorization/claims +uid: razor-pages/security/authorization/claims ai-usage: ai-assisted --- -# Claim-based authorization in ASP.NET Core +# Claim-based authorization in ASP.NET Core Razor Pages When an identity is created for an app user upon signing into an app, the identity provider may assign one or more [claims](xref:System.Security.Claims.Claim#remarks) to the user's identity. A claim is a name value pair that represents what the subject (a user, an app or service, or a device/computer) is, not what the subject can do. A claim can be evaluated by the app to determine access rights to data and other secured resources during the process of authorization and can also be used to make or express authentication decisions about a subject. An identity can contain multiple claims with multiple values and can contain multiple claims of the same type. This article explains how to add claims checks for authorization in an ASP.NET Core app. From 6c006c21890dc0df0734c57276108b3a6295146c Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Wed, 1 Apr 2026 11:46:47 -0400 Subject: [PATCH 3/7] React to Copilot feedback --- aspnetcore/mvc/security/authorization/claims.md | 4 ++-- .../razor-pages/security/authorization/claims.md | 8 +++----- .../razor-pages/security/authorization/roles.md | 6 ++---- aspnetcore/security/authorization/claims.md | 15 +++++++++------ 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/aspnetcore/mvc/security/authorization/claims.md b/aspnetcore/mvc/security/authorization/claims.md index d48d3d1bec43..ef4befe9430c 100644 --- a/aspnetcore/mvc/security/authorization/claims.md +++ b/aspnetcore/mvc/security/authorization/claims.md @@ -1,12 +1,12 @@ --- title: Claim-based authorization in ASP.NET Core MVC +ai-usage: ai-assisted author: wadepickett description: Learn how to add claims checks for authorization in an ASP.NET Core MVC app. ms.author: wpickett monikerRange: '>= aspnetcore-3.1' ms.date: 04/01/2026 uid: mvc/security/authorization/claims -ai-usage: ai-assisted --- # Claim-based authorization in ASP.NET Core MVC @@ -77,7 +77,7 @@ The `[Authorize]` attribute can be applied to an entire controller, in which cas :::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/claims/7.x/WebAll/Controllers/VacationController.cs" id="snippet" highlight="1"::: -If you have a controller that's protected by the `[Authorize]` attribute but want to allow anonymous access to a particular action, apply the [`[AllowAnonymous]` attribute](xref:System.Web.Mvc.AllowAnonymousAttribute): +If you have a controller that's protected by the `[Authorize]` attribute but want to allow anonymous access to a particular action, apply the [`[AllowAnonymous]` attribute](xref:Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute): diff --git a/aspnetcore/razor-pages/security/authorization/claims.md b/aspnetcore/razor-pages/security/authorization/claims.md index 5a46e52f39de..b5585e8ff212 100644 --- a/aspnetcore/razor-pages/security/authorization/claims.md +++ b/aspnetcore/razor-pages/security/authorization/claims.md @@ -1,12 +1,12 @@ --- title: Claim-based authorization in ASP.NET Core Razor Pages +ai-usage: ai-assisted author: wadepickett description: Learn how to add claims checks for authorization in an ASP.NET Core Razor Pages app. ms.author: wpickett monikerRange: '>= aspnetcore-3.1' ms.date: 04/01/2026 uid: razor-pages/security/authorization/claims -ai-usage: ai-assisted --- # Claim-based authorization in ASP.NET Core Razor Pages @@ -130,7 +130,7 @@ Filter attributes, including the [`[Authorize]` attribute](xref:Microsoft.AspNet Alternatively, page handler methods can check claims directly by calling : ```csharp - public async Task OnGet() + public IActionResult OnGet() { if (!User.HasClaim(c => c.Type == ClaimTypes.Sid)) { @@ -138,12 +138,11 @@ Filter attributes, including the [`[Authorize]` attribute](xref:Microsoft.AspNet } // Authorized logic - // await ... return Page(); } - public async Task OnPostAsync() + public IActionResult OnPostAsync() { if (!User.HasClaim(c => c.Type == ClaimTypes.Email)) { @@ -151,7 +150,6 @@ Filter attributes, including the [`[Authorize]` attribute](xref:Microsoft.AspNet } // Authorized logic - // await ... return Page(); } diff --git a/aspnetcore/razor-pages/security/authorization/roles.md b/aspnetcore/razor-pages/security/authorization/roles.md index 5a8a583c8394..1301b6248de2 100644 --- a/aspnetcore/razor-pages/security/authorization/roles.md +++ b/aspnetcore/razor-pages/security/authorization/roles.md @@ -162,7 +162,7 @@ Filter attributes, including the [`[Authorize]` attribute](xref:Microsoft.AspNet Alternatively, page handler methods can check roles directly by calling : ```csharp - public async Task OnGet() + public IActionResult OnGet() { if (!User.IsInRole("User")) { @@ -170,12 +170,11 @@ Filter attributes, including the [`[Authorize]` attribute](xref:Microsoft.AspNet } // Authorized logic - // await ... return Page(); } - public async Task OnPostAsync() + public IActionResult OnPostAsync() { if (!User.IsInRole("Admin")) { @@ -183,7 +182,6 @@ Filter attributes, including the [`[Authorize]` attribute](xref:Microsoft.AspNet } // Authorized logic - // await ... return Page(); } diff --git a/aspnetcore/security/authorization/claims.md b/aspnetcore/security/authorization/claims.md index cf080c8db82a..8082fe5352b8 100644 --- a/aspnetcore/security/authorization/claims.md +++ b/aspnetcore/security/authorization/claims.md @@ -1,12 +1,12 @@ --- title: Claim-based authorization in ASP.NET Core +ai-usage: ai-assisted author: wadepickett description: Learn how to add claims checks for authorization in an ASP.NET Core app. ms.author: wpickett monikerRange: '>= aspnetcore-3.1' ms.date: 04/01/2026 uid: security/authorization/claims -ai-usage: ai-assisted --- # Claim-based authorization in ASP.NET Core @@ -66,8 +66,11 @@ app.UseAuthorization(); Registering the policy takes place as part of the Authorization service configuration in `Startup.ConfigureServices` (`Startup.cs`): ```csharp -builder.Services.AddAuthorizationBuilder() - .AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber")); +services.AddAuthorization(options => +{ + options.AddPolicy("EmployeeOnly", policy => + policy.RequireClaim("EmployeeNumber")); +}); ``` In Blazor Server apps (not Blazor Web Apps), call `Startup.Configure` (place the call after the line that calls ): @@ -132,7 +135,7 @@ You can specify a list of allowed values when creating a policy. The following p ```csharp services.AddAuthorization(options => { - options.AddPolicy("Founders", policy => + options.AddPolicy("Founder", policy => policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5")); }); ``` @@ -162,7 +165,7 @@ If the claim value isn't a single value or a transformation is required, use components. The inner component requires the user to pass it's policy and every policy of parent components. +Multiple policies are applied via multiple components. The inner component requires the user to pass its policy and every policy of parent components. The following example: @@ -187,7 +190,7 @@ builder.Services.AddAuthorizationBuilder() In the app's `Program` file: ```csharp -services.AddAuthorizationBuilder() +builder.Services.AddAuthorizationBuilder() .AddPolicy("HumanResourcesMember", policy => policy.RequireClaim("Department", "Human Resources")); ``` From aa28a12d48725f4fbccfd643ad31823537c339d6 Mon Sep 17 00:00:00 2001 From: Luke Latham <1622880+guardrex@users.noreply.github.com> Date: Thu, 2 Apr 2026 08:00:24 -0400 Subject: [PATCH 4/7] Apply suggestions from code review Co-authored-by: Wade Pickett Co-authored-by: Luke Latham <1622880+guardrex@users.noreply.github.com> --- aspnetcore/mvc/security/authorization/claims.md | 2 +- aspnetcore/security/authorization/claims.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aspnetcore/mvc/security/authorization/claims.md b/aspnetcore/mvc/security/authorization/claims.md index ef4befe9430c..02fa9f8e210f 100644 --- a/aspnetcore/mvc/security/authorization/claims.md +++ b/aspnetcore/mvc/security/authorization/claims.md @@ -102,7 +102,7 @@ You can specify a list of allowed values when creating a policy. The following p ```csharp services.AddAuthorization(options => { - options.AddPolicy("Founders", policy => + options.AddPolicy("Founder", policy => policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5")); }); ``` diff --git a/aspnetcore/security/authorization/claims.md b/aspnetcore/security/authorization/claims.md index 8082fe5352b8..1c3a1b4c08c3 100644 --- a/aspnetcore/security/authorization/claims.md +++ b/aspnetcore/security/authorization/claims.md @@ -73,7 +73,7 @@ services.AddAuthorization(options => }); ``` -In Blazor Server apps (not Blazor Web Apps), call `Startup.Configure` (place the call after the line that calls ): +In Blazor Server apps (not Blazor Web Apps), call in `Startup.Configure` (place the call after the line that calls ): ```csharp app.UseAuthorization(); From 7ac1f41a0ec7cc1a688e3f11c2315fbc7b97ba88 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Thu, 2 Apr 2026 08:10:29 -0400 Subject: [PATCH 5/7] Update content on BWA/Blazor Server UseAuthorization call --- aspnetcore/security/authorization/claims.md | 24 +++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/aspnetcore/security/authorization/claims.md b/aspnetcore/security/authorization/claims.md index 1c3a1b4c08c3..9cd75827f5c4 100644 --- a/aspnetcore/security/authorization/claims.md +++ b/aspnetcore/security/authorization/claims.md @@ -37,18 +37,32 @@ The simplest type of claim policy looks for the presence of a claim and doesn't :::moniker range=">= aspnetcore-8.0" -Registering the policy takes place as part of the Authorization service configuration in the app's `Program` file. In Blazor Web Apps (.NET 8 or later), calling isn't required: +Registering the policy takes place as part of the Authorization service configuration in the app's `Program` file. + +In Blazor Web Apps (.NET 8 or later), calling isn't required because it's called internally: ```csharp builder.Services.AddAuthorizationBuilder() .AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber")); ``` +In Blazor Server apps, call after the line that calls (if present): + +```csharp +builder.Services.AddAuthorizationBuilder() + .AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber")); + +... + +app.UseAuthentication(); // Only present if not called internally +app.UseAuthorization(); +``` + :::moniker-end -:::moniker range=">= aspnetcore-6.0" +:::moniker range=">= aspnetcore-6.0 < aspnetcore-8.0" -Registering the policy takes place as part of the Authorization service configuration in the app's `Program` file. In Blazor Server apps (not Blazor Web Apps), call (place the call after the line that calls ): +Registering the policy takes place as part of the Authorization service configuration in the app's `Program` file. In Blazor Server apps (not Blazor Web Apps), call after the line that calls (if present): ```csharp builder.Services.AddAuthorizationBuilder() @@ -56,6 +70,7 @@ builder.Services.AddAuthorizationBuilder() ... +app.UseAuthentication(); // Only present if not called internally app.UseAuthorization(); ``` @@ -73,9 +88,10 @@ services.AddAuthorization(options => }); ``` -In Blazor Server apps (not Blazor Web Apps), call in `Startup.Configure` (place the call after the line that calls ): +In Blazor Server apps (not Blazor Web Apps), call in `Startup.Configure` after the line that calls (if present): ```csharp +app.UseAuthentication(); // Only present if not called internally app.UseAuthorization(); ``` From 85f6f90fb4ccce157064e7a5d69abad59be426d0 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Thu, 2 Apr 2026 08:27:33 -0400 Subject: [PATCH 6/7] Update Roles article for UseAuthentication changes and add remarks on Blazor WASM apps --- aspnetcore/security/authorization/claims.md | 10 +++++++++ aspnetcore/security/authorization/roles.md | 25 ++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/aspnetcore/security/authorization/claims.md b/aspnetcore/security/authorization/claims.md index 9cd75827f5c4..dd833de8ad01 100644 --- a/aspnetcore/security/authorization/claims.md +++ b/aspnetcore/security/authorization/claims.md @@ -97,6 +97,16 @@ app.UseAuthorization(); :::moniker-end +:::moniker range=">= aspnetcore-5.0" + +Blazor WebAssembly apps call in the `Program` file to add authorization services: + +```csharp +builder.Services.AddAuthorizationCore(); +``` + +:::moniker-end + Apply the policy using the `Policy` property on the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) to specify the policy name. In the following example, the `EmployeeOnly` policy checks for the presence of an `EmployeeNumber` claim on the current identity: For policy-based authorization using an component, use the parameter with a single policy name. diff --git a/aspnetcore/security/authorization/roles.md b/aspnetcore/security/authorization/roles.md index c018cff13a11..821cf9c052c3 100644 --- a/aspnetcore/security/authorization/roles.md +++ b/aspnetcore/security/authorization/roles.md @@ -82,13 +82,21 @@ services.AddIdentityCore() In Blazor Web Apps (.NET 8 or later), calling in the `Program` file isn't required. +In Blazor Server apps, call in the `Program` file after the line that calls (if present): + +```csharp +app.UseAuthentication(); // Only present if not called internally +app.UseAuthorization(); +``` + :::moniker-end -:::moniker range=">= aspnetcore-6.0" +:::moniker range=">= aspnetcore-6.0 < aspnetcore-8.0" -In Blazor Server apps (not Blazor Web Apps), call in the `Program` file: +In Blazor Server apps (not Blazor Web Apps), call in the `Program` file after the line that calls (if present): ```csharp +app.UseAuthentication(); // Only present if not called internally app.UseAuthorization(); ``` @@ -96,14 +104,25 @@ app.UseAuthorization(); :::moniker range="< aspnetcore-6.0" -In Blazor Server apps (not Blazor Web Apps), call in `Startup.Configure` (`Startup.cs`): +In Blazor Server apps (not Blazor Web Apps), call in `Startup.Configure` (`Startup.cs`) after the line that calls (if present): ```csharp +app.UseAuthentication(); // Only present if not called internally app.UseAuthorization(); ``` :::moniker-end +:::moniker range=">= aspnetcore-5.0" + +Blazor WebAssembly apps call in the `Program` file to add authorization services: + +```csharp +builder.Services.AddAuthorizationCore(); +``` + +:::moniker-end + ## Role-based authorization checks Role-based authorization checks: From 485a09978a657f0a77a7a5eb3e25607125f0e137 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Mon, 6 Apr 2026 07:41:19 -0400 Subject: [PATCH 7/7] Updates --- .../mvc/security/authorization/claims.md | 6 +-- .../security/authorization/claims.md | 6 +-- aspnetcore/security/authorization/claims.md | 47 +++++++++++-------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/aspnetcore/mvc/security/authorization/claims.md b/aspnetcore/mvc/security/authorization/claims.md index 02fa9f8e210f..1c191661be3a 100644 --- a/aspnetcore/mvc/security/authorization/claims.md +++ b/aspnetcore/mvc/security/authorization/claims.md @@ -5,7 +5,7 @@ author: wadepickett description: Learn how to add claims checks for authorization in an ASP.NET Core MVC app. ms.author: wpickett monikerRange: '>= aspnetcore-3.1' -ms.date: 04/01/2026 +ms.date: 04/06/2026 uid: mvc/security/authorization/claims --- # Claim-based authorization in ASP.NET Core MVC @@ -21,7 +21,7 @@ This article uses MVC examples and focuses on MVC scenarios. For Blazor and Razo The sample app for this article is the [`WebAll` sample app (`dotnet/AspNetCore.Docs.Samples` GitHub repository)](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/security/authorization/claims) ([how to download](xref:index#how-to-download-a-sample)). For more information, see the sample's README file (`README.md`). -## Adding claims checks +## Add claim checks Claim-based authorization checks are declarative and applied to controllers or actions within a controller. @@ -113,7 +113,7 @@ services.AddAuthorization(options => If the claim value isn't a single value or a transformation is required, use . For more information, see . -## Multiple Policy Evaluation +## Evaluate multiple policies If multiple policies are applied at the controller and action levels, ***all*** policies must pass before access is granted: diff --git a/aspnetcore/razor-pages/security/authorization/claims.md b/aspnetcore/razor-pages/security/authorization/claims.md index b5585e8ff212..6408c6a6d565 100644 --- a/aspnetcore/razor-pages/security/authorization/claims.md +++ b/aspnetcore/razor-pages/security/authorization/claims.md @@ -5,7 +5,7 @@ author: wadepickett description: Learn how to add claims checks for authorization in an ASP.NET Core Razor Pages app. ms.author: wpickett monikerRange: '>= aspnetcore-3.1' -ms.date: 04/01/2026 +ms.date: 04/06/2026 uid: razor-pages/security/authorization/claims --- # Claim-based authorization in ASP.NET Core Razor Pages @@ -23,7 +23,7 @@ Examples throughout this article apply claim-based authorization via one or more The sample app for this article is the [`WebAll` sample app (`dotnet/AspNetCore.Docs.Samples` GitHub repository)](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/security/authorization/claims) ([how to download](xref:index#how-to-download-a-sample)). For more information, see the sample's README file (`README.md`). -## Adding claims checks +## Add claim checks Claim-based authorization checks: @@ -188,7 +188,7 @@ services.AddAuthorization(options => If the claim value isn't a single value or a transformation is required, use . For more information, see . -## Multiple Policy Evaluation +## Evaluate multiple policies If multiple policies are applied at the controller and action levels, ***all*** policies must pass before access is granted. In the following sample, both page handler methods must fulfill *both* the `EmployeeOnly` policy and the `HumanResources` policy: diff --git a/aspnetcore/security/authorization/claims.md b/aspnetcore/security/authorization/claims.md index dd833de8ad01..761def81a4d6 100644 --- a/aspnetcore/security/authorization/claims.md +++ b/aspnetcore/security/authorization/claims.md @@ -5,7 +5,7 @@ author: wadepickett description: Learn how to add claims checks for authorization in an ASP.NET Core app. ms.author: wpickett monikerRange: '>= aspnetcore-3.1' -ms.date: 04/01/2026 +ms.date: 04/06/2026 uid: security/authorization/claims --- # Claim-based authorization in ASP.NET Core @@ -24,7 +24,7 @@ The Blazor Web App sample for this article is the [`BlazorWebAppAuthorization` s > [!CAUTION] > This sample app uses an in-memory database to store user information, which isn't suitable for production scenarios. The sample app is intended for demonstration purposes only and shouldn't be used as a starting point for production apps. -## Adding claims checks +## Add claim checks Claim-based authorization checks: @@ -189,14 +189,13 @@ services.AddAuthorization(options => If the claim value isn't a single value or a transformation is required, use . For more information, see . -## Multiple Policy Evaluation +## Evaluate multiple policies Multiple policies are applied via multiple components. The inner component requires the user to pass its policy and every policy of parent components. - The following example: -* Requires the `Founder` policy, as demonstrated in the preceding [Adding claims checks](#adding-claims-checks) section. +* Requires a `CustomerServiceMember` policy, which indicates that the user is in the organization's human resources department because they have a `Department` claim with a value of `Customer Service`. * Also requires a `HumanResourcesMember` policy, which indicates that the user is in the organization's human resources department because they have a `Department` claim with a value of `Human Resources`. :::moniker range=">= aspnetcore-7.0" @@ -205,6 +204,8 @@ In the app's `Program` file: ```csharp builder.Services.AddAuthorizationBuilder() + .AddPolicy("CustomerServiceMember", policy => + policy.RequireClaim("Department", "Customer Service")) .AddPolicy("HumanResourcesMember", policy => policy.RequireClaim("Department", "Human Resources")); ``` @@ -216,9 +217,13 @@ builder.Services.AddAuthorizationBuilder() In the app's `Program` file: ```csharp -builder.Services.AddAuthorizationBuilder() - .AddPolicy("HumanResourcesMember", policy => +builder.Services.AddAuthorization(options => +{ + options.AddPolicy("CustomerServiceMember", policy => + policy.RequireClaim("Department", "Customer Service")); + options.AddPolicy("HumanResourcesMember", policy => policy.RequireClaim("Department", "Human Resources")); +}); ``` :::moniker-end @@ -230,6 +235,8 @@ In `Startup.ConfigureServices` (`Startup.cs`): ```csharp services.AddAuthorization(options => { + options.AddPolicy("CustomerServiceMember", policy => + policy.RequireClaim("Department", "Customer Service")); options.AddPolicy("HumanResourcesMember", policy => policy.RequireClaim("Department", "Human Resources")); }); @@ -239,25 +246,25 @@ services.AddAuthorization(options => The following example uses components. -`Pages/PassFounderAndHumanResourcesMemberPoliciesWithAuthorizeViews.razor`: +`Pages/PassCustomerServiceMemberAndHumanResourcesMemberPoliciesWithAuthorizeViews.razor`: ```razor -@page "/pass-founder-and-humanresourcesmember-policies-with-authorizeviews" +@page "/pass-customerservicemember-and-humanresourcesmember-policies-with-authorizeviews" -

Pass 'Founder' and 'HumanResourcesMember' policies with AuthorizeViews

+

Pass 'CustomerServiceMember' and 'HumanResourcesMember' policies with AuthorizeViews

- +

User: @context.User.Identity?.Name

- You satisfy the 'Founder' and 'HumanResourcesMember' policies. + You satisfy the 'CustomerServiceMember' and 'HumanResourcesMember' policies.

- You satisfy the 'Founder' policy, but you don't satisfy + You satisfy the 'CustomerServiceMember' policy, but you don't satisfy the 'HumanResourcesMember' policy.

@@ -265,7 +272,7 @@ The following example uses

- You don't satisfy the 'Founder' policy. + You don't satisfy the 'CustomerServiceMember' policy.

@@ -273,24 +280,24 @@ The following example uses - Pass 'Founder' and 'HumanResourcesMember' policies with [Authorize] attributes + Pass 'CustomerServiceMember' and 'HumanResourcesMember' policies with [Authorize] attributes

- You satisfy the 'Founder' and 'HumanResourcesMember' policies. + You satisfy the 'CustomerServiceMember' and 'HumanResourcesMember' policies.

``` -If you want more complicated policies, such as taking a date of birth claim, calculating an age from it then checking the age is 21 or older then you need to write [custom policy handlers](xref:security/authorization/policies). +For more complicated policies, such as taking a date of birth claim, calculating an age from it then checking the age is 21 or older then you need to write [custom policy handlers](xref:security/authorization/policies). ## Claim case sensitivity