Compartilhar cookies de autenticação entre aplicativos ASP.NET

De Rick Anderson

Os sites geralmente consistem em aplicativos Web individuais trabalhando juntos. Para oferecer uma experiência de SSO (logon único), os aplicativos Web em um site devem compartilhar cookies de autenticação. Para dar suporte a esse cenário, a pilha de proteção de dados permite o compartilhamento de autenticação de cookie do Katana e tíquetes de autenticação de cookie do ASP.NET Core.

Nos exemplos a seguir:

  • O nome do cookie de autenticação é definido como um valor comum de .AspNet.SharedCookie.
  • O AuthenticationType é definido como Identity.Application explicitamente ou por padrão.
  • Um nome de aplicativo comum, SharedCookieApp, é usado para habilitar o sistema de proteção de dados para compartilhar chaves de proteção de dados.
  • Identity.Application é usado como o esquema de autenticação. Seja qual for o esquema usado, ele deve ser usado consistentemente dentro e entre os aplicativos de cookie compartilhados como o esquema padrão ou definindo-o explicitamente. O esquema é usado ao criptografar e descriptografar cookies, portanto, um esquema consistente deve ser usado entre os aplicativos.
  • Um local de armazenamento de chave de proteção de dados comum é usado.
  • DataProtectionProvider requer o pacote NuGet Microsoft.AspNetCore.DataProtection.Extensions:
  • SetApplicationName define o nome do aplicativo comum.

Compartilhar cookies de autenticação com o Identity do ASP.NET Core

Ao usar o Identity do ASP.NET Core:

  • As chaves de proteção de dados e o nome do aplicativo devem ser compartilhados entre aplicativos. Um local de armazenamento de chaves comum é fornecido ao método PersistKeysToFileSystem nos exemplos a seguir. Use SetApplicationName para configurar um nome de aplicativo compartilhado comum (SharedCookieApp nos exemplos a seguir). Para obter mais informações, confira Configurar a Proteção de Dados do ASP.NET Core.
  • Use o método de extensão ConfigureApplicationCookie para configurar o serviço de proteção de dados para cookies.
  • O tipo de autenticação padrão é Identity.Application.

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

Observação: As instruções anteriores não funcionam com ITicketStore (CookieAuthenticationOptions.SessionStore). Saiba mais neste tópico do GitHub.

Por razões de segurança, os cookies de autenticação não são compactados no ASP.NET Core. Ao usar cookies de autenticação, os desenvolvedores devem minimizar o número de informações de declaração incluídas apenas para o necessário para suas necessidades.

Compartilhar s de autenticação sem o Identity do ASP.NET Core

Ao usar cookies diretamente sem o Identity do ASP.NET Core, configure a proteção e a autenticação dos dados. No exemplo a seguir, o tipo de autenticação é definido como 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();

Por razões de segurança, os cookies de autenticação não são compactados no ASP.NET Core. Ao usar cookies de autenticação, os desenvolvedores devem minimizar o número de informações de declaração incluídas apenas para o necessário para suas necessidades.

Compartilhar cookies em caminhos base diferentes

Um cookie de autenticação usa o HttpRequest.PathBase como seu padrão Cookie.Path. Se o cookie do aplicativo precisar ser compartilhado entre caminhos base diferentes, Path deverá ser substituído:

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

Compartilhar cookies em subdomínios

Ao hospedar aplicativos que compartilham cookies em subdomínios, especifique um domínio comum na propriedade Cookie.Domain. Para compartilhar em aplicativos em contoso.com, como first_subdomain.contoso.com e second_subdomain.contoso.com, especifique o Cookie.Domain como .contoso.com:

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

Criptografar chaves de proteção de dados em rest

Para implantações de produção, configure o DataProtectionProvider para criptografar chaves em rest com DPAPI ou um X509Certificate. Para obter mais informações, confira Criptografia de chave em rest no Windows e no Azure usando o ASP.NET Core. No exemplo a seguir, uma impressão digital de certificado é fornecida para ProtectKeysWithCertificate:

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

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

Usar um banco de dados de usuário comum

Quando os aplicativos usam o mesmo esquema Identity (mesma versão do Identity), confirme se o sistema Identity para cada aplicativo é apontado para o mesmo banco de dados de usuário. Caso contrário, o sistema de identity produz falhas no runtime ao tentar corresponder as informações no cookie de autenticação com as informações no banco de dados.

Quando o esquema do Identity é diferente entre os aplicativos, geralmente porque os aplicativos estão usando versões diferentes do Identity, não é possível compartilhar um banco de dados comum com base na versão mais recente do Identity sem remapear e adicionar colunas nos esquemas do Identity de outros aplicativos. Geralmente, é mais eficiente atualizar os outros aplicativos para usar a versão mais recente do Identity para que um banco de dados comum possa ser compartilhado pelos aplicativos.

