Where I thought the documentation fell short was the marrying
of the two concepts; there is little explanation given
to how the claims are actually made available to be
check and asserted on.

If we were to inspect the Identity of a User,
we would notice that it already has a substantial
Claims collection. These claims are all seemingly
associate with specific Windows user properties,
and to me have largely legible names yet indecipherable
values, save perhaps for the .../name claim:

In contrast, the Claims examples make use of such
nicely named claims like "EmployeeNumber" or ClaimTypes.DateOfBirth,
none of which can be found in the claims collection of our Windows user.

To load claim in ASP.NET Core 2.x we make use of one or more
claims tranformations, classes implementing
IClaimsTransformation
(used to be called IClaimsTransformer in earlier versions),
which get access to the ClaimsPrincipal and can
construct new ones or add claims to the loaded one.

In the following example we’ll look at adding our own claims to
the collection. To make it a bit more interesting, let’s assume
we have a table in the database that stores the ids of the users
who are administrators of our own application and we would
like to add a flag in claims if a user logging in is part of this table.

Assuming we use these in combination with Authorize attribute,
likely to check for an "IsAdmin" claim: [Authorize(Policy = "IsAdmin")],
we will be making the following changes to our application:

Packages required

If running against .NET Core 2.x, the Microsoft.AspNetCore.App meta-package is sufficient.

Startup.cs

Enable authentication by adding the following to the
Configure(IApplicationBuilder app, ...) method:

app.UseAuthentication();

Add IIS authentication scheme in ConfigureServices:

services.AddAuthentication(IISDefaults.AuthenticationScheme);

We’ll be back here in a bit to register our claims loader

ClaimsLoader.cs

Before we implement IClaimsTransformation a couple notes about it.

First, they run on each AuthenticateAsync call, which means
for IIS Authentication they run only once and whatever claims
we add to the collection are cached for as long as the user
is logged in.
If we remove a logged in user from the list of administrators,
they will continue to behave as such until they log in again.

Note: this will be run on each AuthenticateAsync call,
so its safer to return a new ClaimsPrincipal if your transformation is not idempotent.

This is because if any call (tests?) causes AuthenticateAsync
to be called twice, the same claim is added twice to the collection
as pointed out in this article by Brock Allen.

usingSystem.Security.Claims;// for ClaimsPrincipalusingMicrosoft.AspNetCore.Authentication;// for IClaimsTransformationpublicclassClaimsLoader:IClaimsTransformation{publicconststringIsAdminKey="IsAdmin";privatereadonlyUserContext_userContext;publicMigrationsUserClaimsLoader(UserContextuserContext){_userContext=userContext;}publicasyncTask<ClaimsPrincipal>TransformAsync(ClaimsPrincipalprincipal){varidentity=(ClaimsIdentity)principal.Identity;// create a new ClaimsIdentity copying the existing onevarclaimsIdentity=newClaimsIdentity(identity.Claims,identity.AuthenticationType,identity.NameClaimType,identity.RoleClaimType);// check if our user is in the admin table// identity.Name is the domain-prefixed id, eg HOME\philipif(await_userContext.IsAdminAsync(identity.Name)){claimsIdentity.AddClaim(newClaim(IsAdminKey,"So say we all"));}// create a new ClaimsPrincipal in observation// of the documentation notereturnnewClaimsPrincipal(claimsIdentity);}}

Startup.cs - adding policy

Now that we created our claims loader, let’s register it with the
service collection and add a policy for it too: