Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Este guia mostra-lhe como usar os pacotes de cache de token e certificados Microsoft.Identity.Web com MSAL.NET no .NET Framework, .NET Standard 2.0 e aplicações clássicas .NET (.NET 4.7.2+).
Compreenda a visão geral
Começando com Microsoft.Identity.Web 1.17+, pode utilizar os pacotes de utilitários Microsoft.Identity.Web com MSAL.NET em ambientes que não são ASP.NET Core.
Identificar os benefícios do pacote
| Feature | Benefit |
|---|---|
| Serialização da Cache de Token | Adaptadores de cache reutilizáveis para in-memory, SQL Server, Redis, Cosmos DB, PostgreSQL |
| Ajudantes de Certificados | Carregamento simplificado de certificados a partir do KeyVault, sistema de ficheiros ou lojas de certificados |
| Prorrogações de Reivindicações | Métodos utilitários para manipulação de ClaimsPrincipal |
| .NET Padrão 2.0 | Compatível com .NET Framework 4.7.2+, .NET Core e .NET 5+ |
| Dependências Mínimas | Pacotes direcionados sem dependências do ASP.NET Core |
Analisar cenários suportados
Os seguintes cenários são suportados pelos pacotes utilitários específicos.
- .NET Framework Console Applications (cenários de processos em segundo plano)
- Aplicações de Ambiente de Trabalho (.NET Framework)
- Serviços ao Trabalhador (Quadro .NET)
- .NET Bibliotecas Standard 2.0 (compatibilidade multiplataforma)
- Aplicações não-web MSAL.NET
Observação
Para aplicações ASP.NET MVC/Web API, veja OWIN Integration em vez disso.
Pacotes selecionados
Escolhe o pacote que se adequa ao teu cenário.
Identificar pacotes principais para MSAL.NET
| Package | Purpose | Dependências | .NET Target |
|---|---|---|---|
| Microsoft. Identity.Web.TokenCache | Serializadores de cache de tokens e ClaimsPrincipal extensões |
Mínimo | .NET Padrão 2.0 |
| Microsoft. Identity.Web.Certificate | Utilitários de carregamento de certificados | Mínimo | .NET Padrão 2.0 |
Instalar pacotes
Use um dos seguintes métodos para adicionar os pacotes ao seu projeto.
Consola do Gestor de Pacotes:
# 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
Compreender as limitações do core package
O pacote core Microsoft.Identity.Web inclui dependências do ASP.NET Core (Microsoft.AspNetCore.*), que:
- São incompatíveis com o ASP.NET Framework
- Aumentar o tamanho da encomenda desnecessariamente
- Criar conflitos de dependência
Utilize pacotes direcionados para cenários do .NET Framework e .NET Standard.
Configurar serialização da cache de token
Compreender adaptadores de cache de token
Microsoft. O Identity.Web fornece adaptadores de cache de token que funcionam perfeitamente com o IConfidentialClientApplication da MSAL.NET.
Construir um cliente confidencial com cache de tokens
O exemplo seguinte cria uma aplicação cliente confidencial e anexa uma cache de token em 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 tokens
Selecione o fornecedor de cache que melhor se adapte ao seu cenário de implantação.
Configurar cache de tokens em memória
O exemplo seguinte adiciona uma cache simples em memória:
using Microsoft.Identity.Web.TokenCacheProviders;
_app.AddInMemoryTokenCache();
Cache em memória 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
});
});
Caraterísticas:
- Acesso rápido
- Sem dependências externas
- Não partilhado entre processos
- Perdi no reinício da aplicação
Caso de uso: Aplicações de consola de instância única, aplicações de ambiente de trabalho
Configurar cache de tokens distribuídos em memória
Use o seguinte código para adicionar uma cache distribuída em memória para ambientes de múltiplas instâncias:
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.Memory (NuGet)
services.AddDistributedMemoryCache();
});
Caraterísticas:
- Partilhado entre instâncias de aplicação
- Melhor para cenários de balanceamento de carga
- Requer pacote NuGet adicional
- Ainda estou perdido no reinício da aplicação
Caso de uso: Serviços multi-instância com reaquisição aceitável de tokens
Configurar Cache de Tokens do SQL Server
Use o seguinte código para adicionar uma cache SQL Server distribuída e persistente:
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]);
Caraterísticas:
- Persistente em reinicializações
- Partilhado entre múltiplas instâncias
- Fiável e escalável
- Requer configuração do SQL Server
Caso de uso: Serviços de demónios de produção, tarefas agendadas, trabalhadores multi-instância
Configurar cache de tokens Redis
Use o seguinte código para adicionar uma cache distribuída 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 seguinte mostra uma configuração 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
};
});
Caraterísticas:
- Extremamente rápido
- Partilhado entre instâncias
- Persistente (com persistência Redis ativada)
- Requer servidor Redis
Caso de uso: Aplicações de daemons de alto volume, sistemas distribuídos, microserviços
Configurar cache de tokens da Cosmos DB
Use o seguinte código para adicionar uma cache Cosmos DB distribuída 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;
});
});
Caraterísticas:
- Distribuído globalmente
- Altamente disponível
- Dimensionamento automático
- Latência superior à Redis
- Custo mais elevado
Caso de uso: Serviços globais de demónios, aplicações geo-distribuídas
Configurar cache de tokens PostgreSQL
Use o seguinte código para adicionar uma cache PostgreSQL distribuída:
_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);
});
});
Caraterísticas:
- Persistente em reinicializações
- Partilhado entre múltiplas instâncias
- Semântica SQL familiar
- Trabalha com o Base de Dados do Azure para PostgreSQL
- Requer um servidor PostgreSQL
Caso de Uso: Aplicações que já utilizam PostgreSQL como base de dados principal, ou serviços Azure alojados que utilizam Base de Dados do Azure para PostgreSQL
Construir uma aplicação completa de daemons
O exemplo seguinte mostra uma aplicação daemon completa que adquire tokens usando credenciais do cliente e uma cache de tokens do 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
}
}
}
Gerir certificados
Compreender carregamento de certificados
Microsoft. O Identity.Web simplifica o carregamento de certificados a partir de várias fontes para os fluxos de credenciais dos clientes.
Carregar certificados com o DefaultCertificateLoader
O exemplo seguinte demonstra como carregar um certificado do Azure Key Vault e criar uma aplicação 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;
}
}
Escolha fontes de certificados
Carregar a partir do Azure Key Vault
Carregue um certificado armazenado no 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 gerida ou Principal de Serviço com acesso ao Key Vault
- Pacote NuGet
Azure.Identity - Permissão de Key Vault:
Getnos certificados
Carregar a partir do armazenamento de certificados
Carregue um certificado a partir da loja de certificados do Windows por nome distinto.
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();
Também pode encontrar um certificado por impressão digital:
var certDescription = CertificateDescription.FromStoreWithThumbprint(
thumbprint: "ABCDEF1234567890ABCDEF1234567890ABCDEF12",
storeName: StoreName.My,
storeLocation: StoreLocation.LocalMachine
);
Carregar a partir do sistema de ficheiros
Carregar um certificado a partir de um ficheiro PFX no sistema de ficheiros 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();
Nota de segurança: Nunca codifiquem palavras-passe de forma fixa. Use uma configuração segura.
Carga a partir da cadeia codificada em Base64
Carregue um certificado a partir de uma cadeia codificada em Base64 armazenada em 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 o carregamento de certificados a partir de App.config
Defina as definições de certificados no seu ficheiro App.config e carregue-as em tempo de execução.
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")
};
}
Explore aplicações de exemplo
Reveja estes exemplos para ver implementações a funcionar.
Rever exemplos oficiais da Microsoft
A tabela seguinte lista exemplos oficiais que demonstram cache de tokens e carregamento de certificados.
| Exemplo | Plataforma | Descrição |
|---|---|---|
| ConfidentialClientTokenCache | Consola (.NET Framework) | Padrões de serialização da cache de tokens |
| active-directory-dotnetcore-daemon-v2 | Consola (.NET Core) | Carregamento de certificados a partir do Key Vault |
Siga as melhores práticas
Aplique estes padrões para construir aplicações fiáveis e seguras.
Siga os padrões recomendados
1. Usar o padrão singleton para IConfidentialClientApplication:
Crie uma única instância e reutilize-a em toda a sua aplicação.
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 adequada do cache de tokens:
Configure a expiração deslizante acima da vida útil do token para evitar reaquisições desnecessárias.
// Access tokens typically expire after 1 hour
// Set cache expiration ABOVE token lifetime
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
3. Utilizar armazenamento seguro de certificados:
Armazene certificados no Azure Key Vault ou numa loja de certificados devidamente segura.
// 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 adequado dos erros:
Capture exceções MSAL e registe o ID de correlação para resoluçã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. Utilizar uma cache distribuída para produção:
A cache distribuída partilha tokens entre instâncias e persiste ao longo de reinícios.
// Correct for daemon services
app.AddDistributedTokenCaches(services =>
{
services.AddDistributedSqlServerCache(/* ... */);
});
Evite 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 programes segredos de forma rígida:
// Wrong
.WithClientSecret("supersecretvalue123")
// Correct
.WithClientSecret(ConfigurationManager.AppSettings["AzureAd:ClientSecret"])
3. Não use cache em memória para serviços multi-instância:
// Wrong for services with multiple instances
app.AddInMemoryTokenCache();
// Correct - use distributed cache
app.AddDistributedTokenCaches(services =>
{
services.AddDistributedSqlServerCache(/* ... */);
});
4. Não ignore a validação de certificados:
// Wrong - skips validation
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, errors) => true;
// Correct - validate certificates properly
Migrar a partir do ADAL.NET
Revê as principais diferenças e atualiza o teu código para usar MSAL.NET com a Microsoft. Identidade.Web.
Compreender as principais diferenças
| Aspeto | ADAL.NET (descontinuado) | MSAL.NET + Microsoft. Identity.Web |
|---|---|---|
| Escopos | Baseado em recursos (https://graph.microsoft.com) |
Baseado em âmbito (https://graph.microsoft.com/.default) |
| Cache de Tokens | Serialização manual necessária | Adaptadores incorporados através de métodos de extensão |
| Certificates | Carregamento manual de X509Certificate2 |
DefaultCertificateLoader com múltiplas fontes |
| Autoridade | Fixo na construção | Pode ser anulado por pedido |
Compare 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 conteúdo relacionado
Utilize estes recursos para aprender mais sobre cenários relacionados.