Claims toewijzen, aanpassen en transformeren in ASP.NET Core

Door Damien Bowden

Claims kunnen worden aangemaakt op basis van gebruikers- of identiteitsdata die kunnen worden verstrekt met behulp van een vertrouwde identiteitsprovider of ASP.NET Core Identity. Een claim is een naam-waardepaar dat aangeeft wat het onderwerp is, niet wat het onderwerp kan doen.

In dit artikel wordt beschreven hoe u claims configureert en toewijst met behulp van een OpenID Connect-client, en komen de volgende taken aan bod:

  • Naamclaims en rolclaims instellen
  • De claimsnaamruimten opnieuw instellen
  • De claims aanpassen en uitbreiden met de TransformAsync methode

Claims toewijzen met OpenID Connect-verificatie

De profielclaims kunnen worden teruggestuurd in de id_tokendie wordt teruggestuurd na een geslaagde authenticatie. Alleen het profielbereik is vereist voor de ASP.NET Core-clientapplicatie. Wanneer u de id_token voor claims gebruikt, is er geen extra claimtoewijzing vereist.

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       options.SignInScheme = "Cookies";
       options.Authority = "-your-identity-provider-";
       options.RequireHttpsMetadata = true;
       options.ClientId = "-your-clientid-";
       options.ClientSecret = "-your-client-secret-from-user-secrets-or-keyvault";
       options.ResponseType = "code";
       options.UsePkce = true;
       options.Scope.Add("profile");
       options.SaveTokens = true;
   });

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();

app.Run();

Voor de voorgaande code is het nuGet-pakket Microsoft.AspNetCore.Authentication.OpenIdConnect vereist.

Een andere manier om de gebruikersclaims op te halen, is door de OpenID Connect User Info-API te gebruiken. De ASP.NET Core-client-app maakt gebruik van de eigenschap GetClaimsFromUserInfoEndpoint om de configuratie uit te voeren. In dit scenario moet u expliciet de vereiste claims opgeven met behulp van de MapUniqueJsonKey methode. Anders zijn alleen de name, given_nameen email standaardclaims beschikbaar in de client-app. De claims die in de id_token zijn toegewezen, worden standaard gemapped.

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       options.SignInScheme = "Cookies";
       options.Authority = "-your-identity-provider-";
       options.RequireHttpsMetadata = true;
       options.ClientId = "-your-clientid-";
       options.ClientSecret = "-client-secret-from-user-secrets-or-keyvault";
       options.ResponseType = "code";
       options.UsePkce = true;
       options.Scope.Add("profile");
       options.SaveTokens = true;
       options.GetClaimsFromUserInfoEndpoint = true;
       options.ClaimActions.MapUniqueJsonKey("preferred_username",
                                             "preferred_username");
       options.ClaimActions.MapUniqueJsonKey("gender", "gender");
   });

var app = builder.Build();

// Code removed for brevity.

Notitie

De standaard Open ID Connect-handler maakt gebruik van Pushed Authorization Requests (PAR) als het detectiedocument van de id-provider ondersteuning voor PAR vermeldt. De gebruikelijke locatie voor het discovery-document van de identiteitsprovider is de map .well-known/openid-configuration. Als u PAR niet kunt gebruiken in de clientconfiguratie van de id-provider, kan PAR worden uitgeschakeld met behulp van de PushedAuthorizationBehavior optie.

builder.Services
    .AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddCookie()
    .AddOpenIdConnect("oidc", oidcOptions =>
    {
        // Other provider-specific configuration goes here.

        // The default value is PushedAuthorizationBehavior.UseIfAvailable.

        // 'OpenIdConnectOptions' does not contain a definition for 'PushedAuthorizationBehavior'
        // and no accessible extension method 'PushedAuthorizationBehavior' accepting a first argument
        // of type 'OpenIdConnectOptions' could be found
        oidcOptions.PushedAuthorizationBehavior = PushedAuthorizationBehavior.Disable;
    });

Gebruik in plaats daarvan PushedAuthorizationBehavior.Require enum om ervoor te zorgen dat de verificatie alleen slaagt als PAR wordt gebruikt. Deze wijziging introduceert ook een nieuwe OnPushAuthorization gebeurtenis OpenIdConnectEvents, die kan worden gebruikt om de push-autorisatieaanvraag aan te passen of handmatig te verwerken. Zie het API-voorstel in GitHub dotnet/aspnetcore-probleem #51686 - Support for Pushed Authorization Requests in OidcHandler voor meer informatie.

Naamclaim en rolclaimtoewijzing

De claims name en role worden gekoppeld aan standaardeigenschappen in de HTTP-context van ASP.NET Core. Soms moet u verschillende claims gebruiken voor de standaardeigenschappen, of de naamclaim en rolclaim komen niet overeen met de standaardwaarden. De claims kunnen met behulp van de eigenschap TokenValidationParameters worden toegewezen en naar wens aan elke claim worden gekoppeld. De waarden van de claims kunnen rechtstreeks worden gebruikt in de eigenschap HttpContext User.Identity.Name en de rollen.

