Мы используем веб-перехватчики Microsoft Graph (бета-версия), чтобы получать уведомления об изменениях присутствия в Microsoft Teams, и в настоящее время у нашего клиента есть проблема. Когда мы получаем уведомление об изменении присутствия от Graph API, оно не содержит свойства validationTokens
, поэтому проверка и последующая обработка завершаются неудачей. Наш код похож на образец предоставлен Microsoft.
Содержание полученного запроса у заказчика (упрощенное/сокращенное) выглядит следующим образом:
{
"value": [
{
"subscriptionId": "...",
"clientState": "...",
"changeType": "updated",
"resource": "communications/presences?$filter=id+in+(...)",
"subscriptionExpirationDateTime": "2021-04-22T02:06:56.2872368-07:00",
"resourceData": {
"@odata.id": "communications/presences?$filter=id+in+(...)",
"@odata.type": "#Microsoft.Graph.presence",
"id": "..."
},
"tenantId": "...",
"encryptedContent": {
"data": "...",
"dataSignature": "...",
"dataKey": "...",
"encryptionCertificateId": "3",
"encryptionCertificateThumbprint": "..."
}
}
]
}
По сравнению с нашей лабораторией в теле запроса отсутствует свойство validationTokens
:
{
"value": [
{
"subscriptionId": "...",
"clientState": "...",
"changeType": "updated",
"resource": "communications/presences?$filter=id+in+(...)",
"subscriptionExpirationDateTime": "2021-04-26T00:07:08.9251516-07:00",
"resourceData": {
"@odata.id": "communications/presences?$filter=id+in+(...)",
"@odata.type": "#Microsoft.Graph.presence",
"id": "..."
},
"tenantId": "...",
"encryptedContent": {
"data": "...",
"dataSignature": "...",
"dataKey": "...",
"encryptionCertificateId": "3",
"encryptionCertificateThumbprint": "..."
}
}
],
"validationTokens": [
"..."
]
}
Согласно документу. , validationTokens
предоставляются только для уведомлений об изменениях с данными о ресурсах — что здесь имеет место, поэтому мы предполагаем, что validationTokens
должен присутствовать?
Любые подсказки приветствуются.
Изменить Вот сокращенный код, используемый для десериализации тела запроса/обработки запроса уведомления:
<HttpPost("/Notification/{connectorId}/{apiLinkId}")>
Public Async Function Listen(connectorId As Guid, apiLinkId As Guid, <FromQuery> Optional validationToken As String = Nothing) As Task(Of IActionResult)
If Not String.IsNullOrEmpty(validationToken) Then
' Validate the new subscription by sending the token back to Microsoft Graph.
' This response is required for each subscription.
Return Content(WebUtility.HtmlEncode(validationToken))
End If
Try
' Parse the received notifications.
Dim options As New JsonSerializerOptions With {.PropertyNameCaseInsensitive = True}
options.Converters.Add(New JsonStringEnumConverter(JsonNamingPolicy.CamelCase))
Dim plainNotifications As New Dictionary(Of String, ChangeNotification)()
Dim notificationCollection = Await JsonSerializer.DeserializeAsync(Of ChangeNotificationCollection)(Request.Body, options)
notificationCollection.Value _
.Where(Function(x) x.EncryptedContent Is Nothing) _
.ForEach(Sub(notification)
Dim subscription = Stores.TeamsPresenceSubscriptionStore.Instance.GetValueOrDefault(notification.SubscriptionId.Value)
' Verify the current client state matches the one that was sent.
If subscription Is Nothing OrElse notification.ClientState <> subscription.SecretClientState Then
Log.msg(Category.TEAMS, "Error: Failed to verify notification")
Return
End If
' Just keep the latest notification for each resource. No point pulling data more than once.
plainNotifications(notification.Resource) = notification
End Sub)
If plainNotifications.Count > 0 Then
' Query for the changed messages
GetChangedMessages(plainNotifications.Values)
End If
If notificationCollection.ValidationTokens IsNot Nothing AndAlso notificationCollection.ValidationTokens.Any() Then
' -> notificationCollection.ValidationTokens is not set at the customer
End If
Catch ex As Exception
' Still return a 202 so the service doesn't resend the notification.
End Try
Return Accepted()
End Function
Код для создания подписки
Subscription = graphApi.Client.Subscriptions.Request().AddAsync(New Subscription() With
{
.Resource = $"/communications/presences?$filter=id in ({String.Join(",", userIds.Select(Function(id) $"'{id}'"))})",
.ChangeType = "updated",
.NotificationUrl = $"{publicNotificationEndpoint}/Notification/{connectorid}/{Me.GraphApi.Link.Id}",
.LifecycleNotificationUrl = $"{publicNotificationEndpoint}/LifecycleNotification/{connectorid}/{Me.GraphApi.Link.Id}",
.ClientState = SecretClientState,
.ExpirationDateTime = DateTime.UtcNow.Add(MAX_SUBSCRIPTION_LIFETIME),
.EncryptionCertificate = Convert.ToBase64String(encryptionCertificate.Export(X509ContentType.Cert)),
.EncryptionCertificateId = encryptionCertificate.Version.ToString(),
.IncludeResourceData = True
}).Result