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..1c191661be3a --- /dev/null +++ b/aspnetcore/mvc/security/authorization/claims.md @@ -0,0 +1,136 @@ +--- +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/06/2026 +uid: mvc/security/authorization/claims +--- +# 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`). + +## Add claim 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:Microsoft.AspNetCore.Authorization.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("Founder", 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 . + +## Evaluate multiple policies + +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..6408c6a6d565 --- /dev/null +++ b/aspnetcore/razor-pages/security/authorization/claims.md @@ -0,0 +1,209 @@ +--- +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/06/2026 +uid: razor-pages/security/authorization/claims +--- +# 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. + +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`). + +## Add claim 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 IActionResult OnGet() + { + if (!User.HasClaim(c => c.Type == ClaimTypes.Sid)) + { + return Forbid(); + } + + // Authorized logic + + return Page(); + } + + public IActionResult OnPostAsync() + { + if (!User.HasClaim(c => c.Type == ClaimTypes.Email)) + { + return Forbid(); + } + + // Authorized logic + + 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 . + +## 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: + + + +:::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/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 34f09ff4ad99..761def81a4d6 100644 --- a/aspnetcore/security/authorization/claims.md +++ b/aspnetcore/security/authorization/claims.md @@ -1,417 +1,303 @@ --- -title: Claims-based authorization in ASP.NET Core +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: 01/22/2026 +ms.date: 04/06/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 +## Add claim 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. +:::moniker range=">= aspnetcore-8.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. +Registering the policy takes place as part of the Authorization service configuration in the app's `Program` file. -[!code-csharp[](~/security/authorization/claims/samples/7.x/WebAll/Controllers/VacationController.cs?name=snippet&highlight=14)] +In Blazor Web Apps (.NET 8 or later), calling isn't required because it's called internally: -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. - -[!code-csharp[](~/security/authorization/claims/samples/7.x/WebAll/Program.cs?name=snippet2&highlight=6-8)] - -### 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)] +```csharp +builder.Services.AddAuthorizationBuilder() + .AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber")); +``` -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. +In Blazor Server apps, call after the line that calls (if present): -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). +```csharp +builder.Services.AddAuthorizationBuilder() + .AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber")); -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)] +app.UseAuthentication(); // Only present if not called internally +app.UseAuthorization(); +``` :::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: +:::moniker range=">= aspnetcore-6.0 < aspnetcore-8.0" -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. +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): -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: +```csharp +builder.Services.AddAuthorizationBuilder() + .AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber")); -* 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. +app.UseAuthentication(); // Only present if not called internally +app.UseAuthorization(); +``` -The simplest type of claim policy looks for the presence of a claim and doesn't check the value. +:::moniker-end -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: +:::moniker range="< aspnetcore-6.0" -[!code-csharp[](~/security/authorization/claims/samples/6.x/WebAll/Program.cs?name=snippet&highlight=6-9,23)] +Registering the policy takes place as part of the Authorization service configuration in `Startup.ConfigureServices` (`Startup.cs`): -In this case the `EmployeeOnly` policy checks for the presence of an `EmployeeNumber` claim on the current identity. +```csharp +services.AddAuthorization(options => +{ + options.AddPolicy("EmployeeOnly", policy => + policy.RequireClaim("EmployeeNumber")); +}); +``` -Apply the policy using the `Policy` property on the [`[Authorize]`](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) attribute to specify the policy name. +In Blazor Server apps (not Blazor Web Apps), call in `Startup.Configure` after the line that calls (if present): -[!code-csharp[](~/security/authorization/claims/samples/6.x/WebAll/Controllers/Home2Controller.cs?name=snippet&highlight=1)] +```csharp +app.UseAuthentication(); // Only present if not called internally +app.UseAuthorization(); +``` -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. +:::moniker-end -[!code-csharp[](~/security/authorization/claims/samples/6.x/WebAll/Controllers/VacationController.cs?name=snippet&highlight=1)] +:::moniker range=">= aspnetcore-5.0" -The following code applies the `[Authorize]` attribute to a Razor Page: +Blazor WebAssembly apps call in the `Program` file to add authorization services: -[!code-csharp[](~/security/authorization/claims/samples/6.x/WebAll/Pages/Index.cshtml.cs?name=snippet&highlight=1)] +```csharp +builder.Services.AddAuthorizationCore(); +``` -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")); - }); -} -``` +:::moniker-end -Call in `Configure`. The following code is generated by the ASP.NET Core web app templates: +:::moniker range="< aspnetcore-6.0" ```csharp -public void Configure(IApplicationBuilder app, IWebHostEnvironment env) +services.AddAuthorization(options => { - 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(); - }); -} + options.AddPolicy("Founder", policy => + policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5")); +}); ``` -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; +`Pages/PassFounderPolicyWithAuthorizeView.razor`: -```csharp -[Authorize(Policy = "EmployeeOnly")] -public IActionResult VacationBalance() -{ - return View(); -} -``` +```razor +@page "/pass-founder-policy-with-authorizeview" -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. +

