次の方法で共有


ASP.NET Core の要求のマッピング、カスタマイズ、変換

作成者: Damien Bowden

クレームは、信頼できる ID プロバイダーまたは ASP.NET Core ID を使用して発行できる任意のユーザーまたは ID データから作成できます。 クレームは、サブジェクトが何であるかを表す名前と値のペアであり、サブジェクトで何が実行できるかではありません。 この記事では、次の領域について説明します。

  • OpenID Connect クライアントを使用して要求を構成し、マッピングする方法
  • 名前とロールの要求を設定する
  • 要求の名前空間をリセットする
  • TransformAsync を使用して要求をカスタマイズし、拡張する

OpenID Connect 認証を使用した要求マッピング

プロファイル要求は id_token で返すことができます。これは認証に成功すると返されます。 ASP.NET Core クライアント アプリでは、プロファイル スコープのみ必要となります。 要求に id_token を使用するとき、追加の要求マッピングは必要ありません。

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();

上記のコードでは、Microsoft.AspNetCore.Authentication.OpenIdConnect NuGet パッケージが必要です。

ユーザー要求を取得するもう 1 つの方法は、OpenID Connect ユーザー情報 API を使用する方法です。 ASP.NET Core クライアント アプリでは GetClaimsFromUserInfoEndpoint プロパティを使用してこれを構成します。 最初の設定との重要な違いの 1 つは、MapUniqueJsonKey メソッドを使って必要な要求を指定する必要があるということです。そうしない場合、クライアント アプリでは標準要求の namegiven_nameemail のみを使用できます。 id_token に含まれる要求は既定でマッピングされます。 これは最初のオプションとの大きな違いです。 必要な要求の一部を明示的に定義する必要があります。

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.

Note

ID プロバイダーの検出ドキュメントで PAR のサポートがアドバタイズされている場合、既定の Open ID Connect ハンドラーはプッシュ承認要求 (PAR) を使用します。 ID プロバイダーの検出ドキュメントは、通常、.well-known/openid-configurationにあります。 ID プロバイダーのクライアント構成で PAR を使用できない場合は、PushedAuthorizationBehavior オプションを使用して PAR を無効にすることができます。

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;
    });

PAR が使用されている場合にのみ認証が成功するようにするには、代わりに PushedAuthorizationBehavior.Require を使用します。 この変更により、OpenIdConnectEvents に対する新しい OnPushAuthorization イベントも導入されます。これにより、プッシュされた承認要求をカスタマイズしたり、手動で処理したりできます。 詳細については、API 提案 をご覧ください。

名前要求とロール要求のマッピング

Name 要求と Role 要求は ASP.NET Core HTTP コンテキストで既定のプロパティにマッピングされます。 場合によっては、既定のプロパティに異なる要求を使用する必要があります。それを行わない場合、名前要求とロール要求で既定値が一致しません。 要求は TokenValidationParameters プロパティを利用してマッピングできます。また、必要に応じてあらゆる要求に設定できます。 要求からの値は、HttpContext User.Identity.Name プロパティとロールで直接使用できます。

User.Identity.Name に値がないか、ロールが不足している場合、返された要求で値を確認し、NameClaimType 値と RoleClaimType 値を設定してください。 クライアント認証から返された要求は HTTP コンテキストで表示できます。

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"
       };
  });

要求名前空間、既定の名前空間

ASP.NET Core によって既定の名前空間が一部の既知の要求に追加されますが、アプリでは不要となることがあります。 必要に応じて、これらの追加された名前空間を無効にし、OpenID Connect サーバーによって作成された正確な要求を使用します。

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.

グローバルではなくスキームごとに名前空間を無効にする必要がある場合は、MapInboundClaims = false オプションを使用できます。

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.

IClaimsTransformation を使用してカスタム要求を拡張または追加する

IClaimsTransformation インターフェイスを使用し、ClaimsPrincipal クラスに要求を追加できます。 インターフェイスには 1 つのメソッド TransformAsync が必要です。 このメソッドは複数回呼び出される場合があります。 新しい要求は ClaimsPrincipal にまだ存在しない場合にのみ追加します。 新しい要求を追加する目的で ClaimsIdentity が作成されます。これは 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);
    }
}

