Webhook 不适合在高吞吐量方案中接收更改通知,或者当接收方无法公开可用的通知 URL 时。 或者,可以使用 Azure 事件中心。
可以使用Azure 事件中心高吞吐量方案的示例包括订阅大量资源集的应用程序、订阅频繁更改的资源的应用程序,以及跨大量组织订阅资源的多租户应用程序。
本文将指导你完成管理 Microsoft Graph 订阅的过程,以及如何通过 Azure 事件中心 接收更改通知。
重要
将来将弃用共享访问签名 (SAS) 对事件中心进行身份验证。 建议改为使用Microsoft Entra ID基于角色的访问控制 (RBAC) 对事件中心进行身份验证。
使用Azure 事件中心接收更改通知
Azure 事件中心是专为大规模部署而构建的常用实时事件引入和分发服务。 使用 Azure 事件中心接收更改通知与 Webhook 在某些方面有所不同,包括:
- 不依赖公开显示的通知 URL。 事件中心 SDK 将通知中继到应用程序。
- 无需恢复通知 URL 验证。 可忽略收到的验证消息。
- 需要预配事件中心。
- 需要预配 Azure 密钥保管库或将 Microsoft Graph 更改跟踪 服务添加到事件中心上的数据发送者角色。
设置Azure 事件中心身份验证
Azure 事件中心支持通过共享访问签名 (SAS) 或Microsoft Entra ID基于角色的访问控制 (RBAC) 进行身份验证。 有关详细信息,请参阅授权访问Azure 事件中心。
本部分演示如何在Azure 门户上使用Microsoft Entra ID基于角色的访问控制 (RBAC) 设置Azure 事件中心身份验证。
- 使用在 Azure 订阅中创建资源的权限登录到 Azure 门户。
- 选择“ 创建资源”,在搜索栏中键入 “事件中心 ”,然后选择“ 事件中心” 建议。
- 在“事件中心创建”页上,选择“ 创建”。
- 填写事件中心命名空间创建详细信息,然后选择“ 创建”。
- 预配事件中心命名空间后,转到命名空间的页面。
- 依次选择“ 事件中心 ”、“ + 事件中心”。
- 为新事件中心指定名称,然后选择“ 创建”。
- 创建事件中心后,转到“事件中心”命名空间,然后从边栏中选择“访问控制 (IAM) ”。
- 选择 “角色分配”。
- 选择“ + 添加 ”,然后选择“ 添加角色分配”。
- 在“角色”下,转到“作业职能角色”,选择“Azure 事件中心数据发送者”,然后选择“下一步”。
- 在“ 成员 ”选项卡下,选择“ 分配对用户、组或服务主体的访问权限”。
- 选择“+ 选择成员”,然后搜索并选择“Microsoft Graph 更改跟踪”。
- 选择“ 查看 + 分配 ”以完成该过程。
本部分演示如何通过 Azure CLI 使用共享访问签名 (SAS) 设置Azure 事件中心身份验证。
Azure CLI 允许在 Azure 中编写脚本并自动执行管理任务。 可以在本地计算机上安装 CLI 或直接从 Azure Cloud Shell 运行。
重要
将来将弃用共享访问签名 (SAS) 对事件中心进行身份验证。 建议改用Microsoft Entra ID基于角色的访问控制 (RBAC) 。 按照 指南迁移到 RBAC。
# --------------
# TODO: update the following values
#sets the name of the resource group
resourcegroup=rg-graphevents-dev
#sets the ___location of the resources
___location='uk south'
#sets the name of the Azure Event Hubs namespace
evhamespacename=evh-graphevents-dev
#sets the name of the hub under the namespace
evhhubname=graphevents
#sets the name of the access policy to the hub
evhpolicyname=grapheventspolicy
#sets the name of the Azure KeyVault
keyvaultname=kv-graphevents
#sets the name of the secret in Azure KeyVault that will contain the connection string to the hub
keyvaultsecretname=grapheventsconnectionstring
# --------------
az group create --___location $___location --name $resourcegroup
az eventhubs namespace create --name $evhamespacename --resource-group $resourcegroup --sku Basic --___location $___location
az eventhubs eventhub create --name $evhhubname --namespace-name $evhamespacename --resource-group $resourcegroup --partition-count 2 --message-retention 1
az eventhubs eventhub authorization-rule create --name $evhpolicyname --eventhub-name $evhhubname --namespace-name $evhamespacename --resource-group $resourcegroup --rights Send
evhprimaryconnectionstring=`az eventhubs eventhub authorization-rule keys list --name $evhpolicyname --eventhub-name $evhhubname --namespace-name $evhamespacename --resource-group $resourcegroup --query "primaryConnectionString" --output tsv`
az keyvault create --name $keyvaultname --resource-group $resourcegroup --___location $___location --enable-soft-delete true --sku standard --retention-days 90
az keyvault secret set --name $keyvaultsecretname --value $evhprimaryconnectionstring --vault-name $keyvaultname --output none
graphspn=`az ad sp list --display-name 'Microsoft Graph Change Tracking' --query "[].appId" --output tsv`
az keyvault set-policy --name $keyvaultname --resource-group $resourcegroup --secret-permissions get --spn $graphspn --output none
keyvaulturi=`az keyvault show --name $keyvaultname --resource-group $resourcegroup --query "properties.vaultUri" --output tsv`
domainname=`az ad signed-in-user show --query 'userPrincipalName' | cut -d '@' -f 2 | sed 's/\"//'`
notificationUrl="EventHub:${keyvaulturi}secrets/${keyvaultsecretname}?tenantId=${domainname}"
echo "Notification Url:\n${notificationUrl}"
注意:此处提供的脚本与基于 Linux 的 shell、Windows WSL 和 Azure Cloud Shell兼容。 它需要一些更新才能在 Windows shell 中运行。
本部分演示如何通过Azure 门户使用共享访问签名 (SAS) 设置Azure 事件中心身份验证。
重要
将来将弃用共享访问签名 (SAS) 对事件中心进行身份验证。 建议改用Microsoft Entra ID基于角色的访问控制 (RBAC) 。 按照 指南迁移到 RBAC。
在本部分中,你将:
- 创建事件中心命名空间。
- 将中心添加到该命名空间以中继和传递通知。
- 添加共享访问策略,使你能够将连接字符串到新创建的中心。
步骤:
- 使用在 Azure 订阅中创建资源的权限登录到 Azure 门户。
- 选择“ 创建资源”,在搜索栏中键入 “事件中心 ”,然后选择“ 事件中心” 建议。
- 在“事件中心创建”页上,选择“ 创建”。
- 填写事件中心命名空间创建详细信息,然后选择“ 创建”。
- 预配事件中心命名空间后,转到命名空间的页面。
- 依次选择“ 事件中心 ”、“ + 事件中心”。
- 为新事件中心指定名称,然后选择“ 创建”。
- 创建事件中心后,选择事件中心的名称,然后选择 “共享访问策略 ”和“ + 添加” 以添加新策略。
- 为策略命名,检查发送,然后选择“创建”。
- 创建策略后,选择策略的名称以打开详细信息面板,然后复制 “连接字符串-主键 ”值。 记录值;下一步需要它。
为了安全地访问事件中心并允许密钥轮换,Microsoft Graph 通过 Azure 密钥保管库 获取事件中心的连接字符串。
在本部分中,你将:
- 创建用于存储机密的 Azure 密钥保管库。
- 将连接字符串作为机密添加到事件中心。
- 为 Microsoft Graph 添加访问策略以访问密钥。
步骤:
- 使用在 Azure 订阅中创建资源的权限登录到 Azure 门户。
- 选择“创建资源”,在搜索栏中键入“密钥保管库”,然后选择密钥保管库建议。
- 在“密钥保管库创建”页上,选择“创建”。
- 填写密钥保管库创建详细信息,然后选择“查看 + 创建并创建”。
- 使用通知中的“转到资源”来转到新创建的密钥保管库。
- 复制 DNS 名称;本文稍后会用到它。
- 转到 “机密 ”,然后选择“ + 生成/导入”。
- 为机密指定一个名称,并保留该名称以供以后使用;本文稍后会用到它。 对于该值,请粘贴在“事件中心”步骤中生成的连接字符串。 选择“创建”。
- 依次选择“ 访问策略 ”、“ + 添加访问策略”。
- 对于“密钥权限”,选择“获取”;对于“选择主体”,选择“Microsoft Graph 更改跟踪”。 选择“添加”。
创建订阅并接收通知
创建所需的 Azure KeyVault 和Azure 事件中心服务后,现在可以创建更改通知订阅,并开始通过Azure 事件中心接收更改通知。
创建订阅
使用事件中心创建订阅以接收更改通知与创建 Webhook 订阅几乎完全相同,但 notificationUrl 属性中进行了重要更改。 在继续操作之前,请先查看 Webhook 订阅创建步骤 。
创建订阅时, notificationUrl 必须指向事件中心位置。
如果使用基于角色的访问控制, 则 notificationUrl 属性如下所示:
EventHub:https://<eventhubnamespace>.servicebus.windows.net/eventhubname/<eventhubname>?tenantId=<domainname>
-
<eventhubnamespace>
是提供给事件中心命名空间的名称。 可以在“事件中心概述”页的“主机名”下找到它。
-
<eventhubname>
是提供给事件中心的名称。 可以在事件中心 - 概述 ->> 事件中心中找到它。
-
<domainname>
是租户的名称;例如 。 contoso.com
由于此域用于访问Azure 事件中心,因此它必须匹配保留Azure 事件中心的 Azure 订阅使用的域。 若要获取此信息,请选择Azure 门户上的“Microsoft Entra ID”菜单,检查“概述”页。 域名显示在 “主域”下。
如果使用 密钥保管库,则 notificationUrl 属性如下所示:EventHub:https://<azurekeyvaultname>.vault.azure.net/secrets/<secretname>?tenantId=<domainname>
,并具有以下值:
-
<azurekeyvaultname>
- 在创建期间为密钥保管库提供的名称。 可以在 DNS 名称中找到它。
-
<secretname>
- 在创建过程中为机密提供的名称。 可以在 Azure 密钥保管库 机密页上找到它。
-
<domainname>
- 租户的名称;例如 。 contoso.com
由于此域用于访问 Azure 密钥保管库,因此它必须匹配持有 Azure 密钥保管库的 Azure 订阅使用的域。 若要获取此信息,可以转到创建的 Azure 密钥保管库的概述页,然后选择订阅。 域名将显示在“目录”字段下。
注意
不允许重复订阅。 当订阅请求包含与现有订阅包含的 changeType 和 资源 相同的值时,请求失败并显示 HTTP 错误代码 409 Conflict
和错误消息 Subscription Id <> already exists for the requested combination
。
将事件中心身份验证迁移到 Microsoft Entra ID RBAC
将来将弃用共享访问签名 (SAS) 对事件中心进行身份验证。 建议改为使用Microsoft Entra ID基于角色的访问控制 (RBAC) 对事件中心进行身份验证。
本部分介绍如何使用 SAS 身份验证将现有事件中心迁移到Microsoft Entra ID RBAC 身份验证。
通过 Azure CLI 或 Azure 门户使用与 SAS 身份验证相同的事件中心命名空间。
- 在用于现有订阅的同一事件中心命名空间下,创建新的事件中心。
- 创建一个新订阅,其详细信息与现有订阅相同,但使用 URL 中上一步中新事件中心的名称除外。 有关详细信息,请参阅 创建订阅:使用 RBAC。
你将在新事件中心收到通知。 可以通过检查事件中心的 “消息” 图表来验证流量是否类似于旧订阅。 此外,验证接收通知时是否有任何错误或失败。
验证是否收到通知,并且新事件中心正常工作后,可以删除旧订阅、旧事件中心和基于 SAS 的身份验证,然后开始使用新订阅。
接收通知
更改通知现在由事件中心传递到应用程序。 有关详细信息,请参阅事件中心文档中的接收事件。
在应用程序中接收通知之前,需要创建另一个具有“侦听”权限的共享访问策略并获取连接字符串,类似于配置事件中心中列出的步骤。
提示
为侦听事件中心消息的应用程序创建单独的策略,而不是重用在 Azure KeyVault 中设置的相同连接字符串。 这种分离遵循最小特权原则,确保解决方案的每个组件仅具有所需的权限。
处理验证通知
每当应用程序创建新订阅时,它都会收到验证通知。 应忽略这些通知。 下面的示例表示验证消息的正文。
{
"value":[
{
"subscriptionId":"NA",
"subscriptionExpirationDateTime":"NA",
"clientState":"NA",
"changeType":"Validation: Testing client application reachability for subscription Request-Id: 522a8e7e-096a-494c-aaf1-ac0dcfca45b7",
"resource":"NA",
"resourceData":{
"@odata.type":"NA",
"@odata.id":"NA",
"id":"NA"
}
}
]
}
具有大型有效负载的丰富通知的订阅
事件中心的最大消息大小为 1 MB。 使用 丰富通知时,可能会收到超过此限制的通知。 若要通过事件中心接收大于 1 MB 的通知,还必须向订阅请求添加 Blob 存储帐户。
设置存储并创建订阅
-
创建存储帐户。
-
在存储帐户中创建容器。 容器名称必须设置为
microsoft-graph-change-notifications
。
-
检索存储帐户访问密钥或连接字符串。
- 将连接字符串添加到密钥保管库,并为其命名。 此值是机密名称。
- 创建或重新创建订阅,现在使用以下语法包括 blobStoreUrl 属性:
blobStoreUrl: "https://<azurekeyvaultname>.vault.azure.net/secrets/<secretname>?tenantId=<domainname>"
接收丰富通知
当事件中心收到大于 1 MB 的通知有效负载时,通知不包含丰富通知中包含的 resource、 resourceData 和 encryptedContent 属性。 通知将改为包含一个 附加的PayloadStorageId 属性,该属性的 ID 指向存储这些属性的存储帐户中的 Blob。
如果缺少 Microsoft Graph 更改跟踪 应用程序,该怎么办?
租户中可能缺少 Microsoft Graph 更改跟踪 服务主体,具体取决于租户的创建时间和管理操作。 服务主体的全局唯一 appId 为 0bf30f3b-4a52-48df-9a82-234910c4a086
,你可以运行以下查询来确认它是否存在于租户中。
GET https://graph.microsoft.com/v1.0/servicePrincipals(appId='0bf30f3b-4a52-48df-9a82-234910c4a086')
// Code snippets are only available for the latest version. Current version is 5.x
// To initialize your graphClient, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=csharp
var result = await graphClient.ServicePrincipalsWithAppId("{appId}").GetAsync();
请阅读 SDK 文档,了解如何将 SDK 添加到项目并创建 authProvider 实例的详细信息。
// Code snippets are only available for the latest major version. Current major version is $v1.*
// Dependencies
import (
"context"
msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go"
//other-imports
)
// To initialize your graphClient, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=go
appId := "{appId}"
servicePrincipals, err := graphClient.ServicePrincipalsWithAppId(&appId).Get(context.Background(), nil)
请阅读 SDK 文档,了解如何将 SDK 添加到项目并创建 authProvider 实例的详细信息。
// Code snippets are only available for the latest version. Current version is 6.x
GraphServiceClient graphClient = new GraphServiceClient(requestAdapter);
ServicePrincipal result = graphClient.servicePrincipalsWithAppId("{appId}").get();
请阅读 SDK 文档,了解如何将 SDK 添加到项目并创建 authProvider 实例的详细信息。
<?php
use Microsoft\Graph\GraphServiceClient;
$graphServiceClient = new GraphServiceClient($tokenRequestContext, $scopes);
$result = $graphServiceClient->servicePrincipalsWithAppId('{appId}', )->get()->wait();
请阅读 SDK 文档,了解如何将 SDK 添加到项目并创建 authProvider 实例的详细信息。
# Code snippets are only available for the latest version. Current version is 1.x
from msgraph import GraphServiceClient
# To initialize your graph_client, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=python
result = await graph_client.service_principals_with_app_id("{appId}").get()
请阅读 SDK 文档,了解如何将 SDK 添加到项目并创建 authProvider 实例的详细信息。
如果服务主体不存在,请按如下所示创建它。 必须向调用应用授予 Application.ReadWrite.All 权限才能运行此操作。
方法 1
POST https://graph.microsoft.com/v1.0/servicePrincipals
Content-type: application/json
{
"appId": "0bf30f3b-4a52-48df-9a82-234910c4a086"
}
// Code snippets are only available for the latest version. Current version is 5.x
// Dependencies
using Microsoft.Graph.Models;
var requestBody = new ServicePrincipal
{
AppId = "0bf30f3b-4a52-48df-9a82-234910c4a086",
};
// To initialize your graphClient, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=csharp
var result = await graphClient.ServicePrincipals.PostAsync(requestBody);
请阅读 SDK 文档,了解如何将 SDK 添加到项目并创建 authProvider 实例的详细信息。
mgc service-principals create --body '{\
"appId": "0bf30f3b-4a52-48df-9a82-234910c4a086"\
}\
'
请阅读 SDK 文档,了解如何将 SDK 添加到项目并创建 authProvider 实例的详细信息。
// Code snippets are only available for the latest major version. Current major version is $v1.*
// Dependencies
import (
"context"
msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go"
graphmodels "github.com/microsoftgraph/msgraph-sdk-go/models"
//other-imports
)
requestBody := graphmodels.NewServicePrincipal()
appId := "0bf30f3b-4a52-48df-9a82-234910c4a086"
requestBody.SetAppId(&appId)
// To initialize your graphClient, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=go
servicePrincipals, err := graphClient.ServicePrincipals().Post(context.Background(), requestBody, nil)
请阅读 SDK 文档,了解如何将 SDK 添加到项目并创建 authProvider 实例的详细信息。
// Code snippets are only available for the latest version. Current version is 6.x
GraphServiceClient graphClient = new GraphServiceClient(requestAdapter);
ServicePrincipal servicePrincipal = new ServicePrincipal();
servicePrincipal.setAppId("0bf30f3b-4a52-48df-9a82-234910c4a086");
ServicePrincipal result = graphClient.servicePrincipals().post(servicePrincipal);
请阅读 SDK 文档,了解如何将 SDK 添加到项目并创建 authProvider 实例的详细信息。
const options = {
authProvider,
};
const client = Client.init(options);
const servicePrincipal = {
appId: '0bf30f3b-4a52-48df-9a82-234910c4a086'
};
await client.api('/servicePrincipals')
.post(servicePrincipal);
请阅读 SDK 文档,了解如何将 SDK 添加到项目并创建 authProvider 实例的详细信息。
<?php
use Microsoft\Graph\GraphServiceClient;
use Microsoft\Graph\Generated\Models\ServicePrincipal;
$graphServiceClient = new GraphServiceClient($tokenRequestContext, $scopes);
$requestBody = new ServicePrincipal();
$requestBody->setAppId('0bf30f3b-4a52-48df-9a82-234910c4a086');
$result = $graphServiceClient->servicePrincipals()->post($requestBody)->wait();
请阅读 SDK 文档,了解如何将 SDK 添加到项目并创建 authProvider 实例的详细信息。
Import-Module Microsoft.Graph.Applications
$params = @{
appId = "0bf30f3b-4a52-48df-9a82-234910c4a086"
}
New-MgServicePrincipal -BodyParameter $params
请阅读 SDK 文档,了解如何将 SDK 添加到项目并创建 authProvider 实例的详细信息。
# Code snippets are only available for the latest version. Current version is 1.x
from msgraph import GraphServiceClient
from msgraph.generated.models.service_principal import ServicePrincipal
# To initialize your graph_client, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=python
request_body = ServicePrincipal(
app_id = "0bf30f3b-4a52-48df-9a82-234910c4a086",
)
result = await graph_client.service_principals.post(request_body)
请阅读 SDK 文档,了解如何将 SDK 添加到项目并创建 authProvider 实例的详细信息。
方法 2
POST https://graph.microsoft.com/v1.0/servicePrincipals(appId='0bf30f3b-4a52-48df-9a82-234910c4a086')
Content-type: application/json
Prefer: create-if-missing
{
"displayName": "Microsoft Graph Change Tracking"
}
相关内容