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

Azure AD:在WebAPI中切换身份以调用下游服务

解决WebAPI以服务身份调用另一WebAPI的ADAL.NET实现方案

我刚好之前处理过完全相同的Azure AD场景,用ADAL.NET实现服务到服务的身份验证核心是切换到客户端凭据流(Client Credentials Flow)——这是专门给服务账户用的无用户交互认证方式,和用户委托的令牌完全独立。下面给你一步步讲清楚配置和代码实现:

第一步:Azure AD后台配置(关键!很多人在这里踩坑)

  • 给WebAPI2的应用注册暴露API范围:在WebAPI2的应用注册里,找到“公开API”,添加一个应用类型的范围(比如access_as_app),别选委托类型的范围。
  • 给WebAPI1的应用注册添加应用权限:在WebAPI1的应用注册里,找到“API权限”,点击“添加权限”→选择WebAPI2→勾选刚才创建的应用权限,最后一定要点击“授予管理员同意”(这个步骤不能少,否则令牌会报权限不足)。
  • 给WebAPI1生成客户端凭据:在WebAPI1的应用注册里,找到“证书和密码”,添加一个客户端密码(生产环境更推荐用证书),保存好密码值(只显示一次)。

第二步:WebAPI1中用ADAL.NET获取服务令牌

在需要调用WebAPI2的方法里,用客户端凭据流获取服务账户的令牌,代码示例如下:

using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Threading.Tasks;

public class WebApi2ServiceClient
{
    private readonly string _tenantId;
    private readonly string _webApi1ClientId;
    private readonly string _webApi1ClientSecret;
    private readonly string _webApi2ResourceId;

    // 建议从配置文件读取这些参数,绝对不要硬编码
    public WebApi2ServiceClient(IConfiguration config)
    {
        _tenantId = config["AzureAd:TenantId"];
        _webApi1ClientId = config["AzureAd:ClientId"];
        _webApi1ClientSecret = config["AzureAd:ClientSecret"];
        // WebAPI2的资源ID可以是它的应用ID URI,比如api://<webapi2-client-id>/.default
        _webApi2ResourceId = config["WebApi2:ResourceId"];
    }

    public async Task<string> GetServiceAccessToken()
    {
        var authContext = new AuthenticationContext($"https://login.microsoftonline.com/{_tenantId}");
        var clientCredential = new ClientCredential(_webApi1ClientId, _webApi1ClientSecret);

        // 获取服务账户的访问令牌
        var authResult = await authContext.AcquireTokenAsync(_webApi2ResourceId, clientCredential);
        
        return authResult.AccessToken;
    }

    // 用获取到的令牌调用WebAPI2的示例方法
    public async Task CallWebApi2()
    {
        string accessToken = await GetServiceAccessToken();
        using var httpClient = new HttpClient();
        httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
        
        var response = await httpClient.GetAsync("https://your-webapi2-url/api/your-endpoint");
        response.EnsureSuccessStatusCode();
        // 这里添加你的响应处理逻辑
    }
}

第三步:WebAPI2端的授权验证配置

确保WebAPI2的Startup.cs里配置了正确的JWT验证,允许应用权限的令牌:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.Authority = "https://login.microsoftonline.com/your-tenant-id";
            options.Audience = "api://your-webapi2-client-id"; // WebAPI2的应用ID URI
            // 验证令牌的发行者和受众
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer = "https://sts.windows.net/your-tenant-id/",
                ValidateAudience = true,
                ValidAudience = "api://your-webapi2-client-id"
            };
        });

    // 配置授权策略,只允许指定服务账户访问
    services.AddAuthorization(options =>
    {
        options.AddPolicy("ServiceAccess", policy =>
        {
            policy.RequireClaim("azp", "webapi1-client-id"); // 限定只有WebAPI1的服务账户能访问
            // 或者检查权限范围:policy.RequireClaim("scp", "access_as_app");
        });
    });
}

常见坑点提醒

  • 绝对不要把客户端密钥硬编码到代码里,生产环境建议用Azure Key Vault存储,再通过配置读取。
  • 必须给WebAPI1的应用权限授予管理员同意,否则获取令牌时会返回invalid_grant错误。
  • 如果用证书代替客户端密钥,把ClientCredential换成ClientAssertionCertificate类,安全性更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:04:09