ASP.NET アプリ間で認証 cookie を共有する

作成者: Rick Anderson

多くの場合、Web サイトは連携して動作する個々の Web アプリで構成されます。 シングル サインオン (SSO) エクスペリエンスを提供するには、サイト内の Web アプリで認証 cookie を共有する必要があります。 このシナリオをサポートするために、データ保護スタックでは、Katana cookie 認証と ASP.NET Core cookie 認証チケットを共有できます。

次の例を参照してください。

  • 認証 cookie の名前は共通の値である .AspNet.SharedCookie に設定されています。
  • AuthenticationType は、明示的に、または既定で Identity.Application に設定されています。
  • データ保護システムによってデータ保護キーを共有できるように、共通のアプリ名 (SharedCookieApp) が使われています。
  • 認証スキームとして Identity.Application が使われています。 どのようなスキームを使うにしても、既定のスキームとして、または明示的に設定することにより、共有される cookie アプリの "内部と全体" で一貫して使う必要があります。 スキームは cookie の暗号化と復号化のときに使われるため、アプリ全体で一貫したスキームを使う必要があります。
  • 共通のデータ保護キーの保存場所が使われています。
    • ASP.NET Core アプリでは、PersistKeysToFileSystem を使ってキーの保存場所を設定します。
    • .NET Framework アプリでは、Cookie 認証ミドルウェアによって DataProtectionProvider の実装が使われています。 DataProtectionProvider には、認証 cookie ペイロード データの暗号化と復号化のためのデータ保護サービスが用意されています。 DataProtectionProvider インスタンスは、アプリの他の部分で使われているデータ保護システムから分離されています。 DataProtectionProvider.Create(System.IO.DirectoryInfo, Action<IDataProtectionBuilder>) では、データ保護キーの保存場所を指定する DirectoryInfo をそのまま使用します。
  • DataProtectionProvider には Microsoft.AspNetCore.DataProtection.Extensions NuGet パッケージが必要です。
  • SetApplicationName を使って共通アプリ名を設定します。

ASP.NET Core Identity を使って認証 cookie を共有する

ASP.NET Core Identity を使用する場合:

  • データ保護キーとアプリ名はアプリ間で共有する必要があります。 次の例では、共通キーの保存場所が PersistKeysToFileSystem メソッドに渡されています。 SetApplicationName を使って共通の共有アプリ名を構成します (次の例では SharedCookieApp)。 詳細については、「ASP.NET Core データ保護の構成」を参照してください。
  • ConfigureApplicationCookie 拡張メソッドを使って、cookie のデータ保護サービスを設定します。
  • 既定の認証の種類は Identity.Application です。

Program.csの場合:

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"c:\PATH TO COMMON KEY RING FOLDER"))
    .SetApplicationName("SharedCookieApp");

builder.Services.ConfigureApplicationCookie(options => {
    options.Cookie.Name = ".AspNet.SharedCookie";
});

var app = builder.Build();

注: 前の手順は、ITicketStore (CookieAuthenticationOptions.SessionStore) では機能しません。 詳細については、次を参照してください。この GitHub の問題します。

セキュリティ上の理由から、認証 cookie は ASP.NET Core では圧縮されません。 認証 cookie を使用する場合、開発者は、含まれる要求情報の数を最小限に抑える必要があります。

ASP.NET Core Identity を使わずに認証 cookie を共有する

ASP.NET Core Identity を使わずに cookie を直接使う場合は、データ保護と認証を構成します。 次の例では、認証の種類を Identity.Application に設定しています。

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"c:\PATH TO COMMON KEY RING FOLDER"))
    .SetApplicationName("SharedCookieApp");

builder.Services.AddAuthentication("Identity.Application")
    .AddCookie("Identity.Application", options =>
    {
        options.Cookie.Name = ".AspNet.SharedCookie";
    });

var app = builder.Build();

セキュリティ上の理由から、認証 cookie は ASP.NET Core では圧縮されません。 認証 cookie を使用する場合、開発者は、含まれる要求情報の数を最小限に抑える必要があります。

異なるベース パス間で cookie を共有する

認証 cookie の既定の Cookie.Path には、HttpRequest.PathBase が使われます。 アプリの cookie を異なるベース パス間で共有する必要がある場合は、Path をオーバーライドする必要があります。

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"c:\PATH TO COMMON KEY RING FOLDER"))
    .SetApplicationName("SharedCookieApp");

