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

Teams Bot中OAuthPrompt对部分企业成员无法返回TokenResponse问题排查

Teams Bot OAuthPrompt 登出后部分用户认证异常的问题排查与修复

核心问题根源

  1. 登出操作未清理对话状态,导致用户后续消息仍进入旧的认证对话框流程
  2. 内存缓存的用户请求内容未在登出时清除,引发逻辑判断异常
  3. OAuthPrompt配置与对话状态的协同处理存在疏漏

具体修复方案

1. 登出时同步清理对话状态与缓存

原登出逻辑仅执行了用户登出,未重置对话状态和用户缓存,导致后续消息仍走旧的对话框流程。修改OnMessageActivityAsync中的登出分支:

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    var userTokenClient = turnContext.TurnState.Get<UserTokenClient>();

    if (turnContext.Activity.Text.Equals("logout"))
    {
        await userTokenClient.SignOutUserAsync(turnContext.Activity.From.Id, _connectionName, turnContext.Activity.ChannelId, cancellationToken: cancellationToken);
        // 清除对话状态,重置对话框流程
        var dialogState = _conversationState.CreateProperty<DialogState>(nameof(DialogState));
        await dialogState.SetAsync(turnContext, new DialogState(), cancellationToken);
        await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
        // 清除用户内存缓存的请求内容
        _memoryCache.Remove(turnContext.Activity.From.Id);
        
        await turnContext.SendActivityAsync(MessageFactory.Text("You have been signed out."), cancellationToken);
        return;
    }

    // 原有逻辑...
}

2. 优化对话框Token验证逻辑

在LoginStepAsync中,当OAuthPrompt返回null时,主动尝试重新获取Token(适配SSO自动登录场景),同时处理缓存不存在的情况避免循环:

private async Task<DialogTurnResult> LoginStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var tokenResponse = (TokenResponse)stepContext.Result;
    var userTokenClient = stepContext.Context.TurnState.Get<UserTokenClient>();
    
    // 如果Prompt返回null,主动尝试获取Token(处理SSO自动完成的情况)
    if (tokenResponse == null)
    {
        tokenResponse = await userTokenClient.GetUserTokenAsync(
            stepContext.Context.Activity.From.Id, 
            _configuration["ConnectionName"], 
            stepContext.Context.Activity.ChannelId, 
            null, 
            cancellationToken);
    }

    String? question;
    _memoryCache.TryGetValue(stepContext.Context.Activity.From.Id, out question);

    if (tokenResponse?.Token != null && question != null)
    {
        await _teamsService.ProcessTeamsMessageAsync(stepContext.Context, question, tokenResponse.Token, cancellationToken);
        // 处理完成后清除缓存
        _memoryCache.Remove(stepContext.Context.Activity.From.Id);
    }
    else
    {
        await stepContext.Context.SendActivityAsync(MessageFactory.Text("Stuur je vraag nogmaals aub."), cancellationToken);
        // 若缓存不存在,直接结束对话框,让用户重新触发流程
        if (question == null)
        {
            return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
        }
        return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), null, cancellationToken);
    }

    return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
}

3. 调整OAuthPrompt配置

将EndOnInvalidMessage设为false,避免用户在认证过程中发送消息导致Prompt异常终止,确保SSO流程正常完成:

AddDialog(new OAuthPrompt(
    nameof(OAuthPrompt),
    new OAuthPromptSettings
    {
        ConnectionName = configuration["ConnectionName"] ?? throw new ArgumentException("ConnectionName"),
        Text = "Please Sign In",
        Title = "Sign In",
        Timeout = 300000,
        EndOnInvalidMessage = false // 修改为false
    }));

4. 确保对话状态持久化

检查服务配置与适配器,确保ConversationState正确注册并使用:

  • 服务注册添加:
services.AddSingleton<ConversationState>();
  • 适配器中添加对话状态中间件:
public AdapterWithErrorHandler(BotFrameworkAuthentication auth, ConversationState conversationState, ILogger<BotFrameworkHttpAdapter> logger)
    : base(auth, logger)
{
    Use(new TeamsSSOTokenExchangeMiddleware());
    // 注册对话状态中间件
    Use(new ConversationStateMiddleware(conversationState));
    
    // 原有错误处理逻辑...
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 18:40:41