Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 10 additions & 18 deletions aspnetcore/security/authorization/iard.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ uid: security/authorization/iard

Consider the following sample that implements a custom `MinimumAgeAuthorizationHandler`:

:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/AuthRequirementsData/Program.cs" highlight="9":::
:::code language="csharp" source="~/../aspnetcore/src/Security/samples/CustomPolicyProvider/Startup.cs" highlight="23":::
Copy link
Contributor

@wadepickett wadepickett Apr 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since I'm not up yet on the intent here you may need to disregard, but I see this is moving back to before .NET 6 using Startup.cs rather than Program.cs. Maybe that is intentional, but I'll call it out just in case. @Rick-Anderson who owns the security topics can determine what is right for it, so let him weigh in first.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @wadepickett, I noticed that as well. Is there an updated code sample we can refer to? If not, it might be best to submit a PR to update the aspnetcore repo sample with the .NET 9/10 pattern first, before this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @wadepickett, I noticed that as well. Is there an updated code sample we can refer to? If not, it might be best to submit a PR to update the aspnetcore repo sample with the .NET 9/10 pattern first, before this PR.

Yes, a PR would be welcome. Before doing the PR, propose the work you intend to do in dotnet/aspnetcore#61437 and get approval.


The `MinimumAgeAuthorizationHandler` class:

:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/AuthRequirementsData/Authorization/MinimumAgeAuthorizationHandler.cs" highlight="7,19":::
:::code language="csharp" source="~/../aspnetcore/src/Security/samples/CustomPolicyProvider/Authorization/MinimumAgeAuthorizationHandler.cs" highlight="15,25":::

The custom `MinimumAgePolicyProvider`:

:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/AuthRequirementsData/Authorization/MinimumAgePolicyProvider.cs" id="snippet_all":::
:::code language="csharp" source="~/../aspnetcore/src/Security/samples/CustomPolicyProvider/Authorization/MinimumAgePolicyProvider.cs":::

ASP.NET Core only uses one authorization policy provider. If the custom implementation
doesn't handle all policies, including default policies, etc., it should fall back to an
Expand All @@ -30,23 +30,15 @@ alternate provider. In the preceding sample, a default authorization policy prov

If a custom policy provider is able to handle all expected policy names, setting the fallback policy with <xref:Microsoft.AspNetCore.Authorization.IAuthorizationPolicyProvider.GetFallbackPolicyAsync> isn't required.

:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/AuthRequirementsData/Authorization/MinimumAgePolicyProvider.cs" id="snippet_1":::
Policies are looked up by string name, therefore parameters, for example, `age`, are embedded in the policy names. This is managed by the `MinimumAgeAuthorizeAttribute`, which allows developers to specify parameters like `age` and embeds them in the policy's name. For example, the `[MinimumAgeAuthorize()]` attribute in this sample looks up policies by string name.

Policies are looked up by string name, therefore parameters, for example, `age`, are embedded in the policy names. This is abstracted away from developers by the more strongly-typed attributes derived from <xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute>. For example, the `[MinimumAgeAuthorize()]` attribute in this sample looks up policies by string name.
The `MinimumAgeAuthorizeAttribute` derives from <xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute> and adds support for specifying a minimum age. It generates a unique policy name by combining a constant prefix with the age. The MinimumAgePolicyProvider uses this name to create an authorization policy with the corresponding age requirement:

:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/AuthRequirementsData/Authorization/MinimumAgePolicyProvider.cs" id="snippet_2":::
:::code language="csharp" source="~/../aspnetcore/src/Security/samples/CustomPolicyProvider/Authorization/MinimumAgeAuthorizeAttribute.cs":::

The `MinimumAgeAuthorizeAttribute` uses the <xref:Microsoft.AspNetCore.Authorization.IAuthorizationRequirementData> interface that allows the attribute definition to specify the requirements associated with the authorization policy:
The `HomeController` enforces the minimum age requirement on each action using the MinimumAgeAuthorize attribute. The `MinimumAgeAuthorizationHandler` checks if the user's age, based on their `DateOfBirth` claim, meets the specified age before granting access.

:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/AuthRequirementsData/Authorization/MinimumAgeAuthorizeAttribute.cs" highlight="6":::
:::code language="csharp" source="~/../aspnetcore/src/Security/samples/CustomPolicyProvider/Controllers/HomeController.cs" highlight="18":::

The `GreetingsController` displays the user's name when they satisfy the minimum age policy:

:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/AuthRequirementsData/Controllers/GreetingsController.cs" highlight="10":::

The complete sample can be found in the [AuthRequirementsData](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/security/authorization/AuthRequirementsData) folder of the [AspNetCore.Docs.Samples](https://github.com/dotnet/AspNetCore.Docs.Samples) repository.

The sample can be tested with [`dotnet user-jwts`](xref:security/authentication/jwt) and curl:

* `dotnet user-jwts create --claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth=1989-01-01`
* `curl -i -H "Authorization: Bearer <token from dotnet user-jwts>" http://localhost:<port>/api/greetings/hello`
The complete sample can be found in the [CustomPolicyProvider](https://github.com/dotnet/aspnetcore/tree/main/src/Security/samples/CustomPolicyProvider) folder of the [aspnetcore](https://github.com/dotnet/aspnetcore) repository.
To test the sample, follow the instructions in the folder [readme.md](https://github.com/dotnet/aspnetcore/tree/main/src/Security/samples/CustomPolicyProvider).
Loading