Als de User.Identity.Name eigenschap geen waarde heeft of als de rollen ontbreken, controleert u de waarden in de geretourneerde claims en stelt u de NameClaimType en de RoleClaimType waarden in. De geretourneerde claims van de clientverificatie kunnen worden weergegeven in de HTTP-context.

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
  .AddCookie()
  .AddOpenIdConnect(options =>
  {
       // Other options...
       options.TokenValidationParameters = new TokenValidationParameters
       {
          NameClaimType = "email"
          //, RoleClaimType = "role"
       };
  });

Naamruimten voor claims, standaard naamruimten

ASP.NET Core voegt standaardnaamruimten toe aan enkele bekende claims. De standaardclaims zijn mogelijk niet vereist in de app. Als optie kunt u de toegevoegde naamruimten uitschakelen en de exacte claims gebruiken die de OpenID Connect-server heeft gemaakt.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

JsonWebTokenHandler.DefaultInboundClaimTypeMap.Clear();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       options.SignInScheme = "Cookies";
       options.Authority = "-your-identity-provider-";
       options.RequireHttpsMetadata = true;
       options.ClientId = "-your-clientid-";
       options.ClientSecret = "-your-client-secret-from-user-secrets-or-keyvault";
       options.ResponseType = "code";
       options.UsePkce = true;
       options.Scope.Add("profile");
       options.SaveTokens = true;
   });

var app = builder.Build();

// Code removed for brevity.
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       options.SignInScheme = "Cookies";
       options.Authority = "-your-identity-provider-";
       options.RequireHttpsMetadata = true;
       options.ClientId = "-your-clientid-";
       options.ClientSecret = "-your-client-secret-from-user-secrets-or-keyvault";
       options.ResponseType = "code";
       options.UsePkce = true;
       options.Scope.Add("profile");
       options.SaveTokens = true;
   });

var app = builder.Build();

// Code removed for brevity.

Als u de naamruimten per schema en niet globaal wilt uitschakelen, kunt u de MapInboundClaims = false optie gebruiken.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       options.SignInScheme = "Cookies";
       options.Authority = "-your-identity-provider-";
       options.RequireHttpsMetadata = true;
       options.ClientId = "-your-clientid-";
       options.ClientSecret = "-your-client-secret-from-user-secrets-or-keyvault";
       options.ResponseType = "code";
       options.UsePkce = true;
       options.MapInboundClaims = false;
       options.Scope.Add("profile");
       options.SaveTokens = true;
   });

var app = builder.Build();

// Code removed for brevity.

Aangepaste claims uitbreiden of toevoegen met behulp van 'IClaimsTransformation'

De IClaimsTransformation-interface kan worden gebruikt om extra claims toe te voegen aan de ClaimsPrincipal-klasse. Voor de interface is één methode vereist. TransformAsync Deze methode kan meerdere keren worden aangeroepen. Voeg alleen een nieuwe claim toe als deze nog niet bestaat in de ClaimsPrincipal. Er wordt een ClaimsIdentity object gemaakt om de nieuwe claims toe te voegen en het kan worden toegevoegd aan de ClaimsPrincipal.

using Microsoft.AspNetCore.Authentication;
using System.Security.Claims;

public class MyClaimsTransformation : IClaimsTransformation
{
    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        ClaimsIdentity claimsIdentity = new ClaimsIdentity();
        var claimType = "myNewClaim";
        if (!principal.HasClaim(claim => claim.Type == claimType))
        {
            claimsIdentity.AddClaim(new Claim(claimType, "myClaimValue"));
        }

        principal.AddIdentity(claimsIdentity);
        return Task.FromResult(principal);
    }
}

De IClaimsTransformation-interface en de MyClaimsTransformation-klasse kunnen als een service worden geregistreerd:

builder.Services.AddTransient<IClaimsTransformation, MyClaimsTransformation>();

Aanspraken koppelen van externe identiteitsproviders

Als u claims van externe id-providers voor uw app wilt toewijzen, raadpleegt u Persist andere claims en tokens van externe providers in ASP.NET Core.

Claims kunnen worden gemaakt op basis van gebruikers- of identiteitsgegevens die kunnen worden uitgegeven met behulp van een vertrouwde id-provider of ASP.NET Core-identiteit. Een claim is een naamwaardepaar dat aangeeft wat het onderwerp is, niet wat het onderwerp kan doen. In dit artikel worden de volgende gebieden behandeld:

  • Hoe claims te configureren en toewijzen met behulp van een OpenID Connect-client
  • Stel de naam en de rolclaim in
  • De claimsnaamruimten opnieuw instellen
  • De claims aanpassen, uitbreiden met behulp van TransformAsync

Het in kaart brengen van claims met behulp van OpenID Connect-verificatie

