在本文中,你将使用Microsoft.Identity.Web构建守护程序应用程序、后台服务和自主代理。 这些应用程序在没有用户交互的情况下运行,并使用 应用程序标识 (客户端凭据)或 代理标识进行身份验证。
了解支持的方案
Microsoft。Identity.Web 支持三种类型的非交互式应用程序:
| 情景 | 身份验证类型 | 令牌类型 | 用例 |
|---|---|---|---|
| 标准守护程序 | 客户端凭据(机密/证书) | 仅限应用的访问令牌 | 后台服务、计划作业、数据处理 |
| 自治代理 | 使用客户端凭据的代理标识 | 应用专用的代理访问令牌 | Copilot智能助手,以代理身份运作的自动化服务。 (通常位于受保护的 Web API 中) |
| 代理用户标识 | 代理用户标识 | 使用客户端凭据的代理用户标识 | 为代理用户身份执行操作的自治服务。 (通常位于受保护的 Web API 中) |
开始
先决条件
在开始之前,请确保具备:
- .NET 8.0 或更高版本
- 使用 客户端凭据(客户端机密或证书)Microsoft Entra 应用注册
- 对于代理场景:Microsoft Entra 租户中配置的代理标识
安装软件包
将所需的 NuGet 包添加到项目:
dotnet add package Microsoft.Identity.Web
dotnet add package Microsoft.Extensions.Hosting
选择配置方法
Microsoft。Identity.Web 提供了两种方法来配置守护程序应用程序:
选项 1:TokenAcquirerFactory(建议用于简单方案)
最适合: 快速原型、控制台应用、测试和简单的守护程序服务。
以下代码创建一个 TokenAcquirerFactory,配置下游 API 和Microsoft Graph,并调用图形 API:
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;
// Get the token acquirer factory instance
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
// Configure downstream API and Microsoft Graph (optional)
tokenAcquirerFactory.Services.AddDownstreamApis(
tokenAcquirerFactory.Configuration.GetSection("DownstreamApis"))
.AddMicrosoftGraph();
var serviceProvider = tokenAcquirerFactory.Build();
// Call Microsoft Graph
var graphClient = serviceProvider.GetRequiredService<GraphServiceClient>();
var users = await graphClient.Users.GetAsync();
优点:
- 最小样板代码
- 自动加载
appsettings.json - 非常适合简单场景
- 单行初始化
缺点:
- 不适合并行运行的测试(单一实例)
选项 2:全套 ServiceCollection(推荐用于生产环境)
最适合: 生产应用程序、复杂方案、依赖项注入、可测试性。
以下代码使用.NET通用主机配置身份验证、令牌获取、缓存和后台服务:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
// Configure authentication
services.Configure<MicrosoftIdentityApplicationOptions>(
context.Configuration.GetSection("AzureAd"));
// Add token acquisition (true = singleton lifetime)
services.AddTokenAcquisition(true);
// Add token cache (in-memory for development)
services.AddInMemoryTokenCaches();
// Add HTTP client for API calls
services.AddHttpClient();
// Add Microsoft Graph (optional)
services.AddMicrosoftGraph();
// Add your background service
services.AddHostedService<DaemonWorker>();
})
.Build();
await host.RunAsync();
优点:
- 完全控制配置提供程序
- 使用构造函数注入提高可测试性
- 与 ASP.NET Core托管模型集成
- 支持复杂方案(多个身份验证方案)
- 生产就绪体系结构
- 支持并行测试执行(每个测试的独立服务提供商)
注释
该参数trueAddTokenAcquisition(true)表示该服务注册为单例(应用程序整个生命周期内的单个实例)。 在 Web 应用程序中,使用 false 作为范围生存期。
建议:
TokenAcquirerFactory从原型和单线程测试开始。 在生成生产应用程序或运行并行测试时迁移到完整ServiceCollection模式。
配置标准守护程序应用程序
标准守护程序应用程序使用 客户端凭据 (客户端机密或证书)进行身份验证,并获取 仅应用访问令牌 来调用 API。
配置身份验证设置
将以下配置添加到 appsettings.json 文件。 可以使用客户端密码或证书(建议用于生产):
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-client-id",
"ClientSecret": "your-client-secret",
"ClientCredentials": [
// Option 1: Client Secret
{
"SourceType": "ClientSecret",
"ClientSecret": "your-client-secret",
},
// Option 2: Certificate (recommended for production)
{
"SourceType": "StoreWithDistinguishedName",
"CertificateStorePath": "CurrentUser/My",
"CertificateDistinguishedName": "CN=DaemonAppCert"
}
// More options: https://aka.ms/ms-id-web/client-credentials
]
}
}
重要:将appsettings.json设置为复制到输出目录。 将以下内容添加到 .csproj 文件:
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
ASP.NET Core应用程序自动复制此文件,但守护程序应用(和 OWIN 应用)不会复制。
设置服务配置
以下 Program.cs 代码注册Microsoft标识选项、令牌获取、缓存和托管后台服务:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
IConfiguration configuration = context.Configuration;
// Configure Microsoft Identity options
services.Configure<MicrosoftIdentityApplicationOptions>(
configuration.GetSection("AzureAd"));
// Add token acquisition (true = singleton)
services.AddTokenAcquisition(true);
// Add token cache
services.AddInMemoryTokenCaches(); // For development
// services.AddDistributedTokenCaches(); // For production
// Add HTTP client
services.AddHttpClient();
// Add Microsoft Graph SDK (optional)
services.AddMicrosoftGraph();
// Add your background service
services.AddHostedService<DaemonWorker>();
})
.Build();
await host.RunAsync();
调用 Microsoft Graph
以下 DaemonWorker.cs 类使用 Graph SDK 按定期计划列出用户:
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Graph;
using Microsoft.Identity.Abstractions;
public class DaemonWorker : BackgroundService
{
private readonly GraphServiceClient _graphClient;
private readonly ILogger<DaemonWorker> _logger;
public DaemonWorker(
GraphServiceClient graphClient,
ILogger<DaemonWorker> logger)
{
_graphClient = graphClient;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
// Call Microsoft Graph with app-only permissions
var users = await _graphClient.Users
.GetAsync(cancellationToken: stoppingToken);
_logger.LogInformation($"Found {users?.Value?.Count} users");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error calling Microsoft Graph");
}
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
}
}
}
使用 IAuthorizationHeaderProvider
若要更好地控制 HTTP 调用,请使用 IAuthorizationHeaderProvider 手动创建授权标头:
using Microsoft.Identity.Abstractions;
public class DaemonService
{
private readonly IAuthorizationHeaderProvider _authProvider;
private readonly HttpClient _httpClient;
public DaemonService(
IAuthorizationHeaderProvider authProvider,
IHttpClientFactory httpClientFactory)
{
_authProvider = authProvider;
_httpClient = httpClientFactory.CreateClient();
}
public async Task<string> CallApiAsync()
{
// Get authorization header for app-only access
string authHeader = await _authProvider
.CreateAuthorizationHeaderForAppAsync(
scopes: "https://graph.microsoft.com/.default");
// Add to HTTP request
_httpClient.DefaultRequestHeaders.Clear();
_httpClient.DefaultRequestHeaders.Add("Authorization", authHeader);
var response = await _httpClient.GetStringAsync(
"https://graph.microsoft.com/v1.0/users");
return response;
}
}
另请参阅 调用下游 API 以了解 Microsoft Identity Web 提供的所有调用下游 API 的方法。
配置自治代理(代理标识)
自治代理使用 代理标识 来获取仅限应用的令牌。 此模式适用于Copilot方案和自治服务。
注释
Microsoft 建议代理程序从受保护的 Web API 内部调用下游 API,即使在代理获取应用令牌的情况下也是如此。
配置代理服务
以下代码使用内存中配置设置身份验证、令牌获取和代理标识支持:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Identity.Web;
var services = new ServiceCollection();
// Configuration
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["AzureAd:Instance"] = "https://login.microsoftonline.com/",
["AzureAd:TenantId"] = "your-tenant-id",
["AzureAd:ClientId"] = "your-agent-app-client-id",
["AzureAd:ClientCredentials:0:SourceType"] = "StoreWithDistinguishedName",
["AzureAd:ClientCredentials:0:CertificateStorePath"] = "CurrentUser/My",
["AzureAd:ClientCredentials:0:CertificateDistinguishedName"] = "CN=YourCert"
})
.Build();
services.AddSingleton<IConfiguration>(configuration);
// Configure Microsoft Identity
services.Configure<MicrosoftIdentityApplicationOptions>(
configuration.GetSection("AzureAd"));
services.AddTokenAcquisition(true);
services.AddInMemoryTokenCaches();
services.AddHttpClient();
services.AddMicrosoftGraph();
// Add agent identities support
services.AddAgentIdentities();
var serviceProvider = services.BuildServiceProvider();
使用代理标识获取令牌
配置代理服务后,使用 IAuthorizationHeaderProvider 或 Microsoft Graph SDK 获取令牌:
using Microsoft.Identity.Abstractions;
using Microsoft.Graph;
// Your agent identity GUID
string agentIdentityId = "d84da24a-2ea2-42b8-b5ab-8637ec208024";
// Option 1: Using IAuthorizationHeaderProvider
IAuthorizationHeaderProvider authProvider =
serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();
var options = new AuthorizationHeaderProviderOptions()
.WithAgentIdentity(agentIdentityId);
string authHeader = await authProvider.CreateAuthorizationHeaderForAppAsync(
scopes: "https://graph.microsoft.com/.default",
options);
// Option 2: Using Microsoft Graph SDK
GraphServiceClient graphClient =
serviceProvider.GetRequiredService<GraphServiceClient>();
var applications = await graphClient.Applications.GetAsync(request =>
{
request.Options.WithAuthenticationOptions(authOptions =>
{
authOptions.WithAgentIdentity(agentIdentityId);
});
});
查看完整的自治代理示例
以下类将代理标识令牌获取和图形 API调用包装到可重用的服务中:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Graph;
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;
public class AutonomousAgentService
{
private readonly GraphServiceClient _graphClient;
private readonly IAuthorizationHeaderProvider _authProvider;
private readonly string _agentIdentityId;
public AutonomousAgentService(
string agentIdentityId,
IServiceProvider serviceProvider)
{
_agentIdentityId = agentIdentityId;
_graphClient = serviceProvider.GetRequiredService<GraphServiceClient>();
_authProvider = serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();
}
public async Task<string> GetAuthorizationHeaderAsync()
{
var options = new AuthorizationHeaderProviderOptions()
.WithAgentIdentity(_agentIdentityId);
return await _authProvider.CreateAuthorizationHeaderForAppAsync(
"https://graph.microsoft.com/.default",
options);
}
public async Task<IEnumerable<Application>> ListApplicationsAsync()
{
var apps = await _graphClient.Applications.GetAsync(request =>
{
request.Options.WithAuthenticationOptions(options =>
{
options.WithAgentIdentity(_agentIdentityId);
});
});
return apps?.Value ?? Enumerable.Empty<Application>();
}
}
配置代理用户标识
代理用户标识使代理可以代表具有委派权限的代理用户执行操作。 使用此模式适用于需要自己邮箱或其他用户范围资源的代理。
先决条件
若要使用代理用户标识,需要:
- 在 Microsoft Entra ID 中注册的代理蓝图
- 代理标识已创建并链接到代理应用程序
- 与代理标识关联的代理用户标识
配置代理用户服务
以下代码使用证书凭据配置代理应用程序标识并注册所需的服务:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Web;
using System.Security.Cryptography.X509Certificates;
var services = new ServiceCollection();
// Configure agent application
services.Configure<MicrosoftIdentityApplicationOptions>(options =>
{
options.Instance = "https://login.microsoftonline.com/";
options.TenantId = "your-tenant-id";
options.ClientId = "your-agent-app-client-id";
// Use certificate for agent authentication
options.ClientCredentials = new[]
{
CertificateDescription.FromStoreWithDistinguishedName(
"CN=YourCertificate",
StoreLocation.CurrentUser,
StoreName.My)
};
});
// Add services (true = singleton)
services.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
services.AddTokenAcquisition(true);
services.AddInMemoryTokenCaches();
services.AddHttpClient();
services.AddMicrosoftGraph();
services.AddAgentIdentities();
var serviceProvider = services.BuildServiceProvider();
通过代理身份获取用户令牌
可以通过 UPN 或对象 ID 标识目标用户。
用户名(UPN)
using Microsoft.Identity.Abstractions;
using Microsoft.Graph;
string agentIdentityId = "your-agent-identity-id";
string userUpn = "user@yourtenant.onmicrosoft.com";
// Get authorization header
IAuthorizationHeaderProvider authProvider =
serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();
var options = new AuthorizationHeaderProviderOptions()
.WithAgentUserIdentity(
agentApplicationId: agentIdentityId,
username: userUpn);
string authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
scopes: new[] { "https://graph.microsoft.com/.default" },
options);
// Or use Microsoft Graph SDK
GraphServiceClient graphClient =
serviceProvider.GetRequiredService<GraphServiceClient>();
var me = await graphClient.Me.GetAsync(request =>
{
request.Options.WithAuthenticationOptions(options =>
options.WithAgentUserIdentity(agentIdentityId, userUpn));
});
按用户对象 ID
string agentIdentityId = "your-agent-identity-id";
Guid userObjectId = Guid.Parse("user-object-id");
var options = new AuthorizationHeaderProviderOptions()
.WithAgentUserIdentity(
agentApplicationId: agentIdentityId,
userId: userObjectId);
string authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
scopes: new[] { "https://graph.microsoft.com/.default" },
options);
// With Graph SDK
var me = await graphClient.Me.GetAsync(request =>
{
request.Options.WithAuthenticationOptions(options =>
options.WithAgentUserIdentity(agentIdentityId, userObjectId));
});
用 ClaimsPrincipal 缓存令牌
为了获得更好的性能,请通过传递 ClaimsPrincipal 实例来缓存用户令牌。 第一个调用使用uid和utid声明填充主体身份,后续调用重复使用缓存的令牌:
using System.Security.Claims;
using Microsoft.Identity.Abstractions;
// First call - creates cache entry
ClaimsPrincipal userPrincipal = new ClaimsPrincipal();
string authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
scopes: new[] { "https://graph.microsoft.com/.default" },
options,
userPrincipal);
// ClaimsPrincipal now has uid and utid claims for caching
bool hasUserId = userPrincipal.HasClaim(c => c.Type == "uid");
bool hasTenantId = userPrincipal.HasClaim(c => c.Type == "utid");
// Subsequent calls - uses cache
authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
scopes: new[] { "https://graph.microsoft.com/.default" },
options,
userPrincipal); // Reuse the same principal
覆盖租户
对于多租户场景,可以在运行时覆盖租户。 当应用配置了 "common" ,但需要面向特定租户时,这非常有用:
var options = new AuthorizationHeaderProviderOptions()
.WithAgentUserIdentity(agentIdentityId, userUpn);
// Override tenant (useful when app is configured with "common")
options.AcquireTokenOptions.Tenant = "specific-tenant-id";
string authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
scopes: new[] { "https://graph.microsoft.com/.default" },
options);
// With Graph SDK
var me = await graphClient.Me.GetAsync(request =>
{
request.Options.WithAuthenticationOptions(options =>
{
options.WithAgentUserIdentity(agentIdentityId, userUpn);
options.AcquireTokenOptions.Tenant = "specific-tenant-id";
});
});
查看完整的代理用户标识示例
以下类提供了使用代理用户标识获取用户配置文件和授权标头的方法:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Graph;
using Microsoft.Identity.Abstractions;
using System.Security.Claims;
public class AgentUserService
{
private readonly IAuthorizationHeaderProvider _authProvider;
private readonly GraphServiceClient _graphClient;
private readonly string _agentIdentityId;
public AgentUserService(
string agentIdentityId,
IServiceProvider serviceProvider)
{
_agentIdentityId = agentIdentityId;
_authProvider = serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();
_graphClient = serviceProvider.GetRequiredService<GraphServiceClient>();
}
public async Task<User> GetUserProfileAsync(string userUpn)
{
var me = await _graphClient.Me.GetAsync(request =>
{
request.Options.WithAuthenticationOptions(options =>
options.WithAgentUserIdentity(_agentIdentityId, userUpn));
});
return me!;
}
public async Task<User> GetUserProfileByIdAsync(Guid userObjectId)
{
var me = await _graphClient.Me.GetAsync(request =>
{
request.Options.WithAuthenticationOptions(options =>
options.WithAgentUserIdentity(_agentIdentityId, userObjectId));
});
return me!;
}
public async Task<string> GetAuthHeaderForUserAsync(
string userUpn,
ClaimsPrincipal? cachedPrincipal = null)
{
var options = new AuthorizationHeaderProviderOptions()
.WithAgentUserIdentity(_agentIdentityId, userUpn);
return await _authProvider.CreateAuthorizationHeaderForUserAsync(
scopes: new[] { "https://graph.microsoft.com/.default" },
options,
cachedPrincipal ?? new ClaimsPrincipal());
}
}
创建可重用的服务配置
定义扩展方法
创建可重用的扩展方法,以在整个应用程序中封装代理标识配置:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;
public static class ServiceCollectionExtensions
{
public static IServiceProvider ConfigureServicesForAgentIdentities(
this IServiceCollection services,
IConfiguration configuration)
{
// Add configuration
services.AddSingleton(configuration);
// Configure Microsoft Identity options
services.Configure<MicrosoftIdentityApplicationOptions>(
configuration.GetSection("AzureAd"));
services.AddTokenAcquisition(true);
// Add token caching
services.AddInMemoryTokenCaches();
// Add HTTP client
services.AddHttpClient();
// Add Microsoft Graph (optional)
services.AddMicrosoftGraph();
// Add agent identities support
services.AddAgentIdentities();
return services.BuildServiceProvider();
}
}
使用扩展方法
调用扩展方法以在单个行中配置服务:
var services = new ServiceCollection();
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var serviceProvider = services.ConfigureServicesForAgentIdentities(configuration);
调用 API
本部分介绍如何使用这三种身份验证模式中的每一种调用 API。
调用 Microsoft Graph
以下示例演示如何将Microsoft Graph作为标准守护程序、自治代理和代理用户标识调用:
using Microsoft.Graph;
GraphServiceClient graphClient =
serviceProvider.GetRequiredService<GraphServiceClient>();
// Standard daemon (app-only)
var users = await graphClient.Users.GetAsync();
// Autonomous agent (app-only with agent identity)
var apps = await graphClient.Applications.GetAsync(request =>
{
request.Options.WithAuthenticationOptions(options =>
{
options.WithAgentIdentity("agent-identity-id");
options.RequestAppToken = true;
});
});
// Agent user identity (delegated with user context)
var me = await graphClient.Me.GetAsync(request =>
{
request.Options.WithAuthenticationOptions(options =>
options.WithAgentUserIdentity("agent-identity-id", "user@tenant.com"));
});
使用 IDownstreamApi 调用自定义 API
使用 IDownstreamApi 通过三种身份验证模式之一来调用您自己的受保护 API:
using Microsoft.Identity.Abstractions;
IDownstreamApi downstreamApi =
serviceProvider.GetRequiredService<IDownstreamApi>();
// Standard daemon
var result = await downstreamApi.GetForAppAsync<ApiResponse>(
serviceName: "MyApi",
options => options.RelativePath = "api/data");
// With agent identity
var result = await downstreamApi.GetForAppAsync<ApiResponse>(
serviceName: "MyApi",
options =>
{
options.RelativePath = "api/data";
options.WithAgentIdentity("agent-identity-id");
});
// Agent user identity
var result = await downstreamApi.GetForUserAsync<ApiResponse>(
serviceName: "MyApi",
options =>
{
options.RelativePath = "api/data";
options.WithAgentUserIdentity("agent-identity-id", "user@tenant.com");
});
进行手动 HTTP 调用
需要完全控制 HTTP 请求时直接使用 IAuthorizationHeaderProvider :
using Microsoft.Identity.Abstractions;
IAuthorizationHeaderProvider authProvider =
serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();
HttpClient httpClient = new HttpClient();
// Standard daemon
string authHeader = await authProvider.CreateAuthorizationHeaderForAppAsync(
"https://graph.microsoft.com/.default");
httpClient.DefaultRequestHeaders.Add("Authorization", authHeader);
var response = await httpClient.GetStringAsync("https://graph.microsoft.com/v1.0/users");
// With agent identity
var options = new AuthorizationHeaderProviderOptions()
.WithAgentIdentity("agent-identity-id");
authHeader = await authProvider.CreateAuthorizationHeaderForAppAsync(
"https://graph.microsoft.com/.default",
options);
// Agent user identity
var userOptions = new AuthorizationHeaderProviderOptions()
.WithAgentUserIdentity("agent-identity-id", "user@tenant.com");
authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
new[] { "https://graph.microsoft.com/.default" },
userOptions);
配置令牌缓存
根据环境选择缓存策略。
开发:内存中缓存
使用内存中缓存进行本地开发和测试:
services.AddInMemoryTokenCaches();
生产:分布式缓存
在生产环境中,请使用分布式缓存来在应用程序重启和扩展实例的过程中持久化令牌。
SQL Server
将令牌存储在SQL Server表中:
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = configuration["ConnectionStrings:TokenCache"];
options.SchemaName = "dbo";
options.TableName = "TokenCache";
});
services.AddDistributedTokenCaches();
Redis
使用 Redis 实现高性能分布式令牌缓存:
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = configuration["Redis:ConnectionString"];
options.InstanceName = "TokenCache_";
});
services.AddDistributedTokenCaches();
Cosmos DB
使用 Cosmos DB 进行全局分布式令牌缓存:
services.AddCosmosDbTokenCaches(options =>
{
options.CosmosDbConnectionString = configuration["CosmosDb:ConnectionString"];
options.DatabaseId = "TokenCache";
options.ContainerId = "Tokens";
});
了解详细信息:令牌缓存配置
浏览Azure示例
Microsoft提供了演示守护程序应用模式的示例。
示例存储库
active-directory-dotnetcore-daemon-v2
此存储库包含多个方案:
| 示例 | 说明 | 链接 |
|---|---|---|
| 1-Call-MSGraph | 使用客户端凭据调用Microsoft Graph的基本守护程序 | View 示例 |
| 2-Call-OwnApi | 调用自己受保护的 Web API 的守护程序 | View 示例 |
| 3-Using-KeyVault | 使用Azure 密钥保管库进行证书存储的守护程序 | View 示例 |
| 4-多租户 | 多租户后台应用 | View 示例 |
| 5-Call-MSGraph-ManagedIdentity | 在 Azure 上使用托管标识的守护程序 | View 示例 |
将示例模式与生产模式进行比较
为了简单起见,Azure示例使用 TokenAcquirerFactory.GetDefaultInstance(),这是适用于 simple 控制台应用、原型和测试的建议方法。 本指南显示了这两种模式:
TokenAcquirerFactory Pattern (Azure 示例):
// Simple, perfect for prototypes and tests
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
tokenAcquirerFactory.Services.AddDownstreamApi("MyApi", ...);
var serviceProvider = tokenAcquirerFactory.Build();
完整 服务集合 模式(生产应用):
// More control, testable, follows DI best practices
var services = new ServiceCollection();
services.AddTokenAcquisition(true); // true = singleton
services.Configure<MicrosoftIdentityApplicationOptions>(...);
var serviceProvider = services.BuildServiceProvider();
何时使用:
-
使用
TokenAcquirerFactory用于:控制台应用、快速原型、单元测试、简单守护程序服务 -
使用
ServiceCollection:适用于生产应用程序、ASP.NET Core 集成、复杂 DI 场景以及涉及IHostedService的后台服务
这两种方法都完全受支持,并且已准备好生产。 根据应用程序的复杂性和集成需求进行选择。
解决常见问题
AADSTS700016:找不到应用程序
原因: 无效 ClientId 或应用程序未在租户中注册。
Solution:验证配置中的 ClientId是否与Microsoft Entra应用注册匹配。
AADSTS7000215:客户端密码无效
原因: 客户端密码不正确、已过期或未配置。
Solution:
- 验证Azure门户中的机密是否与配置匹配
- 检查机密过期日期
- 考虑将证书用于生产
AADSTS700027:客户端断言包含无效签名
原因: 证书未找到、过期或私钥不可访问。
Solution:
- 验证证书是否已安装在正确的证书存储中
- 验证证书专有名称是否与配置匹配
- 确保应用程序有权读取私钥
- 请参阅 证书配置指南
AADSTS650052:应用需要访问一个服务
原因: 未授予所需的 API 权限或缺少管理员同意。
Solution:
- 导航到 Azure门户 → 应用注册 → 你的应用 → API 权限
- 添加所需的权限(例如,
User.Read.Allfor Microsoft Graph) - 单击“授予管理员同意”按钮
代理标识错误
AADSTS50105:已登录用户未被分配到角色
原因: 代理标识未正确配置或未分配给应用程序。
Solution:
- 验证代理标识是否存在于Microsoft Entra ID
- 确保代理标识已链接到应用程序
- 检查代理身份是否具有所需的权限
获取令牌但权限不正确
原因: 使用代理用户标识但请求应用权限,反之亦然。
Solution:
- 对于仅限应用的令牌,请使用
CreateAuthorizationHeaderForAppAsyncWithAgentIdentity - 对于委托令牌:与
CreateAuthorizationHeaderForUserAsync一起使用WithAgentUserIdentity - 确保 API 权限与令牌类型匹配(应用程序与委托)
令牌缓存问题
问题: 令牌未缓存,这会导致每次都必须重新获取。
Solution:
- 对于代理用户标识:跨调用重复使用同一
ClaimsPrincipal实例 - 验证分布式缓存连接(如果使用 Redis/SQL)
- 启用调试日志记录以查看缓存操作
详细诊断:日志记录和诊断指南
相关内容
- 从 Web API 调用下游 API - OBO 模式
- MSAL.NET 框架指南 - .NET Framework 的令牌缓存和证书配置
- 证书配置 - 从 密钥保管库、存储库、文件或 Base64 加载证书
- 令牌缓存配置 - 生产缓存策略
- 日志记录和诊断 - 排查令牌获取问题
- 自定义指南 - 高级配置模式
- Microsoft 标识平台守护程序应用文档
- Azure 示例:守护程序应用程序
- Microsoft。Identity.Web NuGet 包
- ** Microsoft.Identity.Abstractions API 参考