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

Microsoft Graph .NET SDK v5中AcquireTokenInteractive重复触发问题求助

问题:调用Microsoft Graph接口重复触发交互式登录

问题现象

使用Microsoft Graph .NET SDK v5时,每次调用graphClient.Me相关接口都会触发AcquireTokenInteractive。首次调用await graphClient.Me.GetAsync()弹出登录界面符合预期,但第二次调用await graphClient.Me.Calendars.GetAsync()时再次弹出登录界面,属于异常行为。

原因分析

问题核心出在TokenProvider类的GetAuthorizationTokenAsync方法中:每次调用该方法都会重新创建PublicClientApplication实例。MSAL的账号、Token缓存与PublicClientApplication实例绑定,新实例无法读取之前登录缓存的账号信息,导致AcquireTokenSilent找不到可用账号,抛出MsalUiRequiredException,进而触发交互式登录流程。

此外,Button1_Click方法每次执行都会新建TokenProvider和GraphServiceClient实例,进一步加剧了缓存失效问题。

解决方案

1. 仅初始化一次PublicClientApplication

将PublicClientApplication的创建逻辑移到TokenProvider的构造函数中,确保整个生命周期内只初始化一次:

public class TokenProvider : IAccessTokenProvider
{
    public AllowedHostsValidator AllowedHostsValidator => throw new NotImplementedException();

    public IPublicClientApplication publicClientApp;
    
    // 在构造函数中初始化PublicClientApplication
    public TokenProvider()
    {
        publicClientApp = PublicClientApplicationBuilder.Create("0c-a5-42-a-92")
            .WithRedirectUri("http://localhost")
            .Build();
    }
    
    public async Task<string> GetAuthorizationTokenAsync(Uri uri, Dictionary<string, object> additionalAuthenticationContext = null, CancellationToken cancellationToken = default)
    {
        var scopes = new[] { "Calendars.Read", "User.Read" };
        AuthenticationResult authResult;
        
        try
        {
            var accounts = await publicClientApp.GetAccountsAsync();
            authResult = await publicClientApp.AcquireTokenSilent(scopes, accounts.FirstOrDefault()).ExecuteAsync();
            return authResult.AccessToken;
        }
        catch (MsalUiRequiredException ex)
        {
            authResult = await publicClientApp.AcquireTokenInteractive(scopes).ExecuteAsync();
            return authResult.AccessToken;
        }
    }

    public async Task SignOut()
    {
        var accounts = await publicClientApp.GetAccountsAsync();
        foreach (var account in accounts)
        {
            await publicClientApp.RemoveAsync(account);
        }
    }
}

2. 复用GraphServiceClient及相关实例

在windows1.cs中,将TokenProvider、BaseBearerTokenAuthenticationProvider和GraphServiceClient的初始化移到类的构造函数中,避免每次点击按钮都新建实例:

TokenProvider tp;
BaseBearerTokenAuthenticationProvider authenticationProvider;
GraphServiceClient graphClient;

// 在类构造函数中初始化实例
public Windows1()
{
    tp = new TokenProvider();
    authenticationProvider = new BaseBearerTokenAuthenticationProvider(tp);
    graphClient = new GraphServiceClient(authenticationProvider);
}

public async Task<bool> Button1_Click()
{
    Microsoft.Graph.Models.User user = null;
    user = await graphClient.Me.GetAsync();   // 首次触发登录界面,符合预期
    return true;
}

public async Task<List<string>> Button2_Click()
{
    var calendars = await graphClient.Me.Calendars.GetAsync();  // 复用缓存的Token,不再触发登录
    // 处理日历数据并返回
    return calendars.Value.Select(c => c.Name).ToList();
}

补充说明

  • MSAL的账号和Token缓存默认存储在本地文件系统中,仅同一个PublicClientApplication实例可访问这些缓存。
  • 生产环境中需实现AllowedHostsValidator,配置合法的主机列表以规避安全风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 07:40:06