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

ASP.NET Core无法从OpenID Connect获取id_token与access token问题排查

ASP.NET Core中通过HttpContext.GetTokenAsync获取Azure AD Access Token返回Null问题

我有一个ASP.NET Core Web应用,需要将Azure AD的access token发送给PHP脚本,但使用GetTokenAsync从HttpContext获取token时始终返回null。调试发现GetTokenAsync被CookieAuthenticationHandler.HandleAuthenticateOnceAsync()中断,该方法返回AuthenticateResult.Failure。


已完成的配置

1. Startup.cs中的OpenID Connect配置

public void ConfigureServices(IServiceCollection services)
{
    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
    services.AddControllersWithViews();
    services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddOpenIdConnect(options =>
    {
        IConfigurationSection sectionOptions = AppConfiguration?.GetSection("OpenIdConnectOptions");
        if(sectionOptions?.GetChildren()?.Any() == true)
        {
            options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.Authority = sectionOptions["Authority"];
            options.ClientId = sectionOptions["ClientId"];
            options.ClientSecret = sectionOptions["ClientSecret"];
            options.CallbackPath = new PathString(sectionOptions["CallbackPath"]);
            options.SignedOutCallbackPath = new PathString(sectionOptions["SignedOutCallbackPath"]);
            options.RemoteSignOutPath = new PathString(sectionOptions["RemoteSignOutPath"]);
            options.ResponseType = OpenIdConnectResponseType.Code;
            options.ResponseMode = OpenIdConnectResponseMode.Query;
            options.GetClaimsFromUserInfoEndpoint = true;
            List<string> scopes =
                (from curSubsectionScope in sectionOptions.GetSection("Scope")?.GetChildren()
                where !string.IsNullOrWhiteSpace(curSubsectionScope.Value)
                select curSubsectionScope.Value.Trim().ToLower())?.ToList();
            options.Scope?.Clear();
            scopes?.ForEach(options.Scope.Add);
            options.MapInboundClaims = false;
            options.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
            options.TokenValidationParameters.RoleClaimType = ClaimTypes.Role;
        }
    }
}

2. appsettings.json配置

"OpenIdConnectOptions": {
    "Authority": "https://login.microsoftonline.com/{my-tenant-id}/v2.0/",
    "ClientId": "{my-client-id}",
    "ClientSecret": "{my-client-secret}",
    "CallbackPath": "/signin-oidc",
    "SignedOutCallbackPath": "/signout-callback-oidc",
    "RemoteSignOutPath": "/signout-oidc",
    "RedirectUri": "http://localhost:80/azure",
    "SaveTokens": true,
    "Scope": [ "openid", "offline_access" ]
},

3. Azure AD应用设置

az ad app show --id $clientId --query "web.redirectUris"
[
  "https://localhost/signin-oidc",
  "https://localhost/signout-callback-oidc",
  "https://localhost/signout-oidc",
  "http://localhost/azure"
]
az ad app permission list --id $clientId
[
  {
    "resourceAccess": [
      {
        "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",    # User.Read
        "type": "Scope"
      },
      {
        "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9",    # Application.ReadWrite.All
        "type": "Role"
      },
      {
        "id": "37f7f235-527c-4136-accd-4a02d197296e",    # openid
        "type": "Scope"
      },
      {
        "id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182",    # offline_access
        "type": "Scope"
      }
    ],
    "resourceAppId": "00000003-0000-0000-c000-000000000000"    # https://graph.microsoft.com
  }
]

出错的代码

string access_token = await httpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);
string id_token = await httpContext.GetTokenAsync(OpenIdConnectParameterNames.IdToken);

问题排查与解决

1. 确保SaveTokens配置被正确加载

你的appsettings.json中设置了SaveTokens: true,但Startup的OpenIdConnect配置代码中没有读取这个参数。默认SaveTokens为false,token不会被保存到Cookie中,导致GetTokenAsync返回null。需要在AddOpenIdConnect的配置块中添加:

options.SaveTokens = sectionOptions.GetValue<bool>("SaveTokens");

2. 补充有效API作用域

当前配置的Scope只有openid和offline_access,这两个作用域仅用于获取id_token和refresh token,不会返回可调用API的access token。需要添加具体的API权限作用域,比如已授权的User.Read,修改appsettings.json的Scope:

"Scope": [ "openid", "offline_access", "https://graph.microsoft.com/User.Read" ]

3. 启用认证中间件

检查Configure方法中是否添加了认证中间件,缺少的话会导致认证流程不执行:

app.UseAuthentication();
app.UseAuthorization();

4. 验证回调地址一致性

确保Azure AD应用中的redirectUris包含应用实际运行的CallbackPath(/signin-oidc),注意协议(http/https)和端口必须与应用运行地址完全匹配,否则回调失败会导致token无法保存。

5. 排查认证失败的具体原因

通过Cookie认证事件捕获失败详情,精准定位问题:

.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
    options.Events = new CookieAuthenticationEvents
    {
        OnAuthenticationFailed = context =>
        {
            // 记录context.Exception的详细信息,比如签名验证失败、Cookie过期等
            return Task.CompletedTask;
        }
    };
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 18:24:51