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

基于Microsoft Identity Platform从Outlook加载项访问.NET Core REST API

问题解答

你的猜测完全正确。你收到的错误:

Bearer error="invalid_token", error_description="The audience 'e1c50fba-abcd-4e63-9f54-xxxxxxxxxx' is invalid".
本质原因是Outlook加载项通过getAccessToken()获取的令牌,受众是加载项自身的Azure AD应用注册ID,而你的REST API验证时要求受众是自己的应用ID,因此触发无效令牌错误。必须使用On-Behalf-Of(OBO)委托流,由你的API将加载项的令牌兑换成针对自身API的有效令牌,这个流程可以通过Microsoft.Identity.Web轻松实现,且全程无需将兑换后的令牌返回给加载项,只需在API内部处理。

实现步骤

1. 确认Azure AD权限配置

确保你的REST API的Azure AD应用注册中,已添加Outlook加载项应用的access_as_user委托权限,并且该权限已完成管理员或用户同意。同时,要为你的REST API应用注册定义对应的自定义范围(比如access_as_user),用于OBO流兑换令牌时指定。

2. 调整API的认证服务配置

修改现有Program.cs中的认证配置,启用OBO流支持并配置下游API信息:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"), subscribeToJwtBearerMiddlewareDiagnosticsEvents: true)
        .EnableTokenAcquisitionToCallDownstreamApi()
            // 配置要兑换令牌的目标API(即你的REST API自身)
            .AddDownstreamApi("MyRestApi", builder.Configuration.GetSection("DownstreamApi"))
            // 保留令牌缓存,避免重复兑换
            .AddInMemoryTokenCaches();

在appsettings.json中添加下游API的配置项:

"DownstreamApi": {
  "BaseUrl": "https://your-rest-api-base-url",
  "Scopes": "api://{your-rest-api-client-id}/access_as_user"
}

将{your-rest-api-client-id}替换为你的REST API应用注册的客户端ID,Scopes值要和你在Azure AD中为API定义的范围一致。

3. 在API内部兑换并使用令牌

控制器内直接处理

在需要处理业务逻辑的控制器中,注入ITokenAcquisition服务来兑换令牌,并在内部使用该令牌进行权限验证或业务处理:

[ApiController]
[Route("[controller]")]
public class DemoController : ControllerBase
{
    private readonly ITokenAcquisition _tokenAcquisition;
    private readonly IConfiguration _configuration;

    public DemoController(ITokenAcquisition tokenAcquisition, IConfiguration configuration)
    {
        _tokenAcquisition = tokenAcquisition;
        _configuration = configuration;
    }

    [HttpGet]
    [Authorize]
    public async Task<IActionResult> GetData()
    {
        // 兑换加载项的令牌为针对当前API的有效令牌
        var apiScope = _configuration["DownstreamApi:Scopes"];
        string validApiToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { apiScope });

        // 后续业务逻辑可使用该令牌,比如调用内部服务、验证权限等
        // 无需将此令牌返回给Outlook加载项

        return Ok("处理完成");
    }
}

全局中间件透明处理(推荐)

如果希望所有请求进入控制器前自动完成令牌兑换,可自定义中间件,对加载项完全透明:

public class OboTokenMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ITokenAcquisition _tokenAcquisition;
    private readonly IConfiguration _configuration;

    public OboTokenMiddleware(RequestDelegate next, ITokenAcquisition tokenAcquisition, IConfiguration configuration)
    {
        _next = next;
        _tokenAcquisition = tokenAcquisition;
        _configuration = configuration;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // 获取目标API范围并兑换令牌
        var apiScope = _configuration["DownstreamApi:Scopes"];
        var validToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { apiScope });

        // 替换请求头中的令牌为兑换后的有效令牌
        context.Request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", validToken);

        await _next(context);
    }
}

在Program.cs中注册中间件(需放在UseAuthentication之后、UseAuthorization之前):

app.UseAuthentication();
app.UseMiddleware<OboTokenMiddleware>();
app.UseAuthorization();

这样后续的授权逻辑和控制器就能直接使用有效令牌,全程对Outlook加载项无感知。

关键注意事项

  • 令牌缓存(AddInMemoryTokenCaches)会自动缓存兑换后的令牌,减少重复请求,提升性能;生产环境可替换为分布式缓存(如Redis)。
  • 绝对不要将兑换后的令牌返回给Outlook加载项,所有兑换和使用逻辑必须在API内部完成。
  • 确保Outlook加载项的应用注册已正确配置对REST API的access_as_user权限,且已完成同意流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 21:50:35