如何通过MS Graph API配置Teams用户呼叫转接策略
概要
用于设置Teams用户呼叫转接策略的MS Graph API是什么?
问题背景
当前正在将基于Lync/Skype的.NET应用迁移至Teams平台,Teams侧开发需求为配置指定用户的呼叫转接偏好。这类用户均启用了直连路由(Direct Routing),拨打固定PSTN/分机号码时,呼叫会转接至用户的移动终端;转接目标的移动号码需根据值班排班动态调整,由程序自动匹配当前值班人员完成配置。
已尝试的方案
- 已完成MS Graph API的身份认证对接
- 已知TAC扩展可实现该功能
- 已知存在对应PowerShell扩展模块可实现该功能,对应cmdlet为
Set-CsUserCallingSettings - 已有其他开发者提出同类问题,但相关讨论帖均未给出最终可行解决方案
Call-Redirect接口不符合需求,该接口需要主动监听呼叫实例,不适用于静态配置用户呼叫转接规则的场景- 官方Teams相关脚本仓库未提供对应实现源码
- 暂未对PowerShell扩展模块做反射分析
- MS Graph Beta版本的
user settings接口仅支持排班相关配置,不支持呼叫转接规则设置
备选方案
- 通过PowerShell SDK调用对应cmdlet实现,但该方案实现方式较为老旧,不作为优先选型
2022-06-20更新进展
- 开始对PowerShell模块做反射分析,初步定位到对应接口地址格式为
https://api.interfaces.records.teams.microsoft.com/Skype.VoiceGroup/userRoutingSettings/{userId} - Teams用户ID可通过官方接口获取
- Teams部分功能仍依赖旧版REST API实现
2022-06-30更新进展
目前已整理出可优化的概念验证(POC)代码如下(后续将常规AcquireTokenOnBehalfOf认证逻辑整合后,会作为答案补充):
Imports System.IO Imports Microsoft.Identity.Client Imports System.Globalization Imports System.Net.Http Imports System.Text Imports System.Net.Http.Headers Imports System.Net Imports Newtonsoft.Json Imports System.IdentityModel.Tokens.Jwt Public Class LyncTest Public Shared Sub Test() Dim InstanceId As String = "https://login.microsoftonline.com/" Dim RedirectURI As String = "https://login.microsoftonline.com/common/oauth2/nativeclient" ' 以下ID、密钥信息可在Azure应用注册页面获取 Dim TenantId As String = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" Dim AppId As String = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" Dim secretVal As String = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" Dim username As String = "xxxxxxx.xxxxxx@xxxxxxxxxxxx.com" Dim password As String = "xxxxxxxxxxxx" ' Teams接口权限范围 Dim scope As String = "48ac35b8-9aa8-4d74-927d-1f4a14a0b239/.default" Dim httpClient = New HttpClient() ' 发起资源所有者密码凭据流认证 Dim baseParam As String = $"client_id={AppId}" & $"&username={WebUtility.UrlEncode(username)}" & $"&password={WebUtility.UrlEncode(password)}" & $"&grant_type=password" & $"&client_secret={WebUtility.UrlEncode(secretVal)}" & $"&scope={scope}" ' 获取user_impersonation权限的访问令牌 Dim tokenReq As New HttpRequestMessage(HttpMethod.Post, $"https://login.microsoftonline.com/{TenantId}/oauth2/v2.0/token") With { .Content = New StringContent(baseParam, Encoding.UTF8, "application/x-www-form-urlencoded") } Dim TokenRes As HttpResponseMessage = httpClient.SendAsync(tokenReq).Result Dim TokenObj As GraphToken = JsonConvert.DeserializeObject(Of GraphToken)(TokenRes.Content.ReadAsStringAsync.Result()) Dim JwtReader As New JwtSecurityTokenHandler Dim JwtToken As JwtSecurityToken = JwtReader.ReadToken(TokenObj.AccessToken) Dim UserOid As String = JwtToken.Payload("oid") ' 配置用户呼叫路由规则 Dim RoutingURL As String = $"https://api.interfaces.records.teams.microsoft.com/Skype.VoiceGroup/userRoutingSettings/{UserOid}" httpClient.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", TokenObj.AccessToken) Dim RoutingJSON As String = "{""sipUri"":""sip:andreas.beeker@kraiburg-tpe.com""," & """forwardingSettings"":{""isEnabled"":false,""forwardingType"":""Simultaneous"",""targetType"":""Unknown"",""target"":""""}," & """unansweredSettings"":{""isEnabled"":true,""targetType"":""SingleTarget"",""target"":""+491701234567"",""delay"":""00:00:20""}," & """callGroupDetails"":{""targets"":[],""order"":""Simultaneous""},""callGroupMembershipSettings"":{""callGroupMembershipDetails"":[]}}" Dim RoutingReq As New HttpRequestMessage(HttpMethod.Post, RoutingURL) With { .Content = New StringContent(RoutingJSON, Encoding.UTF8, "application/json") } Dim RoutingRes As HttpResponseMessage = httpClient.SendAsync(RoutingReq).Result Console.WriteLine(If(RoutingRes.IsSuccessStatusCode, "success", "failed")) End Sub Public Class GraphToken <JsonProperty(PropertyName:="access_token")> Public Property AccessToken As String <JsonProperty(PropertyName:="expires_in")> Public Property ExpiresIn As Integer <JsonProperty(PropertyName:="ext_expires_in")> Public Property ExpiresInExt As Integer <JsonProperty(PropertyName:="scope")> Public Property Scope As String <JsonProperty(PropertyName:="token_type")> Public Property TokenType As String End Class End Class
内容的提问来源于stack exchange,提问作者kiwiwings
相关产品推荐
相关产品推荐