builder.Services.ConfigureApplicationCookie(options => {
    options.Cookie.Name = ".AspNet.SharedCookie";
    options.Cookie.Path = "/";
});

var app = builder.Build();

サブドメイン間で cookie を共有する

サブドメイン間で cookie を共有するアプリをホストする場合は、Cookie.Domain プロパティに共通のドメインを指定します。 first_subdomain.contoso.comsecond_subdomain.contoso.com などの contoso.com にあるアプリ間で cookie を共有する場合は、Cookie.Domain.contoso.com と指定します。

options.Cookie.Domain = ".contoso.com";

保存時のデータ保護キーを暗号化する

運用環境のデプロイの場合は、DPAPI または X509Certificate を使って保存時のキーを暗号化するように DataProtectionProvider を構成します。 詳細については、「Windows および Azure での ASP.NET Core を使用した保存時のキーの暗号化」を参照してください。 次の例では、証明書のサムプリントが ProtectKeysWithCertificate に渡されています。

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDataProtection()
    .ProtectKeysWithCertificate("{CERTIFICATE THUMBPRINT}");

共通のユーザー データベースを使う

複数のアプリが同じ Identity スキーマ (同じバージョンの Identity) を使う場合、各アプリの Identity システムが同じユーザー データベースを指していることを確認します。 そうでない場合、実行時に、ID システムによって認証 cookie の情報とデータベースの情報が照合されたときにエラーが生成されます。

Identity スキーマがアプリ間で異なる場合、通常はアプリに異なる Identity バージョンが使われているため、最新バージョンの Identity に基づいて共通のデータベースを共有するには、他のアプリの Identity スキーマで列を再マッピングおよび追加する必要があります。 多くの場合、他のアプリを最新の Identity バージョンにアップグレードして、複数のアプリで共通のデータベースを共有する方が効率的です。

アプリケーション名の変更

.NET 6 では、WebApplicationBuilder によって、コンテンツのルート パスが DirectorySeparatorChar で終わるように正規化されます。 HostBuilder または WebHostBuilder から移行するほとんどのアプリは正規化されないため、同じアプリ名を共有することはありません。 詳しくは、「SetApplicationName」をご覧ください。

ASP.NET 4.x アプリと ASP.NET Core アプリ間で認証 cookie を共有する

Microsoft.Owin Cookie Authentication Middleware を使う ASP.NET 4.x アプリは、ASP.NET Core Cookie Authentication Middleware と互換性のある認証 cookie を生成するように構成できます。 これは、Web アプリケーションが ASP.NET 4.x アプリと、シングル サインオン エクスペリエンスを共有する必要がある ASP.NET Core アプリの両方で構成されている場合に便利です。 このようなシナリオの具体的な例として、Web アプリの ASP.NET から ASP.NET Core への段階的な移行があります。 このようなシナリオでは、アプリの一部が元の ASP.NET アプリで提供されるのに対し、他の部分が新しい ASP.NET Core アプリで提供されるのが一般的です。 ただし、ユーザーは 1 回だけサインインする必要があります。 これは次の方法のいずれかを使って行うことができます。

  • System.Web アダプターのリモート認証機能を使います。ユーザーは ASP.NET アプリを使ってサインインします。
  • Microsoft.Owin Cookie 認証ミドルウェアを使って、認証 cookie が ASP.NET Core アプリと共有されるように ASP.NET アプリを構成します。

cookie を ASP.NET Core アプリと共有するように ASP.NET Microsoft.Owin Cookie 認証ミドルウェアを構成するには、前述の手順に従って、特定の cookie 名、アプリ名を使い、既知の場所にデータ保護キーを永続化するように ASP.NET Core アプリを構成します。 データ保護キーの永続化の詳細については、「ASP.NET Core データ保護の構成」を参照してください。

ASP.NET アプリで、Microsoft.Owin.Security.Interop パッケージをインストールします。

Startup.Auth.cs の UseCookieAuthentication 呼び出しを更新して、ASP.NET Core アプリの設定に一致するように AspNetTicketDataFormat を構成します。

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    LoginPath = new PathString("/Account/Login"),
    Provider = new CookieAuthenticationProvider
    { 
        OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
            validateInterval: TimeSpan.FromMinutes(30),
            regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
    },

    // Settings to configure shared cookie with ASP.NET Core app
    CookieName = ".AspNet.ApplicationCookie",
    AuthenticationType = "Identity.Application",                
    TicketDataFormat = new AspNetTicketDataFormat(
        new DataProtectorShim(
            DataProtectionProvider.Create(new DirectoryInfo(@"c:\PATH TO COMMON KEY RING FOLDER"),
            builder => builder.SetApplicationName("SharedCookieApp"))
            .CreateProtector(
                "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware",
                // Must match the Scheme name used in the ASP.NET Core app, i.e. IdentityConstants.ApplicationScheme
                "Identity.Application",
                "v2"))),
    CookieManager = new ChunkingCookieManager()
});