Pass 'Founder' policy with AuthorizeView

-```csharp -[Authorize(Policy = "EmployeeOnly")] -public class VacationController : Controller -{ - public ActionResult VacationBalance() - { - } -} + + +

You satisfy the 'Founder' policy.

+
+ +

You don't satisfy the 'Founder' policy.

+
+
``` -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. +### Add a generic claim check -```csharp -[Authorize(Policy = "EmployeeOnly")] -public class VacationController : Controller -{ - public ActionResult VacationBalance() - { - } - - [AllowAnonymous] - public ActionResult VacationPolicy() - { - } -} -``` +If the claim value isn't a single value or a transformation is required, use . For more information, see . -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. +## Evaluate multiple policies -```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")); - }); -} -``` +Multiple policies are applied via multiple components. The inner component requires the user to pass its policy and every policy of parent components. -### Add a generic claim check +The following example: -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). +* 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`. -## Multiple Policy Evaluation +:::moniker range=">= aspnetcore-7.0" -If you apply multiple policies to a controller or action, then all policies must pass before access is granted. For example: +In the app's `Program` file: ```csharp -[Authorize(Policy = "EmployeeOnly")] -public class SalaryController : Controller -{ - public ActionResult Payslip() - { - } - - [Authorize(Policy = "HumanResources")] - public ActionResult UpdateSalary() - { - } -} +builder.Services.AddAuthorizationBuilder() + .AddPolicy("CustomerServiceMember", policy => + policy.RequireClaim("Department", "Customer Service")) + .AddPolicy("HumanResourcesMember", policy => + policy.RequireClaim("Department", "Human Resources")); ``` -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" - -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. +:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" -## 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. - -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) +builder.Services.AddAuthorization(options => { - services.AddControllersWithViews(); - services.AddRazorPages(); - - services.AddAuthorization(options => - { - options.AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber")); - }); -} + options.AddPolicy("CustomerServiceMember", policy => + policy.RequireClaim("Department", "Customer Service")); + options.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 -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() -{ - return View(); -} -``` - -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. +In `Startup.ConfigureServices` (`Startup.cs`): ```csharp -[Authorize(Policy = "EmployeeOnly")] -public class VacationController : Controller +services.AddAuthorization(options => { - public ActionResult VacationBalance() - { - } -} + options.AddPolicy("CustomerServiceMember", policy => + policy.RequireClaim("Department", "Customer Service")); + options.AddPolicy("HumanResourcesMember", policy => + policy.RequireClaim("Department", "Human Resources")); +}); ``` -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. - -```csharp -[Authorize(Policy = "EmployeeOnly")] -public class VacationController : Controller -{ - public ActionResult VacationBalance() - { - } - - [AllowAnonymous] - public ActionResult VacationPolicy() - { - } -} -``` - -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/PassCustomerServiceMemberAndHumanResourcesMemberPoliciesWithAuthorizeViews.razor`: + +```razor +@page "/pass-customerservicemember-and-humanresourcesmember-policies-with-authorizeviews" + +

Pass 'CustomerServiceMember' and 'HumanResourcesMember' policies with AuthorizeViews

+ + + +

User: @context.User.Identity?.Name

+ + +

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

+
+ +

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

+
+
+
+ +

+ You don't satisfy the 'CustomerServiceMember' 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/PassCustomerServiceMemberAndHumanResourcesMemberPoliciesWithAuthorizeAttributes.razor`: -## Multiple Policy Evaluation +```razor +@page "/pass-customerservicemember-and-humanresourcesmember-policies-with-authorize-attributes" +@using Microsoft.AspNetCore.Authorization +@attribute [Authorize(Policy = "CustomerServiceMember")] +@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 'CustomerServiceMember' 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 'CustomerServiceMember' 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 +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 @@ -422,3 +308,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..821cf9c052c3 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,59 @@ 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. + +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 < aspnetcore-8.0" + +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(); +``` + +:::moniker-end + +:::moniker range="< aspnetcore-6.0" + +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: -* 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