IClaimsTransformation インターフェイスと MyClaimsTransformation クラスは、次のようにサービスとして登録できます。

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

外部 ID プロバイダーからの要求をマップする

次のドキュメントを参照してください。

ASP.NET Core で外部プロバイダーからの追加の要求とトークンを保持する

クレームは、信頼できる ID プロバイダーまたは ASP.NET Core ID を使用して発行できる任意のユーザーまたは ID データから作成できます。 クレームは、サブジェクトが何であるかを表す名前と値のペアであり、サブジェクトで何が実行できるかではありません。 この記事では、次の領域について説明します。

  • OpenID Connect クライアントを使用して要求を構成し、マッピングする方法
  • 名前とロールの要求を設定する
  • 要求の名前空間をリセットする
  • TransformAsync を使用して要求をカスタマイズし、拡張する

OpenID Connect 認証を使用した要求マッピング

プロファイル要求は id_token で返すことができます。これは認証に成功すると返されます。 ASP.NET Core クライアント アプリでは、プロファイル スコープのみ必要となります。 要求に id_token を使用するとき、追加の要求マッピングは必要ありません。

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;
   });

ユーザー要求を取得するもう 1 つの方法は、OpenID Connect ユーザー情報 API を使用する方法です。 ASP.NET Core クライアント アプリケーションでは GetClaimsFromUserInfoEndpoint プロパティを使用してこれを構成します。 最初の設定との重要な違いの 1 つは、MapUniqueJsonKey メソッドを利用し、必要な要求を指定する必要があるということです。指定しない場合、標準要求の namegiven_nameemail をクライアント アプリケーションで利用できます。 id_token に含まれる要求は既定でマッピングされます。 これは最初のオプションとの大きな違いです。 必要な要求の一部を明示的に定義する必要があります。

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");
   }); 

名前要求とロール要求のマッピング

Name 要求と Role 要求は ASP.NET Core HTTP コンテキストで既定のプロパティにマッピングされます。 場合によっては、既定のプロパティに異なる要求を使用する必要があります。それを行わない場合、名前要求とロール要求で既定値が一致しません。 要求は TokenValidationParameters プロパティを利用してマッピングできます。また、必要に応じてあらゆる要求に設定できます。 要求からの値は、HttpContext User.Identity.Name プロパティとロールで直接使用できます。

User.Identity.Name に値がないか、ロールが不足している場合、返された要求で値を確認し、NameClaimType 値と RoleClaimType 値を設定してください。 クライアント認証から返された要求は HTTP コンテキストで表示できます。

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"
       };
   });

要求名前空間、既定の名前空間

ASP.NET Core によって既定の名前空間が一部の既知の要求に追加されますが、アプリでは不要となることがあります。 必要に応じて、これらの追加された名前空間を無効にし、OpenID Connect サーバーによって作成された正確な要求を使用します。

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

IClaimsTransformation を使用してカスタム要求を拡張または追加する

IClaimsTransformation インターフェイスを使用し、ClaimsPrincipal クラスに要求を追加できます。 インターフェイスには 1 つのメソッド TransformAsync が必要です。 このメソッドは複数回呼び出される場合があります。 新しい要求は ClaimsPrincipal にまだ存在しない場合にのみ追加します。 新しい要求を追加する目的で ClaimsIdentity が作成されます。これは ClaimsPrincipal に追加できます。

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);
    }
}

IClaimsTransformation インターフェイスと MyClaimsTransformation クラスはサービスとして ConfigureServices メソッドで追加できます。

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

ASP.NET Core Identity でカスタム要求を拡張または追加する

次のドキュメントを参照してください。

IUserClaimsPrincipalFactory を使用して Identity に要求を追加する

外部 ID プロバイダーからの要求をマップする

次のドキュメントを参照してください。

ASP.NET Core で外部プロバイダーからの追加の要求とトークンを保持する