ここで構成される重要な項目は以下のとおりです。

  • cookie の名前は、ASP.NET Core アプリと同じ名前に設定されます。
  • データ保護プロバイダーは、同じキー リング パスを使って作成されます。 これらの例では、データ保護キーはディスクに格納されますが、他のデータ保護プロバイダーを使用できることに注意してください。 たとえば、アプリ間で構成が一致していれば、Redis や Azure Blob Storage をデータ保護プロバイダーとして使用できます。 データ保護キーの永続化の詳細については、「ASP.NET Core データ保護の構成」を参照してください。
  • アプリ名は、ASP.NET Core アプリで使うアプリ名と同じになるように設定されます。
  • 認証の種類には、ASP.NET Core アプリでの認証スキームの名前が設定されます。
  • System.Web.Helpers.AntiForgeryConfig.UniqueClaimTypeIdentifier には、ユーザーに固有の ASP.NET Core ID からの要求が設定されます。

認証の種類は ASP.NET Core アプリの認証スキームと一致するように変更されたため、ASP.NET アプリで同じ名前を使うために新しい ID を生成する方法も更新する必要があります。 これは、通常 Models/IdentityModels.cs で行われます。

public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, "Identity.Application");
        
        // Add custom user claims here
        return userIdentity;
    }
}

これらの変更により、ASP.NET と ASP.NET Core アプリは同じ認証 cookie を使用できるようになり、一方のアプリからサインインまたはサインアウトしたユーザーがもう一方のアプリに反映されるようになります。

ASP.NET Identity と ASP.NET Core Identity のデータベース スキーマには違いがあるため、ユーザーは ASP.NET または ASP.NET Core アプリのいずれか一方のみを使ってサインインすることをお勧めします。 ユーザーがサインインすると、このセクションで説明する手順により、どちらのアプリでも認証 cookie を使用できるようになり、どちらのアプリもユーザーをログアウトできるようになります。

その他の技術情報

次の例を参照してください。

  • 認証 cookie の名前は共通の値である .AspNet.SharedCookie に設定されています。
  • AuthenticationType は、明示的に、または既定で Identity.Application に設定されています。
  • データ保護システムによってデータ保護キー (SharedCookieApp) を共有できるように、共通のアプリ名が使われています。
  • 認証スキームとして Identity.Application が使われています。 どのようなスキームを使うにしても、既定のスキームとして、または明示的に設定することにより、共有される cookie アプリの "内部と全体" で一貫して使う必要があります。 スキームは cookie の暗号化と復号化のときに使われるため、アプリ全体で一貫したスキームを使う必要があります。
  • 共通のデータ保護キーの保存場所が使われています。
    • ASP.NET Core アプリでは、PersistKeysToFileSystem を使ってキーの保存場所を設定します。
    • .NET Framework アプリでは、Cookie 認証ミドルウェアによって DataProtectionProvider の実装が使われています。 DataProtectionProvider には、認証 cookie ペイロード データの暗号化と復号化のためのデータ保護サービスが用意されています。 DataProtectionProvider インスタンスは、アプリの他の部分で使われているデータ保護システムから分離されています。 DataProtectionProvider.Create(System.IO.DirectoryInfo, Action<IDataProtectionBuilder>) では、データ保護キーの保存場所を指定する DirectoryInfo をそのまま使用します。
  • DataProtectionProvider には Microsoft.AspNetCore.DataProtection.Extensions NuGet パッケージが必要です。
  • SetApplicationName を使って共通アプリ名を設定します。

ASP.NET Core Identity を使って認証 cookie を共有する

ASP.NET Core Identity を使用する場合:

  • データ保護キーとアプリ名はアプリ間で共有する必要があります。 次の例では、共通キーの保存場所が PersistKeysToFileSystem メソッドに渡されています。 SetApplicationName を使って共通の共有アプリ名を構成します (次の例では SharedCookieApp)。 詳細については、「ASP.NET Core データ保護の構成」を参照してください。
  • ConfigureApplicationCookie 拡張メソッドを使って、cookie のデータ保護サービスを設定します。
  • 既定の認証の種類は Identity.Application です。

