Microsoft Graph API无交互获取全员Teams状态的C#实现疑问
实现无交互获取Teams员工状态的解决方案
可以实现,但需要使用Microsoft Graph的委派权限+无交互认证流,因为Teams用户状态(Presence)API目前仅支持委派权限,应用权限流确实无法调用该接口,以下是具体实现步骤和注意事项:
一、权限配置
- 在Azure AD应用注册中添加Microsoft Graph的委派权限
Presence.Read.All - 要求租户管理员对该权限进行租户级同意(因为需要读取所有员工的状态,属于高权限范围)
二、无交互认证方式选择
根据公司的MFA策略选择合适的认证流:
1. 用户名密码流(ROPC)—— 完全无交互(仅适用于未启用MFA的用户)
该流允许应用使用服务账号的用户名和密码直接获取令牌,无需用户交互,但不支持启用MFA的账号,适合公司内部无MFA的服务账号场景。
2. 刷新令牌复用—— 首次交互后无交互
如果公司强制MFA,可先通过设备码流完成一次交互式认证,获取并保存刷新令牌,后续使用刷新令牌无交互获取新的访问令牌。
三、C#代码实现(使用Microsoft Graph SDK)
首先安装必要的NuGet包:
Install-Package Microsoft.Graph Install-Package Microsoft.Identity.Client
1. ROPC流示例
using Microsoft.Graph; using Microsoft.Identity.Client; using System.Collections.Generic; using System.Threading.Tasks; class TeamsPresenceTool { static async Task Main(string[] args) { var clientId = "你的Azure应用ID"; var tenantId = "你的租户ID"; var serviceUsername = "内部服务账号用户名"; var servicePassword = "内部服务账号密码"; var targetUserIds = new List<string> { "员工ID1", "员工ID2" }; // 初始化认证客户端 var pca = PublicClientApplicationBuilder .Create(clientId) .WithTenantId(tenantId) .Build(); // 获取访问令牌 var scopes = new[] { "https://graph.microsoft.com/Presence.Read.All" }; var authResult = await pca.AcquireTokenByUsernamePassword(scopes, serviceUsername, servicePassword).ExecuteAsync(); // 初始化Graph客户端 var graphClient = new GraphServiceClient( new DelegateAuthenticationProvider(request => { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authResult.AccessToken); return Task.CompletedTask; })); // 批量获取用户状态 var presenceRequest = new GetPresencesByUserIdsRequest { UserIds = targetUserIds }; var presences = await graphClient.Communications.GetPresencesByUserIds(presenceRequest).Request().PostAsync(); // 处理返回结果 foreach (var presence in presences.Value) { Console.WriteLine($"用户{presence.Id}状态:{presence.Availability} - {presence.Activity}"); } } }
2. 刷新令牌复用示例
using Microsoft.Graph; using Microsoft.Identity.Client; using System.Threading.Tasks; class TeamsPresenceTool { // 从安全存储中读取之前保存的刷新令牌 private const string SavedRefreshToken = "你的刷新令牌"; static async Task Main(string[] args) { var clientId = "你的Azure应用ID"; var tenantId = "你的租户ID"; var pca = PublicClientApplicationBuilder .Create(clientId) .WithTenantId(tenantId) .Build(); var scopes = new[] { "https://graph.microsoft.com/Presence.Read.All" }; AuthenticationResult authResult; // 使用刷新令牌获取新的访问令牌(无交互) try { authResult = await pca.AcquireTokenByRefreshToken(scopes, SavedRefreshToken).ExecuteAsync(); } catch (MsalUiRequiredException) { // 刷新令牌过期,需要重新交互式认证(仅需一次) authResult = await pca.AcquireTokenWithDeviceCode(scopes, deviceCode => { Console.WriteLine(deviceCode.Message); return Task.CompletedTask; }).ExecuteAsync(); // 将authResult.RefreshToken保存到安全位置,比如Azure Key Vault或本地加密文件 } // 后续调用Graph API的逻辑同ROPC示例 var graphClient = new GraphServiceClient( new DelegateAuthenticationProvider(request => { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authResult.AccessToken); return Task.CompletedTask; })); } }
四、关键注意事项
- Microsoft Graph的Presence API不支持应用权限流,无论添加何种应用权限都无法调用,必须使用委派权限
Presence.Read.All权限需要租户管理员同意,否则会返回权限不足的错误- ROPC流存在安全风险,仅建议在内部受信任的工具中使用,且避免用于个人用户账号
- 如果启用MFA,刷新令牌复用是更合规的无交互方案,首次认证后即可长期无交互运行
内容的提问来源于stack exchange,提问作者Peppi
相关产品推荐
相关产品推荐