Alteração do nome do aplicativo

No .NET 6, WebApplicationBuilder normaliza o caminho raiz do conteúdo para terminar com um DirectorySeparatorChar. A maioria dos aplicativos que migram de HostBuilder ou de WebHostBuilder não compartilham o mesmo nome de aplicativo porque não estão normalizados. Para obter mais informações, consulte SetApplicationName

Compartilhar cookies de autenticações entre aplicativos ASP.NET 4.x e ASP.NET Core

Os aplicativos ASP.NET 4.x que usam o Middleware de Autenticação de Cookie do Microsoft.Owin podem ser configurados para gerar cookies de autenticação compatíveis com o Middleware de Autenticação de Cookie do ASP.NET Core. Isso pode ser útil se um aplicativo Web consistir em aplicativos ASP.NET 4.x e aplicativos ASP.NET Core que devem compartilhar uma experiência de logon único. Um exemplo específico desse cenário é migrar incrementalmente um aplicativo Web do ASP.NET para o ASP.NET Core. Nesses cenários, é comum que algumas partes de um aplicativo sejam atendidas pelo aplicativo ASP.NET original, enquanto outras são atendidas pelo novo aplicativo ASP.NET Core. No entanto, os usuários só devem entrar uma vez. Isso pode ser feito por um dos métodos a seguir:

  • Usar o recurso de autenticação remota dos adaptadores System.Web, que usa o aplicativo ASP.NET para conectar usuários.
  • Configurar o aplicativo ASP.NET para usar o Middleware de Autenticação de Cookie do Microsoft.Owin para que os cookies de autenticação sejam compartilhados com o aplicativo ASP.NET Core.

Para configurar o Middleware de Autenticação de Cookie do Microsoft.Owin para compartilhar cookies com um aplicativo ASP.NET Core, siga as instruções anteriores para configurar o aplicativo ASP.NET Core para usar um nome de cookie específico, um nome de aplicativo e manter chaves de proteção de dados em um local bem conhecido. Confira Configurar a Proteção de Dados do ASP.NET Core para obter mais informações sobre a persistência de chaves de proteção de dados.

No aplicativo ASP.NET, instale o pacote Microsoft.Owin.Security.Interop.

Atualize a chamada UseCookieAuthentication em Startup.Auth.cs para configurar um AspNetTicketDataFormat para corresponder às configurações do aplicativo ASP.NET Core:

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

Os itens importantes configurados aqui incluem:

  • O nome de cookie é definido como o mesmo nome que no aplicativo ASP.NET Core.
  • Um provedor de proteção de dados é criado usando o mesmo caminho do anel de chave. Observe que, nesses exemplos, as chaves de proteção de dados são armazenadas em disco, mas outros provedores de proteção de dados podem ser usados. Por exemplo, o Redis ou o Armazenamento de Blobs do Azure podem ser usados para provedores de proteção de dados, desde que a configuração corresponda entre os aplicativos. Confira Configurar a Proteção de Dados do ASP.NET Core para obter mais informações sobre a persistência de chaves de proteção de dados.
  • O nome do aplicativo é definido como o mesmo que o nome do aplicativo usado no aplicativo ASP.NET Core.
  • O tipo de autenticação é definido como o nome do esquema de autenticação no aplicativo ASP.NET Core.
  • System.Web.Helpers.AntiForgeryConfig.UniqueClaimTypeIdentifier é definido como uma declaração da identity do ASP.NET Core que será exclusiva a um usuário.

Como o tipo de autenticação foi alterado para corresponder ao esquema de autenticação do aplicativo ASP.NET Core, também é necessário atualizar a forma como o aplicativo ASP.NET gera novas identidades para usar esse mesmo nome. Normalmente, isso é feito em 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;
    }
}

Com essas alterações, os aplicativos ASP.NET e ASP.NET Core podem usar os mesmos cookies de autenticação para que os usuários que entram ou saem de um aplicativo sejam refletidos no outro aplicativo.

Observe que, como há diferenças entre os esquemas de banco de dados do Identity do ASP.NET e do Identity do ASP.NET Core, é recomendável que os usuários entrem usando apenas um dos aplicativos: o aplicativo ASP.NET ou o ASP.NET Core. Depois que os usuários estiverem conectados, as etapas documentadas nesta seção permitirão que o cookie autenticação seja usado por ambos os aplicativos e os dois poderão fazer logoff dos usuários.

Recursos adicionais

Nos exemplos a seguir:

  • O nome do cookie de autenticação é definido como um valor comum de .AspNet.SharedCookie.
  • O AuthenticationType é definido como Identity.Application explicitamente ou por padrão.
  • Um nome de aplicativo comum é usado para habilitar o sistema de proteção de dados para compartilhar chaves de proteção de dados (SharedCookieApp).
  • Identity.Application é usado como o esquema de autenticação. Seja qual for o esquema usado, ele deve ser usado consistentemente dentro e entre os aplicativos de cookie compartilhados como o esquema padrão ou definindo-o explicitamente. O esquema é usado ao criptografar e descriptografar cookies, portanto, um esquema consistente deve ser usado entre os aplicativos.
  • Um local de armazenamento de chave de proteção de dados comum é usado.
  • DataProtectionProvider requer o pacote NuGet Microsoft.AspNetCore.DataProtection.Extensions:
  • SetApplicationName define o nome do aplicativo comum.

Compartilhar cookies de autenticação com o Identity do ASP.NET Core

Ao usar o Identity do ASP.NET Core:

  • As chaves de proteção de dados e o nome do aplicativo devem ser compartilhados entre aplicativos. Um local de armazenamento de chaves comum é fornecido ao método PersistKeysToFileSystem nos exemplos a seguir. Use SetApplicationName para configurar um nome de aplicativo compartilhado comum (SharedCookieApp nos exemplos a seguir). Para obter mais informações, confira Configurar a Proteção de Dados do ASP.NET Core.
  • Use o método de extensão ConfigureApplicationCookie para configurar o serviço de proteção de dados para cookies.
  • O tipo de autenticação padrão é Identity.Application.

Em Startup.ConfigureServices:

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

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

Observação: As instruções anteriores não funcionam com ITicketStore (CookieAuthenticationOptions.SessionStore). Saiba mais neste tópico do GitHub.

Por razões de segurança, os cookies de autenticação não são compactados no ASP.NET Core. Ao usar cookies de autenticação, os desenvolvedores devem minimizar o número de informações de declaração incluídas apenas para o necessário para suas necessidades.

Compartilhar s de autenticação sem o Identity do ASP.NET Core

Ao usar cookies diretamente sem o Identity do ASP.NET Core, configure a proteção e a autenticação de dados em Startup.ConfigureServices. No exemplo a seguir, o tipo de autenticação é definido como 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";
    });

Por razões de segurança, os cookies de autenticação não são compactados no ASP.NET Core. Ao usar cookies de autenticação, os desenvolvedores devem minimizar o número de informações de declaração incluídas apenas para o necessário para suas necessidades.

Compartilhar cookies em caminhos base diferentes

Um cookie de autenticação usa o HttpRequest.PathBase como seu padrão Cookie.Path. Se o cookie do aplicativo precisar ser compartilhado entre caminhos base diferentes, Path deverá ser substituído:

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

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

Compartilhar cookies em subdomínios

Ao hospedar aplicativos que compartilham cookies em subdomínios, especifique um domínio comum na propriedade Cookie.Domain. Para compartilhar em aplicativos em contoso.com, como first_subdomain.contoso.com e second_subdomain.contoso.com, especifique o Cookie.Domain como .contoso.com:

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

Criptografar chaves de proteção de dados em rest

Para implantações de produção, configure o DataProtectionProvider para criptografar chaves em rest com DPAPI ou um X509Certificate. Para obter mais informações, confira Criptografia de chave em rest no Windows e no Azure usando o ASP.NET Core. No exemplo a seguir, uma impressão digital de certificado é fornecida para ProtectKeysWithCertificate:

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

Compartilhar cookies de autenticações entre aplicativos ASP.NET 4.x e ASP.NET Core

Os aplicativos ASP.NET 4.x que usam o Middleware de Autenticação de Cookie do Katana podem ser configurados para gerar cookies de autenticação compatíveis com o Middleware de Autenticação de Cookie do ASP.NET Core. Para mais informações, confira Compartilhar cookies de autenticação entre aplicativos ASP.NET 4.x e ASP.NET Core (dotnet/AspNetCore.Docs #21987).

Usar um banco de dados de usuário comum

Quando os aplicativos usam o mesmo esquema Identity (mesma versão do Identity), confirme se o sistema Identity para cada aplicativo é apontado para o mesmo banco de dados de usuário. Caso contrário, o sistema de identity produz falhas no runtime ao tentar corresponder as informações no cookie de autenticação com as informações no banco de dados.

Quando o esquema do Identity é diferente entre os aplicativos, geralmente porque os aplicativos estão usando versões diferentes do Identity, não é possível compartilhar um banco de dados comum com base na versão mais recente do Identity sem remapear e adicionar colunas nos esquemas do Identity de outros aplicativos. Geralmente, é mais eficiente atualizar os outros aplicativos para usar a versão mais recente do Identity para que um banco de dados comum possa ser compartilhado pelos aplicativos.

Recursos adicionais