diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 2bf9e708f555..5dd4f1a65a8d 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1683,6 +1683,11 @@ "source_path": "aspnetcore/security/authorization/razor-pages-authorization.md", "redirect_url": "/aspnet/core/razor-pages/security/authorization/conventions", "redirect_document_id": false + }, + { + "source_path": "aspnetcore/security/authorization/resourcebased.md", + "redirect_url": "/aspnet/core/security/authorization/resource-based", + "redirect_document_id": false } ] } diff --git a/aspnetcore/mvc/security/authorization/resource-based.md b/aspnetcore/mvc/security/authorization/resource-based.md new file mode 100644 index 000000000000..0f3d5c758532 --- /dev/null +++ b/aspnetcore/mvc/security/authorization/resource-based.md @@ -0,0 +1,173 @@ +--- +title: Resource-based authorization in ASP.NET Core MVC +ai-usage: ai-assisted +author: wadepickett +description: Learn how to implement resource-based authorization in an ASP.NET Core MVC app when an [Authorize] attribute doesn't suffice. +ms.author: wpickett +ms.custom: mvc +ms.date: 05/05/2026 +uid: mvc/security/authorization/resource-based +--- +# Resource-based authorization in ASP.NET Core MVC + +This article describes how to authorize users for access to app resources. + +In an app, a *resource* is typically represented by a C# class that includes data stored in a collection, such as a [`byte[]` array](xref:System.Byte). The class usually contains additional metadata pertaining to the resource, such as a unique resource identifier, dates, authors, source information, and a friendly name for display in a UI. The collection that holds resource data is usually loaded from physical file content, a cloud storage object, an in-memory object, or data from a database. + +Resource-based authorization requires special attention in ASP.NET Core apps. Attribute evaluation occurs before data binding and before execution of an action that loads a resource. Declarative authorization with an `[Authorize]` attribute doesn't suffice for resource-based authorization. Instead, the app must invoke a custom authorization method—an approach known as *imperative authorization*. + +[View or download sample code](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/security/authorization/resource-based) ([how to download](xref:fundamentals/index#how-to-download-a-sample)). + + contains a sample app that uses resource-based authorization. + +Examples in this article use *primary constructors*, available in C# 12 (.NET 8) or later. For more information, see [Declare primary constructors for classes and structs (C# documentation tutorial)](/dotnet/csharp/whats-new/tutorials/primary-constructors) and [Primary constructors (C# Guide)](/dotnet/csharp/programming-guide/classes-and-structs/instance-constructors#primary-constructors). Sample apps that accompany the article that target versions of .NET earlier than .NET 8 use constructor injection. + +## Use imperative authorization + +Authorization is implemented as an , which is registered in the service collection at app startup *by the ASP.NET Core framework*. The service is made available to classes and actions via [dependency injection](xref:fundamentals/dependency-injection). The following example also injects a document repository, which the developer creates and registers in the service container to manage document operations: + +```csharp +public class DocumentController(IAuthorizationService authorizationService, + IDocumentRepository documentRepository) : Controller +``` + + has two method overloads. One of the overloads accepts a resource and policy name: + +```csharp +Task AuthorizeAsync( + ClaimsPrincipal user, + object resource, + string policyName); +``` + +The other overload accepts a resource and collection of requirements () to evaluate: + +```csharp +Task AuthorizeAsync( + ClaimsPrincipal user, + object resource, + IEnumerable requirements); +``` + +In the following example, the secured resource is loaded into a custom `Document` object. An overload is invoked to determine whether the current user is allowed to edit the document via a custom "`EditPolicy`" authorization policy. If [`authorizationResult.Succeeded`](xref:Microsoft.AspNetCore.Authorization.AuthorizationResult.Succeeded%2A) is `true`, the user is authorized for the document because they authored the document (`Document.Author` matches the user's ). + +> [!NOTE] +> The following example assumes successful authentication with the `User` property set. + +```csharp +[HttpGet] +public async Task Edit(Guid documentId) +{ + Document document = _documentRepository.Find(documentId); + + ... + + var authorizationResult = await _authorizationService + .AuthorizeAsync(User, document, "EditPolicy"); + + ... +} +``` + +## Create a resource-based handler + +Creating a resource-based authorization handler is similar to [creating a plain requirements handler](xref:security/authorization/policies#security-authorization-policies-based-authorization-handler). Create a custom requirement class and implement a requirement handler class. For more information on creating a requirement class, see the [Policy-based authorization: Requirements](xref:security/authorization/policies#requirements). + +The handler class specifies the requirement and resource type. The following example demonstrates a handler utilizing a `SameAuthorRequirement` requirement and a `Document` resource: + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/resource-based/3.0/ResourceBasedAuthApp2/Services/DocumentAuthorizationHandler.cs" id="snippet_HandlerAndRequirement"::: + + + +In the preceding example, imagine that `SameAuthorRequirement` is a special case of a more generic `SpecificAuthorRequirement` class. The `SpecificAuthorRequirement` class (not shown) contains a `Name` property representing the name of the author. The `Name` property could be set to the current user. + +:::moniker range=">= aspnetcore-6.0" + +Register the requirement and handler in `Program.cs`: + +```csharp +builder.Services.AddAuthorizationBuilder() + .AddPolicy("EditPolicy", policy => + policy.Requirements.Add(new SameAuthorRequirement())); + +builder.Services.AddSingleton(); +``` + +:::moniker-end + +:::moniker range="< aspnetcore-6.0" + +Register the requirement and handler in `Startup.ConfigureServices`: + +```csharp +services.AddAuthorization(options => +{ + options.AddPolicy("EditPolicy", policy => + policy.Requirements.Add(new SameAuthorRequirement())); +}); + +services.AddSingleton(); +``` + +:::moniker-end + +For more information on creating authorization policies, see . + +### Operational requirements + +To make decisions based on the outcomes of CRUD (Create, Read, Update, Delete) operations, use the helper class. This class enables you to write a single handler instead of an individual class for each operation type. To use it, provide some operation names: + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/resource-based/3.0/ResourceBasedAuthApp2/Services/DocumentAuthorizationCrudHandler.cs" id="snippet_OperationsClass"::: + + + +The handler is implemented as follows, using an requirement and a `Document` resource: + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/resource-based/3.0/ResourceBasedAuthApp2/Services/DocumentAuthorizationCrudHandler.cs" id="snippet_Handler"::: + + + +The preceding handler validates the operation using the resource, the user's identity, and the requirement's `Name` property. + +## Challenge and forbid with an operational resource handler + +This section shows how the challenge and forbid action results are processed and how challenge and forbid differ. + +When authorization fails but the user is authenticated, the app can return a , which informs authentication middleware that authorization failed. Return a for unauthenticated users. For interactive browser clients, it may be appropriate to redirect the user to a login page. + +> [!NOTE] +> The following example assumes successful authentication with the `User` property set. + +```csharp +if ((await authorizationService + .AuthorizeAsync(User, document, Operations.Read)).Succeeded) +{ + return View(document); +} +else if (User.Identity?.IsAuthenticated ?? false) +{ + return new ForbidResult(); +} +else +{ + return new ChallengeResult(); +} +``` diff --git a/aspnetcore/razor-pages/security/authorization/resource-based.md b/aspnetcore/razor-pages/security/authorization/resource-based.md new file mode 100644 index 000000000000..ca870038ad6a --- /dev/null +++ b/aspnetcore/razor-pages/security/authorization/resource-based.md @@ -0,0 +1,174 @@ +--- +title: Resource-based authorization in ASP.NET Core Razor Pages +ai-usage: ai-assisted +author: wadepickett +description: Learn how to implement resource-based authorization in an ASP.NET Core Razor Pages app when an [Authorize] attribute doesn't suffice. +ms.author: wpickett +ms.custom: mvc +ms.date: 05/05/2026 +uid: razor-pages/security/authorization/resource-based +--- +# Resource-based authorization in ASP.NET Core Razor Pages + +This article describes how to authorize users for access to app resources. + +In an app, a *resource* is typically represented by a C# class that includes data stored in a collection, such as a [`byte[]` array](xref:System.Byte). The class usually contains additional metadata pertaining to the resource, such as a unique resource identifier, dates, authors, source information, and a friendly name for display in a UI. The collection that holds resource data is usually loaded from physical file content, a cloud storage object, an in-memory object, or data from a database. + +Resource-based authorization requires special attention in ASP.NET Core apps. Attribute evaluation occurs before data binding and before execution of a page handler that loads a resource. Declarative authorization with an `[Authorize]` attribute doesn't suffice for resource-based authorization. Instead, the app must invoke a custom authorization method—an approach known as *imperative authorization*. + +[View or download sample code](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/security/authorization/resource-based) ([how to download](xref:fundamentals/index#how-to-download-a-sample)). + + contains a sample app that uses resource-based authorization. + +Examples in this article use *primary constructors*, available in C# 12 (.NET 8) or later. For more information, see [Declare primary constructors for classes and structs (C# documentation tutorial)](/dotnet/csharp/whats-new/tutorials/primary-constructors) and [Primary constructors (C# Guide)](/dotnet/csharp/programming-guide/classes-and-structs/instance-constructors#primary-constructors). Sample apps that accompany the article that target versions of .NET earlier than .NET 8 use constructor injection. + +## Use imperative authorization + +Authorization is implemented as an , which is registered in the service collection at app startup *by the ASP.NET Core framework*. The service is made available to classes and page handlers via [dependency injection](xref:fundamentals/dependency-injection). The following example also injects a document repository, which the developer creates and registers in the service container to manage document operations: + +```csharp +public class DocumentModel(IAuthorizationService authorizationService, + IDocumentRepository documentRepository) : PageModel +``` + + has two method overloads. One of the overloads accepts a resource and policy name: + +```csharp +Task AuthorizeAsync( + ClaimsPrincipal user, + object resource, + string policyName); +``` + +The other overload accepts a resource and collection of requirements () to evaluate: + +```csharp +Task AuthorizeAsync( + ClaimsPrincipal user, + object resource, + IEnumerable requirements); +``` + +In the following example, the secured resource is loaded into a custom `Document` object. An overload is invoked to determine whether the current user is allowed to edit the document via a custom "`EditPolicy`" authorization policy. If [`authorizationResult.Succeeded`](xref:Microsoft.AspNetCore.Authorization.AuthorizationResult.Succeeded%2A) is `true`, the user is authorized for the document because they authored the document (`Document.Author` matches the user's ). + +> [!NOTE] +> The following example assumes successful authentication with the `User` property set. + +```csharp +public async Task OnGetAsync(Guid documentId) +{ + Document = _documentRepository.Find(documentId); + + ... + + var authorizationResult = await _authorizationService + .AuthorizeAsync(User, Document, "EditPolicy"); + + ... +} +``` + +## Create a resource-based handler + +Creating a resource-based authorization handler is similar to [creating a plain requirements handler](xref:security/authorization/policies#security-authorization-policies-based-authorization-handler). Create a custom requirement class and implement a requirement handler class. For more information on creating a requirement class, see the [Policy-based authorization: Requirements](xref:security/authorization/policies#requirements). + +The handler class specifies the requirement and resource type. The following example demonstrates a handler utilizing a `SameAuthorRequirement` requirement and a `Document` resource: + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/resource-based/3.0/ResourceBasedAuthApp2/Services/DocumentAuthorizationHandler.cs" id="snippet_HandlerAndRequirement"::: + + + +In the preceding example, imagine that `SameAuthorRequirement` is a special case of a more generic `SpecificAuthorRequirement` class. The `SpecificAuthorRequirement` class (not shown) contains a `Name` property representing the name of the author. The `Name` property could be set to the current user. + +:::moniker range=">= aspnetcore-6.0" + +Register the requirement and handler in `Program.cs`: + +```csharp +builder.Services.AddAuthorizationBuilder() + .AddPolicy("EditPolicy", policy => + policy.Requirements.Add(new SameAuthorRequirement())); + +builder.Services.AddSingleton(); +``` + +:::moniker-end + +:::moniker range="< aspnetcore-6.0" + +Register the requirement and handler in `Startup.ConfigureServices`: + +```csharp +services.AddAuthorization(options => +{ + options.AddPolicy("EditPolicy", policy => + policy.Requirements.Add(new SameAuthorRequirement())); +}); + +services.AddSingleton(); +``` + +:::moniker-end + +For more information on creating authorization policies, see . + +### Operational requirements + +To make decisions based on the outcomes of CRUD (Create, Read, Update, Delete) operations, use the helper class. This class enables you to write a single handler instead of an individual class for each operation type. To use it, provide some operation names: + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/resource-based/3.0/ResourceBasedAuthApp2/Services/DocumentAuthorizationCrudHandler.cs" id="snippet_OperationsClass"::: + + + +The handler is implemented as follows, using an requirement and a `Document` resource: + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/resource-based/3.0/ResourceBasedAuthApp2/Services/DocumentAuthorizationCrudHandler.cs" id="snippet_Handler"::: + + + +The preceding handler validates the operation using the resource, the user's identity, and the requirement's `Name` property. + +## Challenge and forbid with an operational resource handler + +This section shows how the challenge and forbid results are processed and how challenge and forbid differ. + +When authorization fails but the user is authenticated, the app can return a , which informs authentication middleware that authorization failed. Return a for unauthenticated users. For interactive browser clients, it may be appropriate to redirect the user to a login page. + +> [!NOTE] +> The following example assumes successful authentication with the `User` property set. + +```csharp +var authorizationResult = await _authorizationService + .AuthorizeAsync(User, Document, Operations.Read); + +if (authorizationResult.Succeeded) +{ + return Page(); +} +else if (User.Identity?.IsAuthenticated ?? false) +{ + return new ForbidResult(); +} +else +{ + return new ChallengeResult(); +} +``` diff --git a/aspnetcore/security/authentication/index.md b/aspnetcore/security/authentication/index.md index 80582833bda9..b9aa4a89f741 100644 --- a/aspnetcore/security/authentication/index.md +++ b/aspnetcore/security/authentication/index.md @@ -133,7 +133,7 @@ A forbid action can let the user know: See the following links for differences between challenge and forbid: -* [Challenge and forbid with an operational resource handler](xref:security/authorization/resourcebased#challenge-and-forbid-with-an-operational-resource-handler). +* [Resource-based authorization](xref:security/authorization/resource-based). * [Differences between challenge and forbid](xref:security/authorization/secure-data#challenge). ## Authentication providers per tenant @@ -281,7 +281,7 @@ A forbid action can let the user know: See the following links for differences between challenge and forbid: -* [Challenge and forbid with an operational resource handler](xref:security/authorization/resourcebased#challenge-and-forbid-with-an-operational-resource-handler). +* [Challenge and forbid with an operational resource handler](xref:razor-pages/security/authorization/resource-based#challenge-and-forbid-with-an-operational-resource-handler). * [Differences between challenge and forbid](xref:security/authorization/secure-data#challenge). ## Authentication providers per tenant @@ -424,7 +424,7 @@ A forbid action can let the user know: See the following links for differences between challenge and forbid: -* [Challenge and forbid with an operational resource handler](xref:security/authorization/resourcebased#challenge-and-forbid-with-an-operational-resource-handler). +* [Resource-based authorization](xref:security/authorization/resource-based). * [Differences between challenge and forbid](xref:security/authorization/secure-data#challenge). ## Authentication providers per tenant diff --git a/aspnetcore/security/authorization/resource-based.md b/aspnetcore/security/authorization/resource-based.md new file mode 100644 index 000000000000..7fa14aa59e97 --- /dev/null +++ b/aspnetcore/security/authorization/resource-based.md @@ -0,0 +1,332 @@ +--- +title: Resource-based authorization in ASP.NET Core +ai-usage: ai-assisted +author: wadepickett +description: Learn how to implement resource-based authorization in an ASP.NET Core app when an [Authorize] attribute doesn't suffice. +ms.author: wpickett +ms.custom: mvc +ms.date: 05/05/2026 +uid: security/authorization/resource-based +--- +# Resource-based authorization in ASP.NET Core + +This article describes how to authorize users for access to app resources. + +In an app, a *resource* is typically represented by a C# class that includes data stored in a collection, such as a [`byte[]` array](xref:System.Byte). The class usually contains additional metadata pertaining to the resource, such as a unique resource identifier, dates, authors, source information, and a friendly name for display in a UI. The collection that holds resource data is usually loaded from physical file content, a cloud storage object, an in-memory object, or data from a database. + +Resource-based authorization requires special attention in ASP.NET Core apps. Attribute evaluation occurs before data binding and before execution of any method that loads a resource. Declarative authorization with an `[Authorize]` attribute doesn't suffice for resource-based authorization. Instead, the app must invoke a custom authorization method—an approach known as *imperative authorization*. + +This article uses Razor component examples and focuses on [Blazor](xref:blazor/index) authorization scenarios for ASP.NET Core 3.1 or later. For Razor Pages and MVC guidance, which apply to all releases of ASP.NET Core, see the following resources: + +* +* + +Examples in this article use *primary constructors*, available in C# 12 (.NET 8) or later. For more information, see [Declare primary constructors for classes and structs (C# documentation tutorial)](/dotnet/csharp/whats-new/tutorials/primary-constructors) and [Primary constructors (C# Guide)](/dotnet/csharp/programming-guide/classes-and-structs/instance-constructors#primary-constructors). + +## Sample app + +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 document objects to demonstrate 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. + +## Use imperative authorization + +Authorization is implemented as an , which is registered in the service collection at app startup *by the ASP.NET Core framework*. The service is made available to Razor components and other classes via [dependency injection](xref:fundamentals/dependency-injection): + +```razor +@using Microsoft.AspNetCore.Authorization +@inject IAuthorizationService AuthorizationService +``` + + has two method overloads. One of the overloads accepts a resource and policy name: + +```csharp +Task AuthorizeAsync( + ClaimsPrincipal user, + object resource, + string policyName); +``` + +The other overload accepts a resource and collection of requirements () to evaluate: + +```csharp +Task AuthorizeAsync( + ClaimsPrincipal user, + object resource, + IEnumerable requirements); +``` + +In the following example, which is fully explained in the [Create a resource-based handler](#create-a-resource-based-handler) section, the secured resource is loaded into a custom `Document` object. An overload is invoked to determine whether the current user is allowed access to the document based on the "`SameAuthorPolicy`" authorization policy. If [`authorizationResult.Succeeded`](xref:Microsoft.AspNetCore.Authorization.AuthorizationResult.Succeeded%2A) is `true`, the user is authorized for the document because they authored the document (`Document.Author` matches the user's ): + +```csharp +protected override async Task OnParametersSetAsync() +{ + var user = (await AuthStateProvider.GetAuthenticationStateAsync()).User; + + if (user.Identity is not null && user.Identity.IsAuthenticated) + { + var document = DocumentRepository.Find(DocumentId); + + ... + + var authorizationResult = await AuthorizationService + .AuthorizeAsync(user, document, "SameAuthorPolicy"); + + ... + } +} +``` + +## Create a resource-based handler + +Creating a resource-based authorization handler is similar to [creating a plain requirements handler](xref:security/authorization/policies#security-authorization-policies-based-authorization-handler). Create a custom requirement class and implement a requirement handler class. For more information on creating a requirement class, see [Policy-based authorization: Requirements](xref:security/authorization/policies#requirements). + +The following demonstration `Document` class is used: + +```csharp +namespace BlazorWebAppAuthorization.Models; + +public class Document +{ + public string? Author { get; set; } + + public byte[]? Content { get; set; } + + public Guid ID { get; set; } + + public string? Title { get; set; } +} +``` + +The handler class specifies the requirement and resource type. The following example demonstrates a handler utilizing a `SameAuthorRequirement` requirement and a `Document` resource. + +`Services/DocumentAuthorizationHandler.cs`: + +```csharp +using Microsoft.AspNetCore.Authorization; +using BlazorWebAppAuthorization.Models; + +namespace BlazorWebAppAuthorization.Services; + +public class DocumentAuthorizationHandler : + AuthorizationHandler +{ + protected override Task HandleRequirementAsync( + AuthorizationHandlerContext context, + SameAuthorRequirement requirement, + Document resource) + { + if (context.User.Identity?.Name == resource.Author) + { + context.Succeed(requirement); + } + + return Task.CompletedTask; + } +} + +public class SameAuthorRequirement : IAuthorizationRequirement { } +``` + +:::moniker range=">= aspnetcore-6.0" + +Register the requirement and handler in `Program.cs`: + +```csharp +builder.Services.AddAuthorizationBuilder() + .AddPolicy("SameAuthorPolicy", policy => + policy.Requirements.Add(new SameAuthorRequirement())); + +builder.Services.AddSingleton(); +``` + +:::moniker-end + +:::moniker range="< aspnetcore-6.0" + +Register the requirement and handler in `Startup.ConfigureServices`: + +```csharp +services.AddAuthorization(options => +{ + options.AddPolicy("SameAuthorPolicy", policy => + policy.Requirements.Add(new SameAuthorRequirement())); +}); + +services.AddSingleton(); +``` + +:::moniker-end + +For more information on creating authorization policies, see . + +The following `AccessDocument` component calls an overload to determine whether the current user is allowed to view a document based on the "`SameAuthorPolicy`" authorization policy. If [`authorizationResult.Succeeded`](xref:Microsoft.AspNetCore.Authorization.AuthorizationResult.Succeeded%2A) is `true`, the user is authorized for the document because they authored the document (`Document.Author` matches the user's ). + +`Pages/AccessDocument.razor`: + +```razor +@page "/access-document/{documentId}" +@using Microsoft.AspNetCore.Authorization +@using BlazorWebAppAuthorization.Data +@inject AuthenticationStateProvider AuthStateProvider +@inject IAuthorizationService AuthorizationService +@inject IDocumentRepository DocumentRepository + +

Access Document

+ + + +

Hello, @context.User.Identity?.Name!

+

@message

+
+ +

You're not authorized to access this page.

+
+
+ +@code { + private string? message; + + [Parameter] + public string? DocumentId { get; set; } + + protected override async Task OnParametersSetAsync() + { + var user = (await AuthStateProvider.GetAuthenticationStateAsync()).User; + + if (user.Identity is not null && user.Identity.IsAuthenticated) + { + var document = DocumentRepository.Find(DocumentId); + + if (document == null) + { + message = "Document not found."; + return; + } + + var authorizationResult = await AuthorizationService + .AuthorizeAsync(user, document, "SameAuthorPolicy"); + + message = authorizationResult.Succeeded + ? $"You are authorized for document {DocumentId}." + : $"You are NOT authorized for document {DocumentId}."; + } + } +} +``` + +In the [sample app](#sample-app), each user of the app is authorized access to the seeded document that they authored. + +## Operational requirements + +To make decisions based on the outcomes of CRUD (Create, Read, Update, Delete) operations, use the helper class. The helper class enables you to write a single handler instead of an individual class for each operation type. The following `Operations` class establishes all four CRUD operation types: + +```csharp +using Microsoft.AspNetCore.Authorization.Infrastructure; + +public static class Operations +{ + public static readonly OperationAuthorizationRequirement Create = + new() { Name = nameof(Create) }; + public static readonly OperationAuthorizationRequirement Delete = + new() { Name = nameof(Delete) }; + public static readonly OperationAuthorizationRequirement Read = + new() { Name = nameof(Read) }; + public static readonly OperationAuthorizationRequirement Update = + new() { Name = nameof(Update) }; +} +``` + +The following `DocumentAuthorizationCrudHandler` authorization handler validates the operation using the resource, the user's identity (role) in some cases, and the requirement's `Name` property: + +* All users can read documents. +* Only users in the `Admin` role can create and update documents. +* Only users in the `SuperUser` role can delete documents. + +`Services/DocumentAuthorizationCrudHandler.cs`: + +```csharp +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization.Infrastructure; +using BlazorWebAppAuthorization.Models; + +namespace BlazorWebAppAuthorization.Services; + +public class DocumentAuthorizationCrudHandler : + AuthorizationHandler +{ + protected override Task HandleRequirementAsync( + AuthorizationHandlerContext context, + OperationAuthorizationRequirement requirement, + Document resource) + { + if (requirement.Name == Operations.Create.Name && + context.User.IsInRole("Admin")) + { + context.Succeed(requirement); + } + + if (requirement.Name == Operations.Delete.Name && + context.User.IsInRole("SuperUser")) + { + context.Succeed(requirement); + } + + if (requirement.Name == Operations.Read.Name) + { + context.Succeed(requirement); + } + + if (requirement.Name == Operations.Update.Name && + context.User.IsInRole("Admin")) + { + context.Succeed(requirement); + } + + return Task.CompletedTask; + } +} +``` + +Where services are registered in the app: + +```csharp +builder.Services.AddSingleton(); +``` + +Call the overload of with the operation to return the authorization result. + +For authorization to *create* a document: + +```csharp +var authorizationResult = await AuthorizationService + .AuthorizeAsync(user, document, Operations.Create); +``` + +For authorization to *read* a document: + +```csharp +var authorizationResult = await AuthorizationService + .AuthorizeAsync(user, document, Operations.Read); +``` + +For authorization to *delete* a document: + +```csharp +var authorizationResult = await AuthorizationService + .AuthorizeAsync(user, document, Operations.Delete); +``` + +For authorization to *update* a document: + +```csharp +var authorizationResult = await AuthorizationService + .AuthorizeAsync(user, document, Operations.Update); +``` + +In the [sample app](#sample-app)'s `AccessDocumentCrud` page: + +* Leela (`leela@contoso.com`), as an `Admin` and `SuperUser`, can perform full CRUD operations on resources. +* Harry (`harry@contoso.com`), as only an `Admin`, can create, read, and update resources. +* Sarah (`sarah@contoso.com`), as only a `SuperUser`, can delete and read resources. diff --git a/aspnetcore/security/authorization/resourcebased.md b/aspnetcore/security/authorization/resourcebased.md deleted file mode 100644 index be2ab9f5bb59..000000000000 --- a/aspnetcore/security/authorization/resourcebased.md +++ /dev/null @@ -1,319 +0,0 @@ ---- -title: Resource-based authorization in ASP.NET Core -author: wadepickett -description: Learn how to implement resource-based authorization in an ASP.NET Core app when an Authorize attribute won't suffice. -ai-usage: ai-assisted -ms.author: wpickett -ms.custom: mvc -ms.date: 01/30/2026 -uid: security/authorization/resourcebased ---- -# Resource-based authorization in ASP.NET Core - -:::moniker range=">= aspnetcore-7.0" - -Authorization approach depends on the resource. For example, only the author of a document is authorized to update the document. Consequently, the document must be retrieved from the data store before authorization evaluation can occur. - -Attribute evaluation occurs before data binding and before execution of the page handler or action that loads the document. For these reasons, declarative authorization with an `[Authorize]` attribute doesn't suffice. Instead, you can invoke a custom authorization method—a style known as *imperative authorization*. - -[View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/authorization/resourcebased/samples/3_0) ([how to download](xref:fundamentals/index#how-to-download-a-sample)). - -[Create an ASP.NET Core app with user data protected by authorization](xref:security/authorization/secure-data) contains a sample app that uses resource-based authorization. - -## Use imperative authorization - -Authorization is implemented as an service and is registered in the service collection at application startup. The service is made available via [dependency injection](xref:fundamentals/dependency-injection) to page handlers or actions. - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Controllers/DocumentController.cs?name=snippet_IAuthServiceDI&highlight=6)] - -`IAuthorizationService` has two `AuthorizeAsync` method overloads: one accepting the resource and the policy name and the other accepting the resource and a list of requirements to evaluate. - -```csharp -Task AuthorizeAsync(ClaimsPrincipal user, - object resource, - IEnumerable requirements); -Task AuthorizeAsync(ClaimsPrincipal user, - object resource, - string policyName); -``` - - - -In the following example, the resource to be secured is loaded into a custom `Document` object. An `AuthorizeAsync` overload is invoked to determine whether the current user is allowed to edit the provided document. A custom "EditPolicy" authorization policy is factored into the decision. See [Custom policy-based authorization](xref:security/authorization/policies) for more on creating authorization policies. - -> [!NOTE] -> The following code samples assume authentication has run and set the `User` property. - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Pages/Document/Edit.cshtml.cs?name=snippet_DocumentEditHandler)] - -## Write a resource-based handler - -Writing a handler for resource-based authorization isn't much different than [writing a plain requirements handler](xref:security/authorization/policies#security-authorization-policies-based-authorization-handler). Create a custom requirement class, and implement a requirement handler class. For more information on creating a requirement class, see [Requirements](xref:security/authorization/policies#requirements). - -The handler class specifies both the requirement and resource type. For example, a handler utilizing a `SameAuthorRequirement` and a `Document` resource follows: - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Services/DocumentAuthorizationHandler.cs?name=snippet_HandlerAndRequirement)] - -In the preceding example, imagine that `SameAuthorRequirement` is a special case of a more generic `SpecificAuthorRequirement` class. The `SpecificAuthorRequirement` class (not shown) contains a `Name` property representing the name of the author. The `Name` property could be set to the current user. - -Register the requirement and handler in `Program.cs`: - -[!code-csharp[](resourcebased/samples/7.x/ResourceBasedAuthApp2/Program.cs?name=snippet_ConfigureServicesSample&highlight=4-6,8)] - -### Operational requirements - -If you're making decisions based on the outcomes of CRUD (Create, Read, Update, Delete) operations, use the helper class. This class enables you to write a single handler instead of an individual class for each operation type. To use it, provide some operation names: - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Services/DocumentAuthorizationCrudHandler.cs?name=snippet_OperationsClass)] - -The handler is implemented as follows, using an `OperationAuthorizationRequirement` requirement and a `Document` resource: - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Services/DocumentAuthorizationCrudHandler.cs?name=snippet_Handler)] - -The preceding handler validates the operation using the resource, the user's identity, and the requirement's `Name` property. - -## Challenge and forbid with an operational resource handler - -This section shows how the challenge and forbid action results are processed and how challenge and forbid differ. - -To call an operational resource handler, specify the operation when invoking `AuthorizeAsync` in your page handler or action. The following example determines whether the authenticated user is permitted to view the provided document. - -> [!NOTE] -> The following code samples assume authentication has run and set the `User` property. - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Pages/Document/View.cshtml.cs?name=snippet_DocumentViewHandler&highlight=10-11)] - -If authorization succeeds, the page for viewing the document is returned. If authorization fails but the user is authenticated, returning `ForbidResult` informs any authentication middleware that authorization failed. A `ChallengeResult` is returned when authentication must be performed. For interactive browser clients, it may be appropriate to redirect the user to a login page. - -:::moniker-end - -:::moniker range="= aspnetcore-6.0" - -Authorization approach depends on the resource. For example, only the author of a document is authorized to update the document. Consequently, the document must be retrieved from the data store before authorization evaluation can occur. - -Attribute evaluation occurs before data binding and before execution of the page handler or action that loads the document. For these reasons, declarative authorization with an `[Authorize]` attribute doesn't suffice. Instead, you can invoke a custom authorization method—a style known as *imperative authorization*. - -[View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/authorization/resourcebased/samples/3_0) ([how to download](xref:fundamentals/index#how-to-download-a-sample)). - -[Create an ASP.NET Core app with user data protected by authorization](xref:security/authorization/secure-data) contains a sample app that uses resource-based authorization. - -## Use imperative authorization - -Authorization is implemented as an service and is registered in the service collection at application startup. The service is made available via [dependency injection](xref:fundamentals/dependency-injection) to page handlers or actions. - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Controllers/DocumentController.cs?name=snippet_IAuthServiceDI&highlight=6)] - -`IAuthorizationService` has two `AuthorizeAsync` method overloads: one accepting the resource and the policy name and the other accepting the resource and a list of requirements to evaluate. - -```csharp -Task AuthorizeAsync(ClaimsPrincipal user, - object resource, - IEnumerable requirements); -Task AuthorizeAsync(ClaimsPrincipal user, - object resource, - string policyName); -``` - - - -In the following example, the resource to be secured is loaded into a custom `Document` object. An `AuthorizeAsync` overload is invoked to determine whether the current user is allowed to edit the provided document. A custom "EditPolicy" authorization policy is factored into the decision. See [Custom policy-based authorization](xref:security/authorization/policies) for more on creating authorization policies. - -> [!NOTE] -> The following code samples assume authentication has run and set the `User` property. - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Pages/Document/Edit.cshtml.cs?name=snippet_DocumentEditHandler)] - -## Write a resource-based handler - -Writing a handler for resource-based authorization isn't much different than [writing a plain requirements handler](xref:security/authorization/policies#security-authorization-policies-based-authorization-handler). Create a custom requirement class, and implement a requirement handler class. For more information on creating a requirement class, see [Requirements](xref:security/authorization/policies#requirements). - -The handler class specifies both the requirement and resource type. For example, a handler utilizing a `SameAuthorRequirement` and a `Document` resource follows: - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Services/DocumentAuthorizationHandler.cs?name=snippet_HandlerAndRequirement)] - -In the preceding example, imagine that `SameAuthorRequirement` is a special case of a more generic `SpecificAuthorRequirement` class. The `SpecificAuthorRequirement` class (not shown) contains a `Name` property representing the name of the author. The `Name` property could be set to the current user. - -Register the requirement and handler in `Program.cs`: - -[!code-csharp[](resourcebased/samples/6_0/ResourceBasedAuthApp2/Program.cs?name=snippet_ConfigureServicesSample&highlight=4-8,10)] - -### Operational requirements - -If you're making decisions based on the outcomes of CRUD (Create, Read, Update, Delete) operations, use the helper class. This class enables you to write a single handler instead of an individual class for each operation type. To use it, provide some operation names: - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Services/DocumentAuthorizationCrudHandler.cs?name=snippet_OperationsClass)] - -The handler is implemented as follows, using an `OperationAuthorizationRequirement` requirement and a `Document` resource: - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Services/DocumentAuthorizationCrudHandler.cs?name=snippet_Handler)] - -The preceding handler validates the operation using the resource, the user's identity, and the requirement's `Name` property. - -## Challenge and forbid with an operational resource handler - -This section shows how the challenge and forbid action results are processed and how challenge and forbid differ. - -To call an operational resource handler, specify the operation when invoking `AuthorizeAsync` in your page handler or action. The following example determines whether the authenticated user is permitted to view the provided document. - -> [!NOTE] -> The following code samples assume authentication has run and set the `User` property. - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Pages/Document/View.cshtml.cs?name=snippet_DocumentViewHandler&highlight=10-11)] - -If authorization succeeds, the page for viewing the document is returned. If authorization fails but the user is authenticated, returning `ForbidResult` informs any authentication middleware that authorization failed. A `ChallengeResult` is returned when authentication must be performed. For interactive browser clients, it may be appropriate to redirect the user to a login page. - -:::moniker-end - -:::moniker range=">= aspnetcore-3.0 < aspnetcore-6.0" - -Authorization approach depends on the resource. For example, only the author of a document is authorized to update the document. Consequently, the document must be retrieved from the data store before authorization evaluation can occur. - -Attribute evaluation occurs before data binding and before execution of the page handler or action that loads the document. For these reasons, declarative authorization with an `[Authorize]` attribute doesn't suffice. Instead, you can invoke a custom authorization method—a style known as *imperative authorization*. - -[View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/authorization/resourcebased/samples/3_0) ([how to download](xref:fundamentals/index#how-to-download-a-sample)). - -[Create an ASP.NET Core app with user data protected by authorization](xref:security/authorization/secure-data) contains a sample app that uses resource-based authorization. - -## Use imperative authorization - -Authorization is implemented as an service and is registered in the service collection within the `Startup` class. The service is made available via [dependency injection](xref:fundamentals/dependency-injection) to page handlers or actions. - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Controllers/DocumentController.cs?name=snippet_IAuthServiceDI&highlight=6)] - -`IAuthorizationService` has two `AuthorizeAsync` method overloads: one accepting the resource and the policy name and the other accepting the resource and a list of requirements to evaluate. - -```csharp -Task AuthorizeAsync(ClaimsPrincipal user, - object resource, - IEnumerable requirements); -Task AuthorizeAsync(ClaimsPrincipal user, - object resource, - string policyName); -``` - - - -In the following example, the resource to be secured is loaded into a custom `Document` object. An `AuthorizeAsync` overload is invoked to determine whether the current user is allowed to edit the provided document. A custom "EditPolicy" authorization policy is factored into the decision. See [Custom policy-based authorization](xref:security/authorization/policies) for more on creating authorization policies. - -> [!NOTE] -> The following code samples assume authentication has run and set the `User` property. - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Pages/Document/Edit.cshtml.cs?name=snippet_DocumentEditHandler)] - -## Write a resource-based handler - -Writing a handler for resource-based authorization isn't much different than [writing a plain requirements handler](xref:security/authorization/policies#security-authorization-policies-based-authorization-handler). Create a custom requirement class, and implement a requirement handler class. For more information on creating a requirement class, see [Requirements](xref:security/authorization/policies#requirements). - -The handler class specifies both the requirement and resource type. For example, a handler utilizing a `SameAuthorRequirement` and a `Document` resource follows: - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Services/DocumentAuthorizationHandler.cs?name=snippet_HandlerAndRequirement)] - -In the preceding example, imagine that `SameAuthorRequirement` is a special case of a more generic `SpecificAuthorRequirement` class. The `SpecificAuthorRequirement` class (not shown) contains a `Name` property representing the name of the author. The `Name` property could be set to the current user. - -Register the requirement and handler in `Startup.ConfigureServices`: - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Startup.cs?name=snippet_ConfigureServicesSample&highlight=4-8,10)] - -### Operational requirements - -If you're making decisions based on the outcomes of CRUD (Create, Read, Update, Delete) operations, use the helper class. This class enables you to write a single handler instead of an individual class for each operation type. To use it, provide some operation names: - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Services/DocumentAuthorizationCrudHandler.cs?name=snippet_OperationsClass)] - -The handler is implemented as follows, using an `OperationAuthorizationRequirement` requirement and a `Document` resource: - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Services/DocumentAuthorizationCrudHandler.cs?name=snippet_Handler)] - -The preceding handler validates the operation using the resource, the user's identity, and the requirement's `Name` property. - -## Challenge and forbid with an operational resource handler - -This section shows how the challenge and forbid action results are processed and how challenge and forbid differ. - -To call an operational resource handler, specify the operation when invoking `AuthorizeAsync` in your page handler or action. The following example determines whether the authenticated user is permitted to view the provided document. - -> [!NOTE] -> The following code samples assume authentication has run and set the `User` property. - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Pages/Document/View.cshtml.cs?name=snippet_DocumentViewHandler&highlight=10-11)] - -If authorization succeeds, the page for viewing the document is returned. If authorization fails but the user is authenticated, returning `ForbidResult` informs any authentication middleware that authorization failed. A `ChallengeResult` is returned when authentication must be performed. For interactive browser clients, it may be appropriate to redirect the user to a login page. - -:::moniker-end - -:::moniker range="< aspnetcore-3.0" - -Authorization approach depends on the resource. For example, only the author of a document is authorized to update the document. Consequently, the document must be retrieved from the data store before authorization evaluation can occur. - -Attribute evaluation occurs before data binding and before execution of the page handler or action that loads the document. For these reasons, declarative authorization with an `[Authorize]` attribute doesn't suffice. Instead, you can invoke a custom authorization method—a style known as *imperative authorization*. - -[View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/authorization/resourcebased/samples/2_2) ([how to download](xref:fundamentals/index#how-to-download-a-sample)). - -[Create an ASP.NET Core app with user data protected by authorization](xref:security/authorization/secure-data) contains a sample app that uses resource-based authorization. - -## Use imperative authorization - -Authorization is implemented as an service and is registered in the service collection within the `Startup` class. The service is made available via [dependency injection](xref:fundamentals/dependency-injection) to page handlers or actions. - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Controllers/DocumentController.cs?name=snippet_IAuthServiceDI&highlight=6)] - -`IAuthorizationService` has two `AuthorizeAsync` method overloads: one accepting the resource and the policy name and the other accepting the resource and a list of requirements to evaluate. - -```csharp -Task AuthorizeAsync(ClaimsPrincipal user, - object resource, - IEnumerable requirements); -Task AuthorizeAsync(ClaimsPrincipal user, - object resource, - string policyName); -``` - - - -In the following example, the resource to be secured is loaded into a custom `Document` object. An `AuthorizeAsync` overload is invoked to determine whether the current user is allowed to edit the provided document. A custom "EditPolicy" authorization policy is factored into the decision. See [Custom policy-based authorization](xref:security/authorization/policies) for more on creating authorization policies. - -> [!NOTE] -> The following code samples assume authentication has run and set the `User` property. - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Pages/Document/Edit.cshtml.cs?name=snippet_DocumentEditHandler)] - -## Write a resource-based handler - -Writing a handler for resource-based authorization isn't much different than [writing a plain requirements handler](xref:security/authorization/policies#security-authorization-policies-based-authorization-handler). Create a custom requirement class, and implement a requirement handler class. For more information on creating a requirement class, see [Requirements](xref:security/authorization/policies#requirements). - -The handler class specifies both the requirement and resource type. For example, a handler utilizing a `SameAuthorRequirement` and a `Document` resource follows: - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Services/DocumentAuthorizationHandler.cs?name=snippet_HandlerAndRequirement)] - -In the preceding example, imagine that `SameAuthorRequirement` is a special case of a more generic `SpecificAuthorRequirement` class. The `SpecificAuthorRequirement` class (not shown) contains a `Name` property representing the name of the author. The `Name` property could be set to the current user. - -Register the requirement and handler in `Startup.ConfigureServices`: - -[!code-csharp[](resourcebased/samples/2_2/ResourceBasedAuthApp2/Startup.cs?name=snippet_ConfigureServicesSample&highlight=3-7,9)] - -### Operational requirements - -If you're making decisions based on the outcomes of CRUD (Create, Read, Update, Delete) operations, use the helper class. This class enables you to write a single handler instead of an individual class for each operation type. To use it, provide some operation names: - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Services/DocumentAuthorizationCrudHandler.cs?name=snippet_OperationsClass)] - -The handler is implemented as follows, using an `OperationAuthorizationRequirement` requirement and a `Document` resource: - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Services/DocumentAuthorizationCrudHandler.cs?name=snippet_Handler)] - -The preceding handler validates the operation using the resource, the user's identity, and the requirement's `Name` property. - -## Challenge and forbid with an operational resource handler - -This section shows how the challenge and forbid action results are processed and how challenge and forbid differ. - -To call an operational resource handler, specify the operation when invoking `AuthorizeAsync` in your page handler or action. The following example determines whether the authenticated user is permitted to view the provided document. - -> [!NOTE] -> The following code samples assume authentication has run and set the `User` property. - -[!code-csharp[](resourcebased/samples/3_0/ResourceBasedAuthApp2/Pages/Document/View.cshtml.cs?name=snippet_DocumentViewHandler&highlight=10-11)] - -If authorization succeeds, the page for viewing the document is returned. If authorization fails but the user is authenticated, returning `ForbidResult` informs any authentication middleware that authorization failed. A `ChallengeResult` is returned when authentication must be performed. For interactive browser clients, it may be appropriate to redirect the user to a login page. - -:::moniker-end diff --git a/aspnetcore/security/authorization/views.md b/aspnetcore/security/authorization/views.md index 10c8331fc0fd..b4ae52110693 100644 --- a/aspnetcore/security/authorization/views.md +++ b/aspnetcore/security/authorization/views.md @@ -18,7 +18,7 @@ A developer often wants to show, hide, or otherwise modify a UI based on the cur If you want the authorization service in every view, place the `@inject` directive into the `_ViewImports.cshtml` file of the `Views` directory. For more information, see [Dependency injection into views](xref:mvc/views/dependency-injection). -Use the injected authorization service to invoke `AuthorizeAsync` in exactly the same way you would check during [resource-based authorization](xref:security/authorization/resourcebased#security-authorization-resource-based-imperative): +Use the injected authorization service to invoke `AuthorizeAsync` in exactly the same way you would check during [resource-based authorization](xref:security/authorization/resource-based#use-imperative-authorization): ```cshtml @if ((await AuthorizationService.AuthorizeAsync(User, "PolicyName")).Succeeded) @@ -27,7 +27,7 @@ Use the injected authorization service to invoke `AuthorizeAsync` in exactly the } ``` -In some cases, the resource will be your view model. Invoke `AuthorizeAsync` in exactly the same way you would check during [resource-based authorization](xref:security/authorization/resourcebased#security-authorization-resource-based-imperative): +In some cases, the resource is your view model. Invoke `AuthorizeAsync` in exactly the same way you would check during [resource-based authorization](xref:security/authorization/resource-based#use-imperative-authorization): ```cshtml @if ((await AuthorizationService.AuthorizeAsync(User, Model, Operations.Edit)).Succeeded) diff --git a/aspnetcore/signalr/authn-and-authz.md b/aspnetcore/signalr/authn-and-authz.md index e219c1f5decd..bb2f450130c9 100644 --- a/aspnetcore/signalr/authn-and-authz.md +++ b/aspnetcore/signalr/authn-and-authz.md @@ -202,7 +202,7 @@ In the preceding example, the `DomainRestrictedRequirement` class is both an `IA ## Additional resources * [Bearer Token Authentication in ASP.NET Core](https://blogs.msdn.microsoft.com/webdev/2016/10/27/bearer-token-authentication-in-asp-net-core/) -* [Resource-based Authorization](xref:security/authorization/resourcebased) +* [Resource-based authorization](xref:security/authorization/resource-based) * [View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/signalr/authn-and-authz/sample/) [(how to download)](xref:fundamentals/index#how-to-download-a-sample) :::moniker-end @@ -491,6 +491,6 @@ In the preceding example, the `DomainRestrictedRequirement` class is both an `IA ## Additional resources * [Bearer Token Authentication in ASP.NET Core](https://blogs.msdn.microsoft.com/webdev/2016/10/27/bearer-token-authentication-in-asp-net-core/) -* [Resource-based Authorization](xref:security/authorization/resourcebased) +* [Resource-based authorization](xref:security/authorization/resource-based) :::moniker-end diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index ad01c634932d..816d368a9042 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -574,6 +574,8 @@ items: uid: razor-pages/security/authorization/roles - name: Claim-based authorization uid: razor-pages/security/authorization/claims + - name: Resource-based authorization + uid: razor-pages/security/authorization/resource-based - name: MVC items: - name: Overview @@ -626,6 +628,8 @@ items: uid: mvc/security/authorization/roles - name: Claim-based authorization uid: mvc/security/authorization/claims + - name: Resource-based authorization + uid: mvc/security/authorization/resource-based - name: Blazor items: - name: Overview @@ -2098,7 +2102,7 @@ items: - name: Dependency injection in requirement handlers uid: security/authorization/dependencyinjection - name: Resource-based authorization - uid: security/authorization/resourcebased + uid: security/authorization/resource-based - name: View-based authorization uid: security/authorization/views - name: Limit identity by scheme