De profielclaims kunnen worden teruggestuurd in de id_tokendie wordt teruggestuurd na een geslaagde authenticatie. Alleen het profielbereik is vereist voor de ASP.NET Core-clientapplicatie. Wanneer u de id_token voor claims gebruikt, is er geen extra claimtoewijzing nodig.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       options.SignInScheme = "Cookies";
       options.Authority = "-your-identity-provider-";
       options.RequireHttpsMetadata = true;
       options.ClientId = "-your-clientid-";
       options.ClientSecret = "-your-client-secret-from-user-secrets-or-keyvault";
       options.ResponseType = "code";
       options.UsePkce = true;
       options.Scope.Add("profile");
       options.SaveTokens = true;
   });

Een andere manier om de gebruikersclaims op te halen, is door de OpenID Connect User Info-API te gebruiken. De ASP.NET Core-clienttoepassing maakt gebruik van de eigenschap GetClaimsFromUserInfoEndpoint om dit te configureren. Een belangrijk verschil met de eerste instellingen is dat u de claims moet opgeven die u nodig hebt met behulp van de MapUniqueJsonKey methode, anders zijn alleen de name, given_name en email standaardclaims beschikbaar in de clienttoepassing. De claims die in de id_token zijn toegewezen, worden standaard gemapped. Dit is het belangrijkste verschil met de eerste optie. U moet expliciet enkele claims definiëren die u nodig hebt.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       options.SignInScheme = "Cookies";
       options.Authority = "-your-identity-provider-";
       options.RequireHttpsMetadata = true;
       options.ClientId = "-your-clientid-";
       options.ClientSecret = "-your-client-secret-from-user-secrets-or-keyvault";
       options.ResponseType = "code";
       options.UsePkce = true;
       options.Scope.Add("profile");
       options.SaveTokens = true;
       options.GetClaimsFromUserInfoEndpoint = true;
       options.ClaimActions.MapUniqueJsonKey("preferred_username", "preferred_username");
       options.ClaimActions.MapUniqueJsonKey("gender", "gender");
   }); 

Naamclaim en rolclaimtoewijzing

De name claim en de role claim worden toegewezen aan standaardeigenschappen in de ASP.NET Core HTTP-context. Soms is het vereist om verschillende claims te gebruiken voor de standaardeigenschappen, of de naamclaim en de rolclaim komen niet overeen met de standaardwaarden. De claims kunnen worden toegewezen met behulp van de eigenschap TokenValidationParameters en zo nodig instellen op elke claim. De waarden van de claims kunnen rechtstreeks in de HttpContext UserIdentity.Name eigenschap en de rollen worden gebruikt.

Als de User.Identity.Name geen waarde heeft of de rollen ontbreken, controleert u de waarden in de geretourneerde claims en stelt u de NameClaimType en de RoleClaimType-waarden in. De geretourneerde claims van de clientverificatie kunnen worden weergegeven in de HTTP-context.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       // other options...
       options.TokenValidationParameters = new TokenValidationParameters
       {
         NameClaimType = "email", 
         // RoleClaimType = "role"
       };
   });

Naamruimten voor claims, standaard naamruimten

ASP.NET Core standaardnaamruimten toevoegt aan bepaalde bekende claims, wat mogelijk niet vereist is in de app. Schakel desgewenst deze toegevoegde naamruimten uit en gebruik de exacte claims die de OpenID Connect-server heeft gemaakt.

public void Configure(IApplicationBuilder app)
{
    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

Aangepaste claims uitbreiden of toevoegen met IClaimsTransformation

De IClaimsTransformation-interface kan worden gebruikt om extra claims toe te voegen aan de ClaimsPrincipal-klasse. Voor de interface is één methode TransformAsyncvereist. Deze methode kan meerdere keren worden aangeroepen. Voeg alleen een nieuwe claim toe als deze nog niet bestaat in de ClaimsPrincipal. Er wordt een ClaimsIdentity gemaakt om de nieuwe aanspraken toe te voegen en deze kan aan de ClaimsPrincipalworden toegevoegd.

public class MyClaimsTransformation : IClaimsTransformation
{
    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
       ClaimsIdentity claimsIdentity = new ClaimsIdentity();
       var claimType = "myNewClaim";
       if (!principal.HasClaim(claim => claim.Type == claimType))
       {		   
          claimsIdentity.AddClaim(new Claim(claimType, "myClaimValue"));
       }

       principal.AddIdentity(claimsIdentity);
       return Task.FromResult(principal);
    }
}

De IClaimsTransformation-interface en de MyClaimsTransformation-klasse kunnen als een service worden toegevoegd in de methode ConfigureServices.

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IClaimsTransformation, MyClaimsTransformation>();

Aangepaste claims uitbreiden of toevoegen in ASP.NET Core-Identity

Raadpleeg het volgende document:

Claims toevoegen aan Identity met behulp van IUserClaimsPrincipalFactory

Aanspraken koppelen van externe identiteitsproviders

Raadpleeg het volgende document:

Bewaar aanvullende claims en tokens van externe providers in ASP.NET Core