From c5cca0642cbb3040ead296820e1fea85f2d1a315 Mon Sep 17 00:00:00 2001 From: Mike Rousos Date: Tue, 16 Apr 2019 00:19:18 -0400 Subject: [PATCH] Update `IAuthorizationPolicyProvider` docs (#11901) * Update `IAuthorizationPolicyProvider` docs This adds more details on using fallback providers and adds documentation for the `GetRequiredPolicyAsync` API. Fixes #10824 * Proof-reading fixes * minor tweaks * remove unnecessary word * fix spelling mistake --- .../iauthorizationpolicyprovider.md | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/aspnetcore/security/authorization/iauthorizationpolicyprovider.md b/aspnetcore/security/authorization/iauthorizationpolicyprovider.md index 838feb5a49..28fbe96efe 100644 --- a/aspnetcore/security/authorization/iauthorizationpolicyprovider.md +++ b/aspnetcore/security/authorization/iauthorizationpolicyprovider.md @@ -4,7 +4,7 @@ author: mjrousos description: Learn how to use a custom IAuthorizationPolicyProvider in an ASP.NET Core app to dynamically generate authorization policies. ms.author: riande ms.custom: mvc -ms.date: 01/21/2019 +ms.date: 04/15/2019 uid: security/authorization/iauthorizationpolicyprovider --- # Custom Authorization Policy Providers using IAuthorizationPolicyProvider in ASP.NET Core @@ -38,7 +38,7 @@ By implementing these two APIs, you can customize how authorization policies are One scenario where `IAuthorizationPolicyProvider` is useful is enabling custom `[Authorize]` attributes whose requirements depend on a parameter. For example, in [policy-based authorization](xref:security/authorization/policies) documentation, an age-based (“AtLeast21”) policy was used as a sample. If different controller actions in an app should be made available to users of *different* ages, it might be useful to have many different age-based policies. Instead of registering all the different age-based policies that the application will need in `AuthorizationOptions`, you can generate the policies dynamically with a custom `IAuthorizationPolicyProvider`. To make using the policies easier, you can annotate actions with custom authorization attribute like `[MinimumAgeAuthorize(20)]`. -## Custom Authorization Attributes +## Custom Authorization attributes Authorization policies are identified by their names. The custom `MinimumAgeAuthorizeAttribute` described previously needs to map arguments into a string that can be used to retrieve the corresponding authorization policy. You can do this by deriving from `AuthorizeAttribute` and making the `Age` property wrap the `AuthorizeAttribute.Policy` property. @@ -114,13 +114,33 @@ internal class MinimumAgePolicyProvider : IAuthorizationPolicyProvider ## Multiple authorization policy providers -When using custom `IAuthorizationPolicyProvider` implementations, keep in mind that ASP.NET Core only uses one instance of `IAuthorizationPolicyProvider`. If a custom provider isn't able to provide authorization policies for all policy names, it should fall back to a backup provider. Policy names might include those that come from a default policy for `[Authorize]` attributes without a name. +When using custom `IAuthorizationPolicyProvider` implementations, keep in mind that ASP.NET Core only uses one instance of `IAuthorizationPolicyProvider`. If a custom provider isn't able to provide authorization policies for all policy names that will be used, it should fall back to a backup provider. -For example, consider an application needed both custom age policies and more traditional role-based policy retrieval. Such an app could use a custom authorization policy provider that: +For example, consider an application that needs both custom age policies and more traditional role-based policy retrieval. Such an app could use a custom authorization policy provider that: * Attempts to parse policy names. * Calls into a different policy provider (like `DefaultAuthorizationPolicyProvider`) if the policy name doesn't contain an age. +The example `IAuthorizationPolicyProvider` implementation shown above can be updated to use the `DefaultAuthorizationPolicyProvider` by creating a fallback policy provider in its constructor (to be used in case the policy name doesn't match its expected pattern of 'MinimumAge' + age). + +```csharp +private DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; } + +public MinimumAgePolicyProvider(IOptions options) +{ + // ASP.NET Core only uses one authorization policy provider, so if the custom implementation + // doesn't handle all policies it should fall back to an alternate provider. + FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options); +} +``` + +Then, the `GetPolicyAsync` method can be updated to use the `FallbackPolicyProvider` instead of returning null: + +```csharp +... +return FallbackPolicyProvider.GetPolicyAsync(policyName); +``` + ## Default policy In addition to providing named authorization policies, a custom `IAuthorizationPolicyProvider` needs to implement `GetDefaultPolicyAsync` to provide an authorization policy for `[Authorize]` attributes without a policy name specified. @@ -132,10 +152,18 @@ public Task GetDefaultPolicyAsync() => Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build()); ``` -As with all aspects of a custom `IAuthorizationPolicyProvider`, you can customize this, as needed. In some cases: +As with all aspects of a custom `IAuthorizationPolicyProvider`, you can customize this, as needed. In some cases, it may be desirable to retrieve the default policy from a fallback `IAuthorizationPolicyProvider`. -* Default authorization policies might not be used. -* Retrieving the default policy can be delegated to a fallback `IAuthorizationPolicyProvider`. +## Required policy + +A custom `IAuthorizationPolicyProvider` needs to implement `GetRequiredPolicyAsync` to, optionally, provide a policy that is always required. If `GetRequiredPolicyAsync` returns a non-null policy, that policy will be combined with any other (named or default) policy that is requested. + +If no required policy is needed, the provider can just return null or defer to the fallback provider: + +```csharp +public Task GetRequiredPolicyAsync() => + Task.FromResult(null); +``` ## Use a custom IAuthorizationPolicyProvider