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

.NET6 Blazor Server接入AAD后返回的access token为null问题排查

.NET6 Blazor Server对接Azure AD时Access Token返回null问题修复

问题背景

该问题在技术社区有较多公开讨论,但现有公开方案无法覆盖当前遇到的场景。
当前运行环境为基于.NET6的Blazor Server-Side应用,已完成Azure Active Directory对接,可正常走完AAD身份认证流程,拿到有效的ClaimsPrincipal实例。
初始Program.cs中AAD相关配置片段如下:

[...]
builder.Services
    .AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    ;

builder.Services
    .Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
    {       
        options.SaveTokens = true;
    });
[...]

配置文件中AzureAd节点内容如下:

[...]
"AzureAd": {
  "Instance": "https://login.microsoftonline.com/",
  "Domain": "XXX.com",
  "TenantId": "5dXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "ClientId": "26XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "CallbackPath": "/signin-oidc"
}
[...]

按照公开方案的描述,完成身份认证后在_Host.cshtml调用取token方法本应拿到有效access token,但实际获取到的token值为null,异常状态如下:
Access token为null的异常截图
此前已尝试按照公开方案追加EnableTokenAcquisitionToCallDownstreamApi、AddInMemoryTokenCaches相关调用,调整后的配置如下:

[...]
builder.Services
.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)      
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { "openid" })
.AddInMemoryTokenCaches()
;

但调整后问题没有改善,access token依旧返回null。

问题根因

该问题由三个核心错误导致:

  • Scope配置错误:EnableTokenAcquisitionToCallDownstreamApi传入的scope仅为openid,这是OIDC协议的基础认证scope,仅会触发AAD返回用于站点身份核验的id_token,不会返回可用于访问下游资源的access token。
  • Token获取方式错误:Blazor Server基于长连接Circuit模型运行,Circuit建立后HttpContext不会持续可用,仅配置SaveTokens=true只会把token存在认证Cookie中,不会自动注入到Blazor运行时的DI容器,在组件生命周期内直接通过HttpContext取token大概率拿到null。
  • 云端配置缺失:如果Azure AD应用注册的身份验证配置中没有显式勾选允许返回访问令牌,即使服务端配置了正确的scope,AAD的认证回调响应中也不会携带access_token字段。

修复步骤

  1. 修正服务端DI配置,移除单独写的OpenIdConnectOptions.SaveTokens配置,使用Microsoft Identity内置的token管理流程,替换EnableTokenAcquisitionToCallDownstreamApi中的scope为实际需要访问的资源scope(不要只传openid,如果要访问Microsoft Graph就传对应的Graph权限scope,如果要访问自有受保护API就传API暴露的自定义scope),正确配置示例:
builder.Services
    .AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    // 替换为实际业务需要的资源scope,示例为访问Graph用户信息的scope
    .EnableTokenAcquisitionToCallDownstreamApi(new []{ "User.Read" })
    .AddInMemoryTokenCaches();
  1. 替换token获取方式,不要在Blazor组件/服务中直接依赖HttpContext取token,而是注入框架提供的ITokenAcquisition服务获取有效token,示例:
@inject ITokenAcquisition TokenAcquisition

@code {
    private string? _accessToken;
    protected override async Task OnInitializedAsync()
    {
        // 传入和配置中一致的scope获取对应资源的access token
        _accessToken = await TokenAcquisition.GetAccessTokenForUserAsync(new []{ "User.Read" });
        // 后续可直接用该token调用下游API
    }
}
  1. 如果确实需要在_Host.cshtml页面初始化阶段取token,必须在Blazor应用渲染前从当前请求的HttpContext中获取,再通过组件参数传递到Blazor应用内部,示例:
    在_Host.cshtml的代码块中取token:
@{
    // 该逻辑仅在首次页面请求时执行有效
    var accessToken = await HttpContext.GetTokenAsync("access_token");
}

将token作为参数传入根组件:

<component type="typeof(App)" render-mode="ServerPrerendered" param-InitialAccessToken="accessToken" />

注意:如果完成上述配置后仍然拿不到token,需要登录Azure Portal检查对应应用注册的配置:在「身份验证」-「Web平台配置」板块,确认已经勾选访问令牌和ID令牌两个选项,保存配置后重试即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 01:24:25