You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Visual Studio 2022中运行.NET 6 Web API时获取令牌及缓存方案咨询

问题背景

我有一个部署在Azure App Service上的.NET 6 Web API应用,当前使用Azure托管身份获取令牌,依赖Azure.Identity版本1.7.0,相关代码如下:

var tokenCredential = new ChainedTokenCredential(
            new ManagedIdentityCredential("", new TokenCredentialOptions
            {
                Retry =
                {
                    Delay = TimeSpan.FromSeconds(2),
                    MaxDelay = TimeSpan.FromSeconds(16),
                    MaxRetries = 5,
                    Mode = RetryMode.Exponential
                }
            }),
            new AzureCliCredential()
        );

var accessToken = await tokenCredential.GetTokenAsync(new TokenRequestContext(new[] { _configuration.GetSection("AzureAd:Scope")?.Value }));

目前该应用仅能在Azure App Service环境下运行(因应用服务身份已在Azure AD应用中注册),且未找到开箱即用的令牌缓存方案。现需咨询以下两个问题:

  1. 在Visual Studio 2022中运行该Web应用时,如何获取令牌?
  2. 是否存在开箱即用的令牌缓存方案?若没有,有哪些可选方案?

解答

1. Visual Studio 2022本地运行获取令牌

你的代码已使用ChainedTokenCredential,它会按顺序尝试链中的凭证。要在Visual Studio 2022本地运行时获取令牌,只需在链中添加VisualStudioCredential即可,修改后的代码如下:

var tokenCredential = new ChainedTokenCredential(
            new ManagedIdentityCredential("", new TokenCredentialOptions
            {
                Retry =
                {
                    Delay = TimeSpan.FromSeconds(2),
                    MaxDelay = TimeSpan.FromSeconds(16),
                    MaxRetries = 5,
                    Mode = RetryMode.Exponential
                }
            }),
            new VisualStudioCredential(), // 添加Visual Studio凭证支持
            new AzureCliCredential()
        );

添加后,本地运行时ChainedTokenCredential会尝试使用Visual Studio中登录的Azure账号获取令牌。需确保你在Visual Studio中登录的账号拥有目标资源的访问权限,且AzureAd:Scope配置的范围对该账号有效。

保留ChainedTokenCredential的好处是无需修改代码,即可在本地和Azure生产环境间无缝切换。

2. 令牌缓存方案

Azure.Identity库本身没有开箱即用的令牌缓存实现,因为不同应用场景(单实例、多租户、无状态API等)对缓存的需求差异极大。以下是几种实用的可选方案:

内存缓存(单实例简单场景)

适合单实例部署、无状态要求不高的应用,直接使用.NET自带的IMemoryCache:

private readonly IMemoryCache _cache;

// 构造函数注入IMemoryCache
public TokenService(IMemoryCache cache)
{
    _cache = cache;
}

public async Task<string> GetCachedTokenAsync(IConfiguration configuration)
{
    var scope = configuration.GetSection("AzureAd:Scope")?.Value;
    var cacheKey = $"Token_{scope}";
    
    if (_cache.TryGetValue(cacheKey, out string cachedToken))
    {
        return cachedToken;
    }

    var tokenCredential = new ChainedTokenCredential(
        new ManagedIdentityCredential("", new TokenCredentialOptions
        {
            Retry =
            {
                Delay = TimeSpan.FromSeconds(2),
                MaxDelay = TimeSpan.FromSeconds(16),
                MaxRetries = 5,
                Mode = RetryMode.Exponential
            }
        }),
        new VisualStudioCredential(),
        new AzureCliCredential()
    );

    var accessToken = await tokenCredential.GetTokenAsync(new TokenRequestContext(new[] { scope }));
    // 预留5分钟缓冲时间,避免令牌过期前的请求失败
    var cacheOptions = new MemoryCacheEntryOptions()
        .SetAbsoluteExpiration(accessToken.ExpiresOn - TimeSpan.FromMinutes(5));
    
    _cache.Set(cacheKey, accessToken.Token, cacheOptions);
    return accessToken.Token;
}

该方案实现简单,但应用重启或扩容后缓存会丢失,不适合多实例部署场景。

分布式缓存(多实例生产场景)

如果是多实例部署的应用,建议使用分布式缓存(如Azure Redis Cache、SQL Server分布式缓存),确保所有实例共享缓存状态。以Azure Redis Cache为例,使用IDistributedCache:

private readonly IDistributedCache _distributedCache;

// 构造函数注入IDistributedCache
public TokenService(IDistributedCache distributedCache)
{
    _distributedCache = distributedCache;
}

public async Task<string> GetCachedTokenAsync(IConfiguration configuration)
{
    var scope = configuration.GetSection("AzureAd:Scope")?.Value;
    var cacheKey = $"Token_{scope}";
    
    var cachedToken = await _distributedCache.GetStringAsync(cacheKey);
    if (!string.IsNullOrEmpty(cachedToken))
    {
        return cachedToken;
    }

    var tokenCredential = new ChainedTokenCredential(
        new ManagedIdentityCredential("", new TokenCredentialOptions
        {
            Retry =
            {
                Delay = TimeSpan.FromSeconds(2),
                MaxDelay = TimeSpan.FromSeconds(16),
                MaxRetries = 5,
                Mode = RetryMode.Exponential
            }
        }),
        new VisualStudioCredential(),
        new AzureCliCredential()
    );

    var accessToken = await tokenCredential.GetTokenAsync(new TokenRequestContext(new[] { scope }));
    var expiration = accessToken.ExpiresOn - DateTimeOffset.UtcNow - TimeSpan.FromMinutes(5);
    
    await _distributedCache.SetStringAsync(cacheKey, accessToken.Token, new DistributedCacheEntryOptions
    {
        AbsoluteExpirationRelativeToNow = expiration
    });
    
    return accessToken.Token;
}

需提前配置分布式缓存的连接字符串,确保所有应用实例都能访问到缓存服务。

自定义缓存实现

如果有特殊需求(如租户隔离、精细的缓存过期策略),可以封装独立的令牌缓存服务,结合业务场景定制缓存逻辑。例如针对多租户场景,在缓存键中加入租户ID,实现租户级别的缓存隔离。


内容的提问来源于stack exchange,提问作者user584018

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 23:50:25