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

基于Teams AI库的操作型消息扩展:如何启用SSO并获取有效Graph API访问令牌

基于Teams AI库的操作型消息扩展:如何启用SSO并获取有效Graph API访问令牌

看起来你已经走在正确的路上了!我来帮你完善代码逻辑,实现「未授权时引导用户跳转到 consent 对话框,已授权则打开任务自适应卡片」的需求,同时顺利拿到Graph API的访问令牌。

第一步:完善SSO基础配置

首先确保你的MSAL和认证选项配置完整,这里要注意signInLink是机器人接收Teams授权回调的HTTPS端点,必须提前在你的机器人服务中配置好:

// 初始化MSAL客户端
IConfidentialClientApplication msal = ConfidentialClientApplicationBuilder.Create(config.AppId)
                                       .WithClientSecret(config.AppPassword)
                                       .WithTenantId(config.AppTenantId)
                                       .WithLegacyCacheCompatibility(false)
                                       .Build();

// 配置SSO的回调地址(替换成你的机器人域名对应的auth端点)
string signInLink = $"https://{config.BotDomain}/api/auth";

// 配置Graph API的认证方案,这里可根据需求添加权限范围
AuthenticationOptions<AppState> authOptions = new();
authOptions.AddAuthentication("graph", new TeamsSsoSettings(
    scopes: new string[] { "User.Read", "Mail.Read" }, // 按需添加Graph权限
    signInLink: signInLink,
    msalApp: msal
));

// 构建完整的应用实例
var app = new ApplicationBuilder<AppState>()
        .WithAIOptions(new(actionPlanner))
        .WithStorage(storage)
        .WithLoggerFactory(loggerFactory)
        .WithTurnStateFactory(() => new AppState())
        .WithAuthentication(authOptions)
        .Build();

第二步:添加授权回调端点

你需要在机器人的控制器中添加一个api/auth的路由,用来处理Teams的SSO授权回调:

[Route("api/auth")]
[ApiController]
public class AuthController : ControllerBase
{
    private readonly IAuthenticationService _authService;

    public AuthController(IAuthenticationService authService)
    {
        _authService = authService;
    }

    [HttpGet]
    public async Task<IActionResult> SignInAsync([FromQuery] string state)
    {
        // 交由Teams AI库处理授权逻辑
        var result = await _authService.HandleSignInAsync(HttpContext, "graph", state);
        return result;
    }
}

第三步:处理消息扩展的Action逻辑

接下来就是核心的消息扩展处理逻辑——判断用户授权状态,返回对应的响应:

// 注册你消息扩展中定义的Action处理函数(替换成你的Action ID)
app.AddMessageExtensionHandler(
    "your_action_id",
    async (turnContext, state, ct) =>
    {
        // 获取认证服务实例
        var authService = turnContext.TurnState.Get<IAuthenticationService>();
        if (authService == null)
        {
            throw new InvalidOperationException("认证服务未初始化");
        }

        try
        {
            // 尝试获取用户的Graph API访问令牌
            var tokenResult = await authService.GetUserTokenAsync(
                turnContext,
                "graph", // 对应之前配置的认证方案名称
                ct: ct
            );

            if (tokenResult.Succeeded && !string.IsNullOrEmpty(tokenResult.Token))
            {
                // ✅ 用户已授权,拿到令牌后调用Graph API
                var graphClient = new GraphServiceClient(
                    new DelegateAuthenticationProvider(request =>
                    {
                        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenResult.Token);
                        return Task.CompletedTask;
                    })
                );

                // 示例:调用Graph获取当前用户信息
                var user = await graphClient.Me.GetAsync(cancellationToken: ct);

                // 构建并返回任务自适应卡片
                return new TaskModuleResponse
                {
                    Task = new TaskModuleContinueResponse
                    {
                        Type = "continue",
                        Value = new TaskModuleTaskInfo
                        {
                            Title = $"欢迎回来,{user.DisplayName}!",
                            Width = "medium",
                            Height = "medium",
                            Card = new AdaptiveCard(new AdaptiveSchemaVersion(1, 0))
                            {
                                Body = new List<AdaptiveElement>
                                {
                                    new AdaptiveTextBlock { Text = "您已完成授权,可以继续操作", Size = AdaptiveTextSize.Medium },
                                    new AdaptiveTextBlock { Text = $"邮箱:{user.Mail}" }
                                }
                            }
                        }
                    }
                };
            }
            else
            {
                // ❌ 用户未授权,返回登录引导,让Teams弹出consent对话框
                return new TaskModuleResponse
                {
                    Task = new TaskModuleSignInResponse
                    {
                        Type = "signin",
                        Value = new TaskModuleSignInResponseValue
                        {
                            SignInLink = signInLink
                        }
                    }
                };
            }
        }
        catch (Exception ex)
        {
            // 记录异常日志,方便排查问题
            loggerFactory.CreateLogger("MessageExtensionHandler").LogError(ex, "处理消息扩展请求时发生错误");
            throw;
        }
    }
);

几个关键注意点

  • 权限配置:务必在Azure AD应用注册中添加你需要的Graph API权限(比如User.Read),如果是租户级权限,还需要管理员提前授予同意。
  • 令牌管理:Teams AI库会自动帮你处理令牌的缓存、刷新逻辑,不需要手动维护令牌生命周期。
  • HTTPS要求:signInLink必须是HTTPS地址,Teams不允许HTTP的回调端点。

这样配置后,用户触发消息扩展的Action时,系统会自动判断授权状态:未授权则弹出consent对话框,授权完成后自动回到任务卡片;已授权则直接加载卡片并调用Graph API。

备注:内容来源于stack exchange,提问作者YonF

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.17 08:09:40