Teams命令式Chat Bot的Azure AD SSO Token在Identity Server 4中免登录调用问题
问题分析与解决方案
核心问题根源
当前问题本质是Teams Bot获取的SSO Token无法直接被后端IdentityServer4识别,且后端配置的交互式OIDC流程不匹配Bot的服务端调用场景:
- Teams Bot的SSO Token受众(
aud)是Bot自身的Client ID,而非后端API或IdentityServer4的资源ID,后端无法验证该Token的有效性。 - 后端IdentityServer4配置的
ResponseType = "code"属于授权码流程,是交互式认证模式,依赖用户浏览器会话Cookie;但Bot是服务端调用,没有用户浏览器会话,因此添加Prompt="none"会触发AADSTS50058错误(无用户会话Cookie)。
正确实现流程:使用On-Behalf-Of(OBO)流程
要实现Bot携带用户身份调用后端API,需通过Azure AD的On-Behalf-Of流程,将Bot获取的用户SSO Token(用户针对Bot的Token)兑换为针对后端API的访问Token,再用这个Token调用后端API。
步骤1:配置Azure AD权限
- 在Bot的Azure AD应用注册中,添加后端API的委托权限(如
api://{backend-client-id}/access_as_user),并完成管理员同意授权。 - 在后端API的Azure AD应用注册中,暴露对应的API范围,确保Bot有权限申请该范围的Token。
步骤2:Bot中实现OBO Token兑换
使用Microsoft.Identity.Client库,将用户的SSO Token兑换为后端API的访问Token:
var confidentialClient = ConfidentialClientApplicationBuilder .Create("{bot-client-id}") .WithClientSecret("{bot-client-secret}") .WithAuthority(new Uri($"https://login.microsoftonline.com/{tenant-id}/v2.0")) .Build(); // userSsoToken是Teams Bot通过AuthPrompt获取的用户身份Token var result = await confidentialClient.AcquireTokenOnBehalfOf( new[] { "api://{backend-client-id}/access_as_user" }, // 后端API的权限范围 new UserAssertion(userSsoToken) ).ExecuteAsync(); // 拿到可用于调用后端API的访问Token var backendApiAccessToken = result.AccessToken;
步骤3:调整后端IdentityServer4配置
后端不需要再走Azure AD的交互式OIDC流程,改为直接验证Azure AD颁发的后端API Token:
方案1:在IdentityServer4中配置Azure AD作为身份源
.AddIdentityServer() .AddInMemoryClients(clients) .AddInMemoryIdentityResources(identityResources) .AddInMemoryApiScopes(apiScopes) .AddAzureAdIdentityProvider(options => { options.Authority = $"https://login.microsoftonline.com/{tenant-id}/v2.0"; options.ClientId = "{backend-client-id}"; options.ClientSecret = "{backend-client-secret}"; options.Scope = "api://{backend-client-id}/access_as_user"; });
方案2:直接在API中配置JWT验证
如果后端API不需要通过IdentityServer4中转,可直接验证Azure AD的Token:
.AddJwtBearer("AzureAD", options => { options.Authority = $"https://login.microsoftonline.com/{tenant-id}/v2.0"; options.Audience = "api://{backend-client-id}"; options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = $"https://sts.windows.net/{tenant-id}/", ValidateAudience = true, ValidAudience = "api://{backend-client-id}", ValidateLifetime = true }; });
常见误区修正
- 禁止直接将Bot的SSO Token传递给后端:Token受众不匹配,后端无法通过验证。
- 后端避免使用授权码流程处理Bot的服务端调用:授权码流程是交互式模式,依赖用户浏览器会话,完全不适合服务端到服务端的用户上下文调用。
内容的提问来源于stack exchange,提问作者CuriousBoy
相关产品推荐
相关产品推荐

