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

ASP.NET Core 3.1 MVC集成MS Graph遇IDW10502错误求助

解决方案

1. 修正Startup.cs中的认证服务配置

你的ASP.NET Core MVC应用属于Web应用,而非Web API,因此不应使用AddMicrosoftIdentityWebApi,需替换为AddMicrosoftIdentityWebApp,该方法专门用于处理用户登录和下游API调用的token获取:

// Startup.cs
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

// 注册HttpContextAccessor,用于处理认证挑战
services.AddHttpContextAccessor();

services.AddGraphService(Configuration);
services.AddControllersWithViews(options =>
{
    var policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
    options.Filters.Add(new AuthorizeFilter(policy));
});

services.AddRazorPages();

2. 修复CustomAuthenticationProvider的变量作用域与异常处理

原代码中accessToken变量仅在try块内声明,外部无法访问,且未处理MsalUiRequiredException导致的登录挑战需求:

// GraphServiceClientFactory.cs中的CustomAuthenticationProvider
class CustomAuthenticationProvider : IAuthenticationProvider
{
    private readonly Func<Task<string>> _acquireAccessToken;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public CustomAuthenticationProvider(Func<Task<string>> acquireTokenCallback, IHttpContextAccessor httpContextAccessor)
    {
        _acquireAccessToken = acquireTokenCallback;
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task AuthenticateRequestAsync(HttpRequestMessage request)
    {
        string accessToken = null;
        try 
        {
            accessToken = await _acquireAccessToken.Invoke();
        }
        catch (MsalUiRequiredException)
        {
            // 触发用户重新登录的认证挑战
            var httpContext = _httpContextAccessor.HttpContext;
            if (httpContext != null)
            {
                await httpContext.ChallengeAsync(MicrosoftIdentityDefaults.AuthenticationScheme);
            }
            throw;
        }
        catch (Exception ex) 
        {
            // 根据业务需求处理其他异常
            throw new InvalidOperationException("获取访问令牌失败", ex);
        }

        if (!string.IsNullOrEmpty(accessToken))
        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
        }
    }
}

3. 更新GraphServiceClientFactory的客户端创建逻辑

需要传入IHttpContextAccessor到自定义认证提供者:

// GraphServiceClientFactory.cs
public static GraphServiceClient GetAuthenticatedGraphClient(Func<Task<string>> acquireAccessToken, string baseUrl, IHttpContextAccessor httpContextAccessor)
{
    return new GraphServiceClient(baseUrl, new CustomAuthenticationProvider(acquireAccessToken, httpContextAccessor));
}

4. 修正控制器中的方法问题

  • Index方法缺少public修饰符,无法被路由访问
  • GetGraphUser方法需补充默认返回值,避免编译错误
  • 更新GraphServiceClient实例化逻辑,传入IHttpContextAccessor:
// MyController.cs
public class MyController: BaseController
{
    // ... 原有字段和构造函数 ...

    // 修正:添加public修饰符
    public async Task<IActionResult> Index()
    {
        string[] scopes = new string[] { "User.Read", "User.ReadBasic.All", "User.Read.All", "User.ReadWrite", "User.ReadWrite.All" };
        User graphUser = await GetGraphUser(graphSettings, tokenAcquisition, scopes).ConfigureAwait(false);

        // 业务逻辑...

        return View();
    }

    public async Task<User> GetGraphUser(GraphSettings graphSettings, ITokenAcquisition tokenAcquisition, string[] scopes)
    {
       GraphServiceClient graphClient = GetGraphServiceClient(graphSettings, tokenAcquisition, scopes);
        string selectedFields = "displayName,streetAddress,city,state,postalCode,businessPhones,mobilePhone,mail,userPrincipalName,id,appRoleAssignments,jobTitle,givenName,surname";

        string loggedInUserId = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
        if (string.IsNullOrEmpty(loggedInUserId))
        {
            throw new UnauthorizedAccessException("无法获取当前用户ID");
        }

        var graphUser1 = await graphClient.Users[loggedInUserId]
            .Request()
            .Select(selectedFields)
            .GetAsync()
            .ConfigureAwait(false);

        return graphUser1;
    }

    public GraphServiceClient GetGraphServiceClient(GraphSettings graphSettings, ITokenAcquisition tokenAcquisition, string[] scopes, bool beta = false)
    {
        var httpContextAccessor = HttpContext.RequestServices.GetRequiredService<IHttpContextAccessor>();
        return GraphServiceClientFactory.GetAuthenticatedGraphClient(async () =>
        {
            string accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(scopes).ConfigureAwait(false);
            return accessToken;
        },
        beta ? graphSettings.GraphApiBeta : graphSettings.GraphApiUrl,
        httpContextAccessor);
    }
}

5. 验证Azure AD应用注册配置

确保你的Azure AD应用注册中:

  • 重定向URI(RedirectUri)与应用配置文件中的AzureAd:RedirectUri一致(格式通常为https://localhost:{port}/signin-oidc)
  • 已添加所需的Graph API权限(如User.Read、User.Read.All等),并完成管理员同意(如果是租户级权限)
  • 客户端密钥(ClientSecret)或证书配置正确,与AzureAd:ClientSecret匹配

错误原因说明

IDW10502与MsalUiRequiredException的核心原因是:

  • 你使用了适用于Web API的AddMicrosoftIdentityWebApi配置,而非Web应用的AddMicrosoftIdentityWebApp,导致用户登录后的身份上下文未正确存入token缓存
  • MSAL尝试静默获取token时,无法找到对应的用户账户信息,因此抛出需要用户交互(登录)的异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 08:31:13