Startup.ConfigureServicesの場合:

services.AddDataProtection()
    .PersistKeysToFileSystem("{PATH TO COMMON KEY RING FOLDER}")
    .SetApplicationName("SharedCookieApp");

services.ConfigureApplicationCookie(options => {
    options.Cookie.Name = ".AspNet.SharedCookie";
});

注: 前の手順は、ITicketStore (CookieAuthenticationOptions.SessionStore) では機能しません。 詳細については、次を参照してください。この GitHub の問題します。

セキュリティ上の理由から、認証 cookie は ASP.NET Core では圧縮されません。 認証 cookie を使用する場合、開発者は、含まれる要求情報の数を最小限に抑える必要があります。

ASP.NET Core Identity を使わずに認証 cookie を共有する

ASP.NET Core Identity を使わずに cookie を直接使う場合は、Startup.ConfigureServices でデータ保護と認証を構成します。 次の例では、認証の種類を Identity.Application に設定しています。

services.AddDataProtection()
    .PersistKeysToFileSystem("{PATH TO COMMON KEY RING FOLDER}")
    .SetApplicationName("SharedCookieApp");

services.AddAuthentication("Identity.Application")
    .AddCookie("Identity.Application", options =>
    {
        options.Cookie.Name = ".AspNet.SharedCookie";
    });

セキュリティ上の理由から、認証 cookie は ASP.NET Core では圧縮されません。 認証 cookie を使用する場合、開発者は、含まれる要求情報の数を最小限に抑える必要があります。

異なるベース パス間で cookie を共有する

認証 cookie の既定の Cookie.Path には、HttpRequest.PathBase が使われます。 アプリの cookie を異なるベース パス間で共有する必要がある場合は、Path をオーバーライドする必要があります。

services.AddDataProtection()
    .PersistKeysToFileSystem("{PATH TO COMMON KEY RING FOLDER}")
    .SetApplicationName("SharedCookieApp");

services.ConfigureApplicationCookie(options => {
    options.Cookie.Name = ".AspNet.SharedCookie";
    options.Cookie.Path = "/";
});

サブドメイン間で cookie を共有する

サブドメイン間で cookie を共有するアプリをホストする場合は、Cookie.Domain プロパティに共通のドメインを指定します。 first_subdomain.contoso.comsecond_subdomain.contoso.com などの contoso.com にあるアプリ間で cookie を共有する場合は、Cookie.Domain.contoso.com と指定します。

options.Cookie.Domain = ".contoso.com";

保存時のデータ保護キーを暗号化する

運用環境のデプロイの場合は、DPAPI または X509Certificate を使って保存時のキーを暗号化するように DataProtectionProvider を構成します。 詳細については、「Windows および Azure での ASP.NET Core を使用した保存時のキーの暗号化」を参照してください。 次の例では、証明書のサムプリントが ProtectKeysWithCertificate に渡されています。

services.AddDataProtection()
    .ProtectKeysWithCertificate("{CERTIFICATE THUMBPRINT}");

ASP.NET 4.x アプリと ASP.NET Core アプリ間で認証 cookie を共有する

Katana Cookie Authentication Middleware を使う ASP.NET 4.x アプリは、ASP.NET Core Cookie Authentication Middleware と互換性のある認証 cookie を生成するように構成できます。 詳細については、「Share authentication cookies between ASP.NET 4.x and ASP.NET Core apps (ASP.NET 4.x アプリと ASP.NET Core アプリ間で認証 Cookie を共有する)」(dotnet/AspNetCore.Docs #21987) を参照してください。

共通のユーザー データベースを使う

複数のアプリが同じ Identity スキーマ (同じバージョンの Identity) を使う場合、各アプリの Identity システムが同じユーザー データベースを指していることを確認します。 そうでない場合、実行時に、ID システムによって認証 cookie の情報とデータベースの情報が照合されたときにエラーが生成されます。

Identity スキーマがアプリ間で異なる場合、通常はアプリに異なる Identity バージョンが使われているため、最新バージョンの Identity に基づいて共通のデータベースを共有するには、他のアプリの Identity スキーマで列を再マッピングおよび追加する必要があります。 多くの場合、他のアプリを最新の Identity バージョンにアップグレードして、複数のアプリで共通のデータベースを共有する方が効率的です。

その他の技術情報