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
pull/11987/head
Mike Rousos 2019-04-16 00:19:18 -04:00 committed by Scott Addie
parent 86e1c1b3bf
commit c5cca0642c
1 changed files with 35 additions and 7 deletions

View File

@ -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<AuthorizationOptions> 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<AuthorizationPolicy> 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<AuthorizationPolicy> GetRequiredPolicyAsync() =>
Task.FromResult<AuthorizationPolicy>(null);
```
## Use a custom IAuthorizationPolicyProvider