Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
O Microsoft Graph permite que os aplicativos assinem e recebam notificações sobre alterações nos recursos. Este artigo explica como configurar notificações avançadas, que incluem dados de recursos diretamente no conteúdo da notificação.
As notificações avançadas eliminam a necessidade de chamadas à API extras para obter recursos atualizados, tornando mais rápida e fácil a execução da lógica de negócios.
Recursos com suporte
Notificações avançadas estão disponíveis para os seguintes recursos.
Observação
As notificações avançadas para assinaturas de pontos de extremidade marcados com um asterisco (*) só estão disponíveis no /beta ponto de extremidade.
| Recurso | Caminhos de recursos com suporte | Limitações |
|---|---|---|
| Copilot aiInteraction | Interações de IA do Copilot das quais um determinado usuário faz parte: copilot/users/{userId}/interactionHistory/getAllEnterpriseInteractions Interações de IA do Copilot em uma organização: copilot/interactionHistory/getAllEnterpriseInteractions |
Cotas máximas de assinaturas:
|
| Evento do Outlook | Alterações em todos os eventos na caixa de correio de um usuário: /users/{id}/events |
Requer $select o retorno de apenas um subconjunto de propriedades na notificação avançada. Para obter mais informações, consulte Alterar notificações para recursos do Outlook. |
| Mensagem do Outlook | Alterações em todas as mensagens na caixa de correio de um usuário: /users/{id}/messages Alterações nas mensagens na caixa de entrada de um usuário: /users/{id}/mailFolders/{id}/messages |
Requer $select o retorno de apenas um subconjunto de propriedades na notificação avançada. Para obter mais informações, consulte Alterar notificações para recursos do Outlook. |
| Contato pessoal do Outlook | Alterações em todos os contatos pessoais na caixa de correio de um usuário: /users/{id}/contacts Alterações em todos os contatos pessoais no contactFolder de um usuário: /users/{id}/contactFolders/{id}/contacts |
Requer $select o retorno de apenas um subconjunto de propriedades na notificação avançada. Para obter mais informações, consulte Alterar notificações para recursos do Outlook. |
| CallRecording do Teams | Todas as gravações em uma organização: communications/onlineMeetings/getAllRecordings Todas as gravações de uma reunião específica: communications/onlineMeetings/{onlineMeetingId}/recordings Uma gravação de chamada que se torna disponível em uma reunião organizada por um usuário específico: users/{id}/onlineMeetings/getAllRecordings Uma gravação de chamada que se torna disponível em uma reunião em que um determinado aplicativo do Teams está instalado: appCatalogs/teamsApps/{id}/installedToOnlineMeetings/getAllRecordings * |
Cotas máximas de assinaturas:
|
| Transcrição de chamada do Teams | Todas as transcrições em uma organização: communications/onlineMeetings/getAllTranscripts Todas as transcrições de uma reunião específica: communications/onlineMeetings/{onlineMeetingId}/transcripts Uma transcrição de chamada que fica disponível em uma reunião organizada por um usuário específico: users/{id}/onlineMeetings/getAllTranscripts Uma transcrição de chamada que fica disponível em uma reunião em que um determinado aplicativo do Teams está instalado: appCatalogs/teamsApps/{id}/installedToOnlineMeetings/getAllTrancripts * |
Cotas máximas de assinaturas:
|
| Canal do Teams | Alterações nos canais em todas as equipes: /teams/getAllChannelsAlterações no canal em uma equipe específica: /teams/{id}/channels |
- |
| Chat do Teams | Alterações em qualquer chat no locatário: /chatsAlterações em um chat específico: /chats/{id} |
- |
| Teams chatMessage | Alterações nas mensagens de chat em todos os canais em todas as equipes: /teams/getAllMessagesAlterações nas mensagens de chat em um canal específico: /teams/{id}/channels/{id}/messagesAlterações nas mensagens de chat em todos os chats: /chats/getAllMessagesAlterações nas mensagens de chat em um chat específico: /chats/{id}/messagesAlterações nas mensagens de chat em todos os chats dos quais um determinado usuário faz parte: /users/{id}/chats/getAllMessages |
Não dá suporte ao uso $select para retornar apenas propriedades selecionadas. A notificação avançada consiste em todas as propriedades da instância alterada. |
| conversationMember do Teams | Alterações na associação de uma equipe específica: /teams/{id}/membersAlterações na associação em todas as equipes no locatário: /teams/getAllMembersAlterações na associação em todos os canais de uma equipe específica: /teams/{id}/channels/getAllMembersAlterações na associação de todos os canais em todo o locatário: /teams/getAllChannels/getAllMembersAlterações na associação em um chat específico: /chats/{id}/members Alterações na assinatura de todos os chats do Teams: /chats/getAllMembers |
Não dá suporte ao uso $select para retornar apenas propriedades selecionadas. A notificação avançada consiste em todas as propriedades da instância alterada. |
| Teams onlineMeeting * | Alterações em uma reunião online: /communications/onlineMeetings(joinWebUrl='{encodedJoinWebUrl}')/meetingCallEvents * |
Não dá suporte ao uso $select para retornar apenas propriedades selecionadas. A notificação avançada consiste em todas as propriedades da instância alterada. Uma assinatura permitida por aplicativo por reunião online. Para obter mais informações, consulte Obter notificações de alteração para atualizações de eventos de chamada de reunião do Microsoft Teams. |
| Teams presença | Alterações na presença de um único usuário: /communications/presences/{id} Alterações na presença de vários usuários: /communications/presences?$filter=id in ({id},{id}...) |
A assinatura para a presença de vários usuários é limitada a 650 usuários distintos. Não dá suporte ao uso $select para retornar apenas propriedades selecionadas. A notificação avançada consiste em todas as propriedades da instância alterada. Uma assinatura permitida por aplicativo por usuário delegado. Para obter mais informações, consulte Obter notificações de alteração para atualizações de presença no Microsoft Teams. |
| Equipe do Teams | Alterações em qualquer equipe no locatário: /teamsAlterações em uma equipe específica: /teams/{id} |
- |
Dados de recursos na carga de notificação
As notificações avançadas incluem dados de recursos com estes detalhes:
- A ID e o tipo da instância de recurso alterada, encontrados na propriedade resourceData .
- Todos os valores de propriedade da instância do recurso, criptografados conforme especificado na assinatura, encontrados na propriedade encryptedContent .
- Propriedades específicas do recurso, dependendo do recurso ou se solicitado usando um
$selectparâmetro na URL do recurso da assinatura.
Configuração do aplicativo para notificações
Antes de criar uma assinatura com dados de recurso, configure o acesso ao aplicativo para o objeto principal de serviço que representa o par locatário-aplicativo definindo a propriedade appRoleAssignmentRequired da seguinte maneira:
- [Recomendado] Definindo-o como
false. Saiba como configurar esta propriedade. - Como alternativa, se a propriedade precisar permanecer
true, atribua explicitamente à entidade de serviço de Controle de Alterações do Microsoft Graph (appId é0bf30f3b-4a52-48df-9a82-234910c4a086) uma função de aplicativo de recurso com suporte do recurso do Microsoft Graph. Saiba como conceder funções de aplicativo a uma entidade de serviço.
Se nenhuma condição for atendida, o conteúdo da notificação conterá um token de nullvalidação.
Criar uma assinatura
Para configurar notificações avançadas, siga as mesmas etapas das notificações de alteração básicas, mas inclua estas propriedades obrigatórias:
-
includeResourceData: defina isso como para solicitar dados de
truerecurso. - encryptionCertificate: forneça a chave pública que o Microsoft Graph usa para criptografar os dados do recurso. Saiba mais em Descriptografar dados de recursos de notificações de alteração.
- encryptionCertificateId: forneça um identificador para o certificado corresponder às notificações com a chave de descriptografia correta.
Valide ambos os pontos de extremidade conforme descrito em Validação de ponto de extremidade de notificação. Se você usar a mesma URL para ambos os pontos de extremidade, receberá e deverá responder a duas solicitações de validação.
Exemplo: solicitação de assinatura
Este exemplo cria uma assinatura para mensagens de canal no Microsoft Teams.
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl": "https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/{id}/channels/{id}/messages",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Resposta de assinatura
HTTP/1.1 201 Created
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl": "https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/{id}/channels/{id}/messages",
"includeResourceData": true,
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Notificações do ciclo de vida da assinatura
Os eventos podem interromper o fluxo de notificações de alteração em uma assinatura. As notificações do ciclo de vida informam quais ações tomar para manter o fluxo ininterrupto. Ao contrário das notificações de alteração de recursos, as notificações de ciclo de vida se concentram no estado da assinatura.
Para saber mais, consulte Reduzir assinaturas ausentes e alterar notificações.
Validar a autenticidade das notificações
Sempre verifique a autenticidade das notificações de alteração antes de processá-las. Isso impede que seu aplicativo dispare lógica de negócios incorreta usando notificações falsas de terceiros.
Para notificações básicas, valide-as usando o valor clientState , conforme explicado em Processando a notificação de alteração. Para notificações avançadas, execute etapas de validação adicionais.
Tokens de validação na notificação de alteração
As notificações avançadas incluem uma propriedade validationTokens , que contém uma matriz de JSON Web Tokens (JWT). Cada token é exclusivo para o aplicativo e o par de locatários. Uma notificação de alteração pode conter uma combinação de itens para vários aplicativos e locatários que assinaram usando a mesma notificationUrl.
Observação
O Microsoft Graph não envia tokens de validação para notificações de alteração entregues por meio de Hubs de Eventos do Azure porque o serviço de assinatura não precisa validar o notificationUrl para Hubs de Eventos.
No exemplo a seguir, a notificação de alteração contém dois itens para o mesmo aplicativo e para dois locatários diferentes, portanto, o conjunto validationTokens contém dois tokens que precisam ser validados.
Dica
Um null valor para validationTokens indica que o Microsoft Graph não pôde criptografar os dados do recurso devido à configuração incorreta do aplicativo. Examine a seção Configuração do aplicativo para notificações para corrigir esse problema.
{
"value": [
{
"subscriptionId": "76619225-ff6b-4489-96ca-4ef547e78b22",
"tenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee",
"changeType": "created",
...
},
{
"subscriptionId": "5cfe2387-163c-4006-81bb-1b5e1e060afe",
"tenantId": "bbbbcccc-1111-dddd-2222-eeee3333ffff",
"changeType": "created",
...
}
],
"validationTokens": [
"eyJ0eXAiOiJKV1QiLCJhb...",
"cGlkYWNyIjoiMiIsImlkc..."
]
}
O objeto de notificação de alteração está na estrutura do tipo de recurso changeNotificationCollection.
Como validar
Use a MSAL (Biblioteca de Autenticação da Microsoft) ou uma biblioteca de terceiros para validar tokens. Siga estas etapas:
Lembre-se dos seguintes princípios:
- Responda à notificação com um código de
HTTP 202 Acceptedstatus imediatamente. - Responda antes de validar a notificação de alteração, mesmo que a validação falhe mais tarde. Responda imediatamente após receber a notificação de alteração, independentemente de armazenar notificações em filas para processamento posterior ou processá-las em tempo real.
- Aceitar e responder a uma notificação de alteração evita novas tentativas desnecessárias de entrega e oculta os resultados de validação de possíveis invasores. Você sempre pode ignorar uma notificação de alteração inválida depois de recebê-la.
Especificamente, realize a validação em todos os tokens JWT na coleção validationTokens. Se algum token falhar, considere a notificação de alteração suspeita e investigue mais.
Siga estas etapas para validar tokens e os aplicativos que os geram:
Valide se o token não expirou.
Valide se a plataforma de identidade da Microsoft emitiu o token e se ele não foi adulterado.
- Obtenha as chaves de assinatura do ponto de extremidade de configuração comum:
https://login.microsoftonline.com/common/.well-known/openid-configuration. Seu aplicativo pode armazenar essa configuração em cache por algum tempo. A configuração é atualizada com frequência, pois as chaves de assinatura são alternadas diariamente. - Verifique a assinatura do token JWT usando essas chaves.
Não aceite tokens emitidos por nenhuma outra autoridade.
- Obtenha as chaves de assinatura do ponto de extremidade de configuração comum:
Confirme se o token foi emitido para seu aplicativo.
As etapas a seguir fazem parte da lógica de validação padrão nas bibliotecas de token JWT e podem ser tipicamente executadas como uma única chamada de função.
- Valide a “audiência” no token que corresponde à ID do seu aplicativo.
- Se você tiver mais de um aplicativo recebendo notificações de alterações, verifique a existencia de vários IDs.
Valide a identidade do chamador do token para garantir que a notificação se origine do serviço de notificação de alteração do Microsoft Graph. A identidade esperada do chamador é
0bf30f3b-4a52-48df-9a82-234910c4a086. A declaração usada para representar o aplicativo chamador depende da versão do token:- Para tokens v1.0 (
ver="1.0"), a identidade doappidchamador é representada pela declaração. - Para tokens v2.0 (
ver="2.0"), a identidade do chamador é representada pelaazpdeclaração.
Importante
A falha ao validar a declaração apropriada pode resultar na aceitação de notificações de um fornecedor não confiável.
- Para tokens v1.0 (
Exemplo de Token JWT
O exemplo a seguir mostra as propriedades em um token JWT v2.0 necessárias para validação.
{
// aud is your app's id
"aud": "925bff9f-f6e2-4a69-b858-f71ea2b9b6d0",
"iss": "https://login.microsoftonline.com/9f4ebab6-520d-49c0-85cc-7b25c78d4a93/v2.0",
"iat": 1624649764,
"nbf": 1624649764,
"exp": 1624736464,
"aio": "E2ZgYGjnuFglnX7mtjJzwR5lYaWvAA==",
// azp represents the notification publisher and must always be the same value of 0bf30f3b-4a52-48df-9a82-234910c4a086
"azp": "0bf30f3b-4a52-48df-9a82-234910c4a086",
"azpacr": "2",
"oid": "1e7d79fa-7893-4d50-bdde-164260d9c5ba",
"rh": "0.AX0AtrpOnw1SwEmFzHslx41KkzsP8wtSSt9ImoIjSRDEoIZ9AAA.",
"sub": "1e7d79fa-7893-4d50-bdde-164260d9c5ba",
"tid": "9f4ebab6-520d-49c0-85cc-7b25c78d4a93",
"uti": "mIB4QKCeZE6hK71XUHJ3AA",
"ver": "2.0"
}
Exemplo: verificação de tokens de validação
// add Microsoft.IdentityModel.Protocols.OpenIdConnect and System.IdentityModel.Tokens.Jwt nuget packages to your project
public async Task<bool> ValidateToken(string token, string tenantId, IEnumerable<string> appIds)
{
var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(
"https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration",
new OpenIdConnectConfigurationRetriever());
var openIdConfig = await configurationManager.GetConfigurationAsync();
var handler = new JwtSecurityTokenHandler();
try
{
handler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
ValidIssuer = $"https://sts.windows.net/{tenantId}/",
ValidAudiences = appIds,
IssuerSigningKeys = openIdConfig.SigningKeys
}, out _);
return true;
}
catch (Exception ex)
{
Trace.TraceError($"{ex.Message}:{ex.StackTrace}");
return false;
}
}
Descriptografar os dados de recursos de notificações de alteração
A propriedade resourceData em uma notificação de alteração inclui informações básicas de ID e tipo de uma instância de recurso. A propriedade encryptedData tem os dados de recurso completos, criptografados pelo Microsoft Graph com a chave pública fornecida na assinatura. A propriedade também contém valores necessários para verificação e descriptografia. Essa criptografia é feita para aumentar a segurança dos dados do cliente acessados por meio de notificações de alteração. Proteja a chave privada para garantir que terceiros não possam descriptografar os dados do cliente, mesmo que interceptem as notificações de alteração originais.
Nesta seção, você aprenderá os seguintes conceitos:
Gerenciar as chaves de criptografia
Obtenha um certificado com um par de chaves assimétricas.
Você pode usar um certificado autoassinado, pois o Microsoft Graph não verifica o emissor do certificado e usa a chave pública apenas para criptografia.
Use Azure Key Vault para criar, alternar e gerenciar certificados com segurança. Cerifique-se de que as chaves atendem aos seguintes critérios:
- A chave deve ser do tipo
RSA. - O tamanho da chave deve estar entre 2.048 bits e 4.096 bits.
- A chave deve ser do tipo
Exporte o certificado no formato X.509 codificado em Base64 e inclua apenas a chave pública.
Ao criar uma assinatura:
Forneça o certificado na propriedade encryptionCertificate , usando o conteúdo codificado em Base64 no qual o certificado foi exportado.
Forneça seu próprio identificador na propriedade encryptionCertificateId.
Esse identificador permite corresponder seus certificados às notificações de alterações recebidas e recuperar certificados do seu repositório de certificados. O identificador pode ter no máximo 128 caracteres.
Gerencie com segurança a chave privada com para que seu código de processamento de notificação de alteração acesse a chave privada para decriptar os dados do recurso.
Chaves de rotação
Altere as chaves assimétricas periodicamente para minimizar o risco de comprometimento de uma chave privada. Siga estas etapas para introduzir um novo par de chaves:
Obtenha um novo certificado com um novo par de chaves assimétricas. Use-o para todas as novas assinaturas sendo criadas.
Atualize as assinaturas existentes com a nova chave de certificado.
- Torne esta atualização parte da renovação regular da assinatura.
- Ou enumere todas as assinaturas e forneça a chave. Use a operação PATCH na assinatura e atualize as propriedades encryptionCertificate e encryptionCertificateId.
Lembre-se dos seguintes princípios:
- O certificado antigo ainda pode ser usado para criptografia por algum tempo. Seu aplicativo deve ter acesso a certificados novos e antigos para poder descriptografar o conteúdo.
- Use a propriedade encryptionCertificateId em cada notificação de alteração para identificar a chave correta a ser utilizada.
- Descarte o certificado antigo somente quando você não vir notificações de alteração recentes fazendo referência a ele.
Descriptografar dados de recursos
Para otimizar o desempenho, o Microsoft Graph usa um processo de criptografia de duas etapas:
- Ele gera uma chave simétrica de uso único e a usa para criptografar dados de recursos.
- Ele usa a chave pública assimétrica (que você forneceu ao fazer a assinatura) para criptografar a chave simétrica e a incluir em cada notificação de alteração desta assinatura.
Suponha que a chave simétrica seja diferente para cada item na notificação de modificação.
Para decriptar os dados de recursos, o seu aplicativo deve executar as etapas inversas, usando as propriedades encryptedContent em cada notificação de alteração:
Identifique o certificado correto usando a propriedade encryptionCertificateId .
Inicializar um componente criptográfico RSA com a chave privada. Uma maneira fácil de inicializar um componente RSA é usar o método RSACertificateExtensions.GetRSAPrivateKey(X509Certificate2) com uma instância X509Certificate2 , que contém a chave privada descrita em Gerenciando chaves de criptografia.
Descriptografe a chave simétrica na propriedade dataKey de cada item na notificação de alteração usando sua chave privada. Use o OAEP (Preenchimento de Criptografia Assimétrica Ideal) como o algoritmo de descriptografia.
Use a chave simétrica para calcular a assinatura HMAC-SHA256 para o valor nos dados. Compare-o com o valor em dataSignature. Se eles não corresponderem, assuma que o conteúdo foi adulterado e não o descriptografe.
Descriptografe a propriedade de dados usando a chave simétrica com o AES (Advanced Encryption Standard), como o .NET Aes.
Use os seguintes parâmetros de descriptografia para o algoritmo AES:
- Preenchimento: PKCS7.
- Modo de criptografia: CBC.
Defina o “vetor de inicialização” copiando os primeiros 16 bytes da chave simétrica usada para descriptografia.
Os dados descriptografados serão uma cadeia de caracteres JSON que representa o recurso.
Exemplo: descriptografar dados de recursos
O exemplo JSON a seguir mostra uma notificação de alteração que inclui valores de propriedade criptografados de uma instância chatMessage em uma mensagem de canal. O @odata.id valor especifica a instância.
{
"value": [
{
"subscriptionId": "76222963-cc7b-42d2-882d-8aaa69cb2ba3",
"changeType": "created",
// Other properties typical in a resource change notification
"resource": "teams('d29828b8-c04d-4e2a-b2f6-07da6982f0f0')/channels('19:f127a8c55ad949d1a238464d22f0f99e@thread.skype')/messages('1565045424600')/replies('1565047490246')",
"resourceData": {
"id": "1565293727947",
"@odata.type": "#Microsoft.Graph.ChatMessage",
"@odata.id": "teams('88cbc8fc-164b-44f0-b6a6-b59b4a1559d3')/channels('19:8d9da062ec7647d4bb1976126e788b47@thread.tacv2')/messages('1565293727947')/replies('1565293727947')"
},
"encryptedContent": {
"data": "{encrypted data that produces a full resource}",
"dataSignature": "<HMAC-SHA256 hash>",
"dataKey": "{encrypted symmetric key from Microsoft Graph}",
"encryptionCertificateId": "MySelfSignedCert/DDC9651A-D7BC-4D74-86BC-A8923584B0AB",
"encryptionCertificateThumbprint": "07293748CC064953A3052FB978C735FB89E61C3D"
}
}
],
"validationTokens": [
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSU..."
]
}
Para obter uma descrição completa dos dados enviados quando as notificações de alteração são entregues, consulte o tipo de recurso changeNotificationCollection.
Descriptografar a chave simétrica
A seção contém alguns trechos de código úteis que usam C# e .NET em cada etapa da descriptografia.
// Initialize with the private key that matches the encryptionCertificateId.
X509Certificate2 certificate = <instance of X509Certificate2 matching the encryptionCertificateId property>;
RSA rsa = certificate.GetRSAPrivateKey();
byte[] encryptedSymmetricKey = Convert.FromBase64String(<value from dataKey property>);
// Decrypt using OAEP padding.
byte[] decryptedSymmetricKey = rsa.Decrypt(encryptedSymmetricKey, RSAEncryptionPadding.OaepSHA1);
// Can now use decryptedSymmetricKey with the AES algorithm.
Comparar assinatura de dados usando HMAC-SHA256
byte[] decryptedSymmetricKey = <the aes key decrypted in the previous step>;
byte[] encryptedPayload = <the value from the data property, still encrypted>;
byte[] expectedSignature = <the value from the dataSignature property>;
byte[] actualSignature;
using (HMACSHA256 hmac = new HMACSHA256(decryptedSymmetricKey))
{
actualSignature = hmac.ComputeHash(encryptedPayload);
}
if (actualSignature.SequenceEqual(expectedSignature))
{
// Continue with decryption of the encryptedPayload.
}
else
{
// Do not attempt to decrypt encryptedPayload. Assume notification payload has been tampered with and investigate.
}
Descriptografar o conteúdo dos dados de recursos
Aes aesProvider = Aes.Create();
aesProvider.Key = decryptedSymmetricKey;
aesProvider.Padding = PaddingMode.PKCS7;
aesProvider.Mode = CipherMode.CBC;
// Obtain the initialization vector from the symmetric key itself.
int vectorSize = 16;
byte[] iv = new byte[vectorSize];
Array.Copy(decryptedSymmetricKey, iv, vectorSize);
aesProvider.IV = iv;
byte[] encryptedPayload = Convert.FromBase64String(<value from data property>);
string decryptedResourceData;
// Decrypt the resource data content.
using (var decryptor = aesProvider.CreateDecryptor())
{
using (MemoryStream msDecrypt = new MemoryStream(encryptedPayload))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
decryptedResourceData = srDecrypt.ReadToEnd();
}
}
}
}
// decryptedResourceData now contains a JSON string that represents the resource.
Conteúdo relacionado
- Configure o tipo de recurso de assinatura.