Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este guia mostra como usar os pacotes de cache de token e de certificado do Microsoft.Identity.Web com MSAL.NET no .NET Framework, .NET Standard 2.0 e aplicativos .NET clássicos (.NET 4.7.2+).
Entender a visão geral
Começando com Microsoft.Identity.Web 1.17+, você pode usar os pacotes de utilitários do Microsoft.Identity.Web com o MSAL.NET em ambientes não ASP.NET Core.
Identificar benefícios do pacote
| Característica | Benefício |
|---|---|
| Serialização do cache de token | Adaptadores de cache reutilizáveis para memória, SQL Server, Redis, Cosmos DB, PostgreSQL |
| Auxiliares de Certificado | Carregamento de certificado simplificado do KeyVault, sistema de arquivos ou repositórios de certificados |
| Extensões de Claims | Métodos utilitários para manipulação de ClaimsPrincipal |
| .NET Standard 2.0 | Compatível com .NET Framework 4.7.2+, .NET Core e .NET 5+ |
| Dependências mínimas | Pacotes de destino sem dependências de ASP.NET Core |
Revisar cenários suportados
Os seguintes cenários são suportados pelos pacotes utilitários direcionados.
- .NET Framework Console Applications (cenários daemon)
- Desktop Applications (.NET Framework)
- Worker Services (.NET Framework)
- bibliotecas .NET Standard 2.0 (compatibilidade entre plataformas)
- Aplicativos MSAL.NET não web
Observação
Para ASP.NET MVC/aplicativos de API Web, consulte OWIN Integration em vez disso.
Selecionar pacotes
Escolha o pacote que corresponde ao seu cenário.
Identificar pacotes principais para MSAL.NET
| Package | Propósito | Dependências | Destino do .NET |
|---|---|---|---|
| Microsoft. Identity.Web.TokenCache | Serializadores de cache de token, ClaimsPrincipal extensões |
Mínimo | .NET Standard 2.0 |
| Microsoft. Identity.Web.Certificate | Utilitários de carregamento de certificado | Mínimo | .NET Standard 2.0 |
Instalar pacotes
Use um dos métodos a seguir para adicionar os pacotes ao seu projeto.
Gerenciador de Pacotes Console:
# Token cache serialization
Install-Package Microsoft.Identity.Web.TokenCache
# Certificate management
Install-Package Microsoft.Identity.Web.Certificate
.NET CLI:
dotnet add package Microsoft.Identity.Web.TokenCache
dotnet add package Microsoft.Identity.Web.Certificate
Entender as limitações do pacote principal
O pacote principal Microsoft.Identity.Web inclui dependências ASP.NET Core (Microsoft.AspNetCore.*), que:
- São incompatíveis com o ASP.NET Framework
- Aumentar o tamanho do pacote desnecessariamente
- Criar conflitos de dependência
Use pacotes direcionados para cenários .NET Framework e .NET Standard.
Configurar a serialização de cache de token
Entender os adaptadores de cache de token
Microsoft.Identity.Web fornece adaptadores de cache de token que funcionam perfeitamente com o IConfidentialClientApplication em MSAL.NET.
Criar um cliente confidencial com cache de token
O exemplo a seguir cria um aplicativo cliente confidencial e anexa um cache de token na memória.
using Microsoft.Identity.Client;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders;
public class MsalAppBuilder
{
private static IConfidentialClientApplication _app;
public static IConfidentialClientApplication BuildConfidentialClientApplication()
{
if (_app == null)
{
string clientId = ConfigurationManager.AppSettings["AzureAd:ClientId"];
string clientSecret = ConfigurationManager.AppSettings["AzureAd:ClientSecret"];
string tenantId = ConfigurationManager.AppSettings["AzureAd:TenantId"];
// Create the confidential client application
_app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithTenantId(tenantId)
.WithAuthority(AzureCloudInstance.AzurePublic, tenantId)
.Build();
// Add token cache serialization (choose one option below)
_app.AddInMemoryTokenCache();
}
return _app;
}
}
Escolher opções de cache de token
Selecione o provedor de cache que melhor se ajusta ao seu cenário de implantação.
Configurar o cache de token na memória
O exemplo a seguir adiciona um cache simples na memória:
using Microsoft.Identity.Web.TokenCacheProviders;
_app.AddInMemoryTokenCache();
In-memory cache com limites de tamanho (Microsoft.Identity.Web 1.20+):
using Microsoft.Extensions.Caching.Memory;
_app.AddInMemoryTokenCache(services =>
{
// Configure memory cache options
services.Configure<MemoryCacheOptions>(options =>
{
options.SizeLimit = 5000000; // 5 MB limit
});
});
Características:
- Acesso rápido
- Nenhuma dependência externa
- Não compartilhado entre processos
- Perda na reinicialização do aplicativo
Caso de uso: Aplicativos de console com instância única, aplicativos da área de trabalho
Configurar o cache de token distribuído na memória
Use o seguinte código para adicionar um cache distribuído na memória para ambientes de várias instâncias:
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.Memory (NuGet)
services.AddDistributedMemoryCache();
});
Características:
- Compartilhado entre instâncias de aplicativo
- Melhor para cenários com balanceamento de carga
- Requer um pacote NuGet adicional
- Ainda perdido na reinicialização do aplicativo
Caso de uso: Serviços de várias instâncias com reobtenção de token aceitável
Configurar o cache de token do SQL Server
Use o seguinte código para adicionar um cache de SQL Server persistente e distribuído:
using Microsoft.Extensions.Caching.SqlServer;
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.SqlServer (NuGet)
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = ConfigurationManager.ConnectionStrings["TokenCache"].ConnectionString;
options.SchemaName = "dbo";
options.TableName = "TokenCache";
// IMPORTANT: Set expiration above token lifetime
// Access tokens typically expire after 1 hour
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
Execute o SEGUINTE SQL para criar a tabela de cache necessária:
-- Create the cache table
CREATE TABLE [dbo].[TokenCache] (
[Id] NVARCHAR(449) NOT NULL,
[Value] VARBINARY(MAX) NOT NULL,
[ExpiresAtTime] DATETIMEOFFSET NOT NULL,
[SlidingExpirationInSeconds] BIGINT NULL,
[AbsoluteExpiration] DATETIMEOFFSET NULL,
PRIMARY KEY ([Id])
);
-- Create index for performance
CREATE INDEX [Index_ExpiresAtTime] ON [dbo].[TokenCache] ([ExpiresAtTime]);
Características:
- Persistente mesmo após reinicializações
- Compartilhado em várias instâncias
- Confiável e escalonável
- Requer configurar o SQL Server
Caso de uso: Serviços de processos em segundo plano de produção, tarefas agendadas, processos de múltiplas instâncias
Configurar o cache de token Redis
Use o seguinte código para adicionar um cache distribuído Redis de alto desempenho:
using StackExchange.Redis;
using Microsoft.Extensions.Caching.StackExchangeRedis;
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.StackExchangeRedis (NuGet)
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = ConfigurationManager.AppSettings["Redis:ConnectionString"];
options.InstanceName = "TokenCache_";
});
});
O exemplo a seguir mostra uma configuração do Redis pronta para produção:
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = ConfigurationManager.AppSettings["Redis:ConnectionString"];
options.InstanceName = "MyDaemonApp_";
// Optional: Configure Redis options
options.ConfigurationOptions = new ConfigurationOptions
{
AbortOnConnectFail = false,
ConnectTimeout = 5000,
SyncTimeout = 5000
};
});
Características:
- Extremamente rápido
- Compartilhado entre instâncias
- Persistente (com a persistência do Redis habilitada)
- Requer o servidor Redis
Caso de uso: Aplicativos daemon de alto volume, sistemas distribuídos, microsserviços
Configurar o cache de token do Cosmos DB
Use o seguinte código para adicionar um cache do Cosmos DB distribuído globalmente:
using Microsoft.Extensions.Caching.Cosmos;
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.Cosmos (preview)
services.AddCosmosCache(options =>
{
options.ContainerName = "TokenCache";
options.DatabaseName = "IdentityCache";
options.ClientBuilder = new CosmosClientBuilder(
ConfigurationManager.AppSettings["CosmosConnectionString"]);
options.CreateIfNotExists = true;
});
});
Características:
- Distribuído globalmente
- Altamente disponível
- Dimensionamento automático
- Latência maior que Redis
- Custo mais alto
Caso de uso: Serviços daemon globais, aplicativos distribuídos geograficamente
Configurar o cache de token PostgreSQL
Use o seguinte código para adicionar um cache PostgreSQL distribuído:
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.Postgres (NuGet)
services.AddDistributedPostgresCache(options =>
{
options.ConnectionString = ConfigurationManager.ConnectionStrings["PostgresCache"].ConnectionString;
options.SchemaName = ConfigurationManager.AppSettings["PostgresCache:SchemaName"];
options.TableName = ConfigurationManager.AppSettings["PostgresCache:TableName"];
options.CreateIfNotExists = bool.Parse(
ConfigurationManager.AppSettings["PostgresCache:CreateIfNotExists"] ?? "true");
// Set expiration above token lifetime.
// Access tokens typically expire after 1 hour.
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
Características:
- Persistente mesmo após reinicializações
- Compartilhado em várias instâncias
- Semântica de SQL familiar
- Funciona com Banco de Dados do Azure para PostgreSQL
- Requer um servidor PostgreSQL
Use case: Aplicações já usando o PostgreSQL como banco de dados primário ou serviços hospedados na Azure usando o Banco de Dados do Azure para PostgreSQL
Criar um aplicativo daemon completo
O exemplo a seguir mostra um aplicativo daemon completo que adquire tokens usando credenciais de cliente e um cache de token SQL Server.
using Microsoft.Identity.Client;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders;
using System;
using System.Threading.Tasks;
namespace DaemonApp
{
class Program
{
private static IConfidentialClientApplication _app;
static async Task Main(string[] args)
{
// Build confidential client with token cache
_app = BuildConfidentialClient();
// Acquire token for app-only access
string[] scopes = new[] { "https://graph.microsoft.com/.default" };
try
{
var result = await _app.AcquireTokenForClient(scopes)
.ExecuteAsync();
Console.WriteLine($"Token acquired successfully!");
Console.WriteLine($"Token source: {result.AuthenticationResultMetadata.TokenSource}");
Console.WriteLine($"Expires on: {result.ExpiresOn}");
// Use token to call API
await CallProtectedApi(result.AccessToken);
}
catch (MsalServiceException ex)
{
Console.WriteLine($"Error acquiring token: {ex.ErrorCode}");
Console.WriteLine($"CorrelationId: {ex.CorrelationId}");
}
}
private static IConfidentialClientApplication BuildConfidentialClient()
{
var app = ConfidentialClientApplicationBuilder
.Create(ConfigurationManager.AppSettings["ClientId"])
.WithClientSecret(ConfigurationManager.AppSettings["ClientSecret"])
.WithTenantId(ConfigurationManager.AppSettings["TenantId"])
.Build();
// Add SQL Server token cache for persistence
app.AddDistributedTokenCaches(services =>
{
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = ConfigurationManager
.ConnectionStrings["TokenCache"].ConnectionString;
options.SchemaName = "dbo";
options.TableName = "TokenCache";
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
return app;
}
private static async Task CallProtectedApi(string accessToken)
{
// Your API call logic
}
}
}
Gerenciar certificados
Entender o carregamento de certificado
Microsoft. O Identity.Web simplifica o carregamento de certificados de várias fontes para fluxos de credenciais do cliente.
Carregar certificados com DefaultCertificateLoader
O exemplo a seguir demonstra como carregar um certificado de Azure Key Vault e criar um aplicativo cliente confidencial.
using Microsoft.Identity.Web;
using Microsoft.Identity.Client;
public class CertificateHelper
{
public static IConfidentialClientApplication CreateAppWithCertificate()
{
string clientId = ConfigurationManager.AppSettings["AzureAd:ClientId"];
string tenantId = ConfigurationManager.AppSettings["AzureAd:TenantId"];
// Define certificate source
var certDescription = CertificateDescription.FromKeyVault(
keyVaultUrl: "https://my-keyvault.vault.azure.net",
keyVaultCertificateName: "MyCertificate"
);
// Load certificate
ICertificateLoader certificateLoader = new DefaultCertificateLoader();
certificateLoader.LoadIfNeeded(certDescription);
// Create confidential client with certificate
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithCertificate(certDescription.Certificate)
.WithTenantId(tenantId)
.Build();
// Add token cache
app.AddInMemoryTokenCache();
return app;
}
}
Escolher fontes de certificado
Carregar de Azure Key Vault
Carregue um certificado armazenado em Azure Key Vault especificando a URL do cofre e o nome do certificado.
var certDescription = CertificateDescription.FromKeyVault(
keyVaultUrl: "https://my-keyvault.vault.azure.net",
keyVaultCertificateName: "MyApplicationCert"
);
ICertificateLoader loader = new DefaultCertificateLoader();
loader.LoadIfNeeded(certDescription);
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithCertificate(certDescription.Certificate)
.WithTenantId(tenantId)
.Build();
Pré-requisitos:
- Identidade Gerenciada ou Entidade de Serviço com acesso ao Key Vault
-
Azure.Identitypacote NuGet - permissão Key Vault:
Getem certificados
Carregar do repositório de certificados
Carregue um certificado do repositório de certificados Windows pelo nome diferenciado.
var certDescription = CertificateDescription.FromStoreWithDistinguishedName(
distinguishedName: "CN=MyApp.contoso.com",
storeName: StoreName.My,
storeLocation: StoreLocation.CurrentUser
);
ICertificateLoader loader = new DefaultCertificateLoader();
loader.LoadIfNeeded(certDescription);
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithCertificate(certDescription.Certificate)
.WithTenantId(tenantId)
.Build();
Você também pode encontrar um certificado por impressão digital:
var certDescription = CertificateDescription.FromStoreWithThumbprint(
thumbprint: "ABCDEF1234567890ABCDEF1234567890ABCDEF12",
storeName: StoreName.My,
storeLocation: StoreLocation.LocalMachine
);
Carregar do sistema de arquivos
Carregue um certificado de um arquivo PFX no sistema de arquivos local.
var certDescription = CertificateDescription.FromPath(
path: @"C:\Certificates\MyAppCert.pfx",
password: ConfigurationManager.AppSettings["Certificate:Password"]
);
ICertificateLoader loader = new DefaultCertificateLoader();
loader.LoadIfNeeded(certDescription);
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithCertificate(certDescription.Certificate)
.WithTenantId(tenantId)
.Build();
Observação de segurança: Nunca codifique senhas diretamente no código. Use a configuração segura.
Carregar da string codificada em Base64
Carregue um certificado de uma cadeia de caracteres codificada em Base64 armazenada na configuração.
string base64Cert = ConfigurationManager.AppSettings["Certificate:Base64"];
var certDescription = CertificateDescription.FromBase64Encoded(
base64EncodedValue: base64Cert,
password: ConfigurationManager.AppSettings["Certificate:Password"] // Optional
);
ICertificateLoader loader = new DefaultCertificateLoader();
loader.LoadIfNeeded(certDescription);
Configurar a carga de certificados a partir do App.config
Defina as configurações de certificado no arquivo App.config e carregue-as em runtime.
App.config:
<appSettings>
<add key="AzureAd:ClientId" value="your-client-id" />
<add key="AzureAd:TenantId" value="your-tenant-id" />
<!-- Option 1: KeyVault -->
<add key="Certificate:SourceType" value="KeyVault" />
<add key="Certificate:KeyVaultUrl" value="https://my-vault.vault.azure.net" />
<add key="Certificate:KeyVaultCertificateName" value="MyCert" />
<!-- Option 2: Store -->
<!--
<add key="Certificate:SourceType" value="StoreWithThumbprint" />
<add key="Certificate:CertificateThumbprint" value="ABCD..." />
<add key="Certificate:CertificateStorePath" value="CurrentUser/My" />
-->
</appSettings>
<connectionStrings>
<add name="TokenCache"
connectionString="Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=TokenCache;Integrated Security=True;" />
</connectionStrings>
Use o seguinte método auxiliar para carregar o certificado com base na configuração:
public static CertificateDescription GetCertificateFromConfig()
{
string sourceType = ConfigurationManager.AppSettings["Certificate:SourceType"];
return sourceType switch
{
"KeyVault" => CertificateDescription.FromKeyVault(
ConfigurationManager.AppSettings["Certificate:KeyVaultUrl"],
ConfigurationManager.AppSettings["Certificate:KeyVaultCertificateName"]
),
"StoreWithThumbprint" => CertificateDescription.FromStoreWithThumbprint(
ConfigurationManager.AppSettings["Certificate:CertificateThumbprint"],
StoreName.My,
StoreLocation.CurrentUser
),
_ => throw new ConfigurationErrorsException("Invalid certificate source type")
};
}
Explorar aplicativos de exemplo
Examine esses exemplos para ver implementações de trabalho.
Examinar exemplos oficiais de Microsoft
A tabela a seguir lista exemplos oficiais que demonstram o cache de token e o carregamento de certificados.
| Amostra | Plataforma | Descrição |
|---|---|---|
| ConfidentialClientTokenCache | Console (.NET Framework) | Padrões de serialização de cache de token |
| active-directory-dotnetcore-daemon-v2 | Console (.NET Core) | Carregamento de certificado de Key Vault |
Seguir as práticas recomendadas
Aplique esses padrões para criar aplicativos confiáveis e seguros.
Siga os padrões recomendados
1. Use o padrão singleton para IConfidentialClientApplication:
Crie uma única instância e reutilize-a em seu aplicativo.
private static IConfidentialClientApplication _app;
public static IConfidentialClientApplication GetApp()
{
if (_app == null)
{
_app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithTenantId(tenantId)
.Build();
_app.AddDistributedTokenCaches(/* ... */);
}
return _app;
}
2. Definir a expiração do cache de token apropriada:
Configure a expiração deslizante acima do tempo de vida do token para evitar a nova aquisição desnecessária.
// Access tokens typically expire after 1 hour
// Set cache expiration ABOVE token lifetime
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
3. Use o armazenamento seguro de certificados:
Armazene certificados em Azure Key Vault ou em um repositório de certificados protegido corretamente.
// Azure Key Vault (production)
var cert = CertificateDescription.FromKeyVault(keyVaultUrl, certName);
// Certificate store with proper permissions
var cert = CertificateDescription.FromStoreWithThumbprint(
thumbprint, StoreName.My, StoreLocation.LocalMachine);
4. Implementar o tratamento de erros adequado:
Capturar exceções MSAL e registrar o ID de correlação para solução de problemas.
try
{
var result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
}
catch (MsalServiceException ex)
{
logger.Error($"Token acquisition failed. CorrelationId: {ex.CorrelationId}, ErrorCode: {ex.ErrorCode}");
throw;
}
5. Use um cache distribuído para produção:
Um cache distribuído compartilha tokens entre instâncias e persiste entre reinicializações.
// Correct for daemon services
app.AddDistributedTokenCaches(services =>
{
services.AddDistributedSqlServerCache(/* ... */);
});
Evitar erros comuns
1. Não crie novas instâncias IConfidentialClientApplication repetidamente:
// Wrong - creates new instance every time
public void AcquireToken()
{
var app = ConfidentialClientApplicationBuilder.Create(clientId).Build();
// ...
}
// Correct - use singleton
private static readonly IConfidentialClientApplication _app = BuildApp();
2. Não codificar segredos:
// Wrong
.WithClientSecret("supersecretvalue123")
// Correct
.WithClientSecret(ConfigurationManager.AppSettings["AzureAd:ClientSecret"])
3. Não use cache na memória para serviços de várias instâncias:
// Wrong for services with multiple instances
app.AddInMemoryTokenCache();
// Correct - use distributed cache
app.AddDistributedTokenCaches(services =>
{
services.AddDistributedSqlServerCache(/* ... */);
});
4. Não ignore a validação do certificado:
// Wrong - skips validation
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, errors) => true;
// Correct - validate certificates properly
Migrar da ADAL.NET
Examine as principais diferenças e atualize seu código para usar MSAL.NET com Microsoft. Identity.Web.
Entender as principais diferenças
| Aspecto | ADAL.NET (preterida) | MSAL.NET + Microsoft. Identity.Web |
|---|---|---|
| Escopos | Baseado em recursos (https://graph.microsoft.com) |
Baseado em escopo (https://graph.microsoft.com/.default) |
| Token Cache | Serialização manual necessária | Adaptadores integrados via métodos de extensão |
| Certificados | Carregamento manual do X509Certificate2 |
DefaultCertificateLoader com várias fontes |
| Autoridade | Corrigido na construção | Pode ser substituído por solicitação |
Comparar exemplos de migração
ADAL.NET (Antigo):
AuthenticationContext authContext = new AuthenticationContext(authority);
ClientCredential credential = new ClientCredential(clientId, clientSecret);
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, credential);
MSAL.NET com Microsoft. Identity.Web (Novo):
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithTenantId(tenantId)
.Build();
app.AddInMemoryTokenCache(); // Add token cache
string[] scopes = new[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
Explorar o conteúdo relacionado
Use esses recursos para saber mais sobre cenários relacionados.