Bot Framework v3对接Teams实现SSO时登录后无验证码无法获取token问题
问题原因
该问题是Bot Framework v3 SDK已停止维护、未适配Teams渠道OAuth回调机制导致的,和你已完成的权限、AAD连接、manifest域名配置无关。v3自带的GetTokenDialog仅适配了WebChat渠道的验证码回传逻辑,没有处理Teams的登录回调上下文传递,所以登录完成后不会返回验证码。
修复步骤
- 替换原生
GetTokenDialog组件
不要使用SDK自带的登录对话框,手动构造带openUrl按钮的登录卡片,将Teams会话的conversationId、userId、serviceUrl编码后拼接到AAD授权链接的state参数中,AAD授权完成后会原封不动返回该参数用于会话定位。 - 自定义OAuth回调接口
将AAD应用的重定向URI修改为你自行开发的回调接口,不要使用Bot Framework默认的回调地址。接口中完成三个动作:解析state参数拿到会话上下文、用授权码兑换访问令牌、主动调用Bot Connector API将验证码或令牌推送给对应的Teams用户,最后返回带window.close()脚本的响应自动关闭登录标签页。 - 补充验证码校验逻辑
新增用户输入监听逻辑,校验用户输入的验证码匹配后,取出缓存的令牌直接走后续业务流程。 - 补全Teams manifest配置
确认manifest中已添加webApplicationInfo节点,配置你的AAD应用ID和资源URI,这是Teams登录流程必需的配置。
代码示例
构造自定义登录卡片
private async Task SendCustomSignInCard(IDialogContext context) { // 拼接会话上下文到state参数 var state = $"conversationId={context.Activity.Conversation.Id}&userId={context.Activity.From.Id}&serviceUrl={Uri.EscapeDataString(context.Activity.ServiceUrl)}"; // 构造AAD v2授权链接 var authUrl = $"https://login.microsoftonline.com/{你的租户ID}/oauth2/v2.0/authorize?" + $"client_id={你的AAD客户端ID}" + $"&response_type=code" + $"&redirect_uri={Uri.EscapeDataString(你的回调接口地址)}" + $"&scope={Uri.EscapeDataString("你需要的Graph权限,比如User.Read openid offline_access")}" + $"&state={Uri.EscapeDataString(state)}"; var signInCard = new HeroCard { Text = $"请登录{ConnectionName}以继续操作", Buttons = new List<CardAction> { new CardAction(ActionTypes.OpenUrl, "登录", value: authUrl) } }; var reply = context.MakeMessage(); reply.Attachments.Add(signInCard.ToAttachment()); await context.PostAsync(reply); // 等待用户输入验证码 context.Wait(HandleVerificationCodeInput); }
OAuth回调接口处理逻辑
[HttpGet] [Route("api/oauth/callback")] public async Task<IActionResult> OAuthCallback(string code, string state) { // 解析state参数获取会话信息 var stateDict = HttpUtility.ParseQueryString(Uri.UnescapeDataString(state)); var conversationId = stateDict["conversationId"]; var userId = stateDict["userId"]; var serviceUrl = stateDict["serviceUrl"]; // 用授权码兑换访问令牌 using var httpClient = new HttpClient(); var tokenReqParams = new Dictionary<string, string> { {"client_id", 你的AAD客户端ID}, {"client_secret", 你的AAD客户端密钥}, {"code", code}, {"grant_type", "authorization_code"}, {"redirect_uri", 你的回调接口地址}, {"scope", "你需要的Graph权限,和授权链接保持一致"} }; var tokenResp = await httpClient.PostAsync( $"https://login.microsoftonline.com/{你的租户ID}/oauth2/v2.0/token", new FormUrlEncodedContent(tokenReqParams)); var tokenContent = await tokenResp.Content.ReadAsStringAsync(); var tokenResult = JsonConvert.DeserializeObject<TokenResult>(tokenContent); // 生成6位随机验证码,和令牌绑定缓存,过期时间设为5分钟 var verificationCode = new Random().Next(100000, 999999).ToString(); 你的缓存组件.Set($"login_code_{userId}", new { Code = verificationCode, Token = tokenResult.AccessToken }, TimeSpan.FromMinutes(5)); // 主动给Teams用户推送验证码 var connectorClient = new ConnectorClient(new Uri(serviceUrl), new MicrosoftAppCredentials(你的机器人AppID, 你的机器人App密钥)); var notifyActivity = Activity.CreateMessageActivity(); notifyActivity.From = new ChannelAccount(你的机器人AppID, "你的机器人名称"); notifyActivity.Recipient = new ChannelAccount(userId); notifyActivity.Conversation = new ConversationAccount(id: conversationId); notifyActivity.Text = $"你的登录验证码为:{verificationCode},5分钟内有效"; await connectorClient.Conversations.SendToConversationAsync((Activity)notifyActivity); // 自动关闭登录标签页 return Content("<script>window.close();</script>", "text/html"); } // 令牌解析用的实体类 public class TokenResult { [JsonProperty("access_token")] public string AccessToken { get; set; } [JsonProperty("expires_in")] public int ExpiresIn { get; set; } }
验证码校验逻辑
private async Task HandleVerificationCodeInput(IDialogContext context, IAwaitable<IMessageActivity> result) { var userInput = (await result).Text?.Trim(); var cacheKey = $"login_code_{context.Activity.From.Id}"; var cacheData = 你的缓存组件.Get<dynamic>(cacheKey); if (cacheData != null && cacheData.Code == userInput) { // 校验通过,删除缓存,执行业务逻辑 你的缓存组件.Delete(cacheKey); await DoThingsWithToken(context, cacheData.Token); } else { await context.PostAsync("验证码错误或已过期,请重新点击登录按钮获取"); await SendCustomSignInCard(context); } }
内容的提问来源于stack exchange,提问作者Shamrock
相关产品推荐
相关产品推荐

