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.
Este artigo fornece as práticas recomendadas para gerenciar tokens de acesso de usuário nos SDKs dos Serviços de Comunicação do Azure. Siga estas diretrizes para otimizar os recursos usados pelo aplicativo e reduzir o número de viagens de ida e volta para a API de Identidade de Comunicação do Azure.
Credencial de Token de Comunicação
A Credencial de Token de Comunicação (Credencial) é um primitivo de autenticação que encapsula os Tokens de Acesso do Usuário. Ele é usado para autenticar usuários nos Serviços de Comunicação, como Chat ou Chamada. Além disso, ele fornece funcionalidade de atualização de token interna para a conveniência do desenvolvedor.
Escolhendo o tempo de vida da sessão
Dependendo do seu cenário, talvez você queira ajustar o tempo de vida dos tokens emitidos para seu aplicativo. As seguintes práticas recomendadas ou sua combinação podem ajudá-lo a alcançar a solução ideal para seu cenário:
- Personalize o tempo de expiração do token de acordo com suas necessidades específicas.
- Inicialize a Credencial com um token estático para mensagens de Chat pontuais ou sessões de Chamada limitadas por tempo.
- Use uma função de retorno de chamada para agentes que usam o aplicativo por períodos mais longos de tempo.
Definindo um tempo de expiração de token personalizado
Ao solicitar um novo token, recomendamos usar tokens de tempo de vida curto para mensagens de Chat pontuais ou sessões de Chamada limitadas por tempo. Recomendamos tokens de tempo de vida mais longos para agentes que usam o aplicativo por períodos mais longos de tempo. O tempo de expiração do token padrão é de 24 horas. Você pode personalizar o tempo de expiração fornecendo um valor entre uma hora e 24 horas para o parâmetro opcional da seguinte maneira:
const tokenOptions = { tokenExpiresInMinutes: 60 };
const user = { communicationUserId: userId };
const scopes = ["chat"];
let communicationIdentityToken = await identityClient.getToken(user, scopes, tokenOptions);
Token estático
Para clientes de curta duração, inicialize a Credencial com um token estático. Essa abordagem é adequada para cenários como enviar mensagens de Chat pontuais ou sessões de Chamada limitadas por tempo.
let communicationIdentityToken = await identityClient.getToken({ communicationUserId: userId }, ["chat", "voip"]);
const tokenCredential = new AzureCommunicationTokenCredential(communicationIdentityToken.token);
Função de callback
Para clientes de vida longa, inicialize a Credencial com uma função de retorno de chamada que garanta um estado de autenticação contínua durante as comunicações. Essa abordagem é adequada, por exemplo, para sessões de chamada longas.
const tokenCredential = new AzureCommunicationTokenCredential({
tokenRefresher: async (abortSignal) => fetchTokenFromMyServerForUser(abortSignal, "<user_name>")
});
Atualização de token
Para implementar corretamente o retorno de chamada do atualizador de token, o código deve retornar uma cadeia de caracteres com um JWT (Token Web JSON) válido. O token retornado deve ser sempre válido e sua data de validade definida no futuro. Algumas plataformas, como JavaScript e .NET, oferecem uma maneira de anular a operação de atualização e passar AbortSignal ou CancellationToken para sua função. Recomendamos que você aceite esses objetos, utilize-os ou passe-os mais adiante.
Exemplo 1: atualizando um token para um usuário de comunicação
Vamos supor que temos um aplicativo Node.js criado no Express com o endpoint /getToken permitindo buscar um novo token válido para um usuário especificado por nome.
app.post('/getToken', async (req, res) => {
// Custom logic to determine the communication user id
let userId = await getCommunicationUserIdFromDb(req.body.username);
// Get a fresh token
const identityClient = new CommunicationIdentityClient("<COMMUNICATION_SERVICES_CONNECTION_STRING>");
let communicationIdentityToken = await identityClient.getToken({ communicationUserId: userId }, ["chat", "voip"]);
res.json({ communicationIdentityToken: communicationIdentityToken.token });
});
Em seguida, precisamos implementar um retorno de chamada da atualização do token no aplicativo cliente, utilizando corretamente o AbortSignal e retornando uma cadeia de caracteres JWT com quebra de linha cancelada.
const fetchTokenFromMyServerForUser = async function (abortSignal, username) {
const response = await fetch(`${HOST_URI}/getToken`,
{
method: "POST",
body: JSON.stringify({ username: username }),
signal: abortSignal,
headers: { 'Content-Type': 'application/json' }
});
if (response.ok) {
const data = await response.json();
return data.communicationIdentityToken;
}
};
Exemplo 2: atualizando um token para um usuário do Teams
Vamos supor que tenhamos um aplicativo Node.js criado no Expresso com o ponto de extremidade /getTokenForTeamsUser, permitindo a troca de um token de acesso do Microsoft Entra de um usuário do Teams para um novo token de acesso de Identidade de Comunicação com um tempo de expiração correspondente.
app.post('/getTokenForTeamsUser', async (req, res) => {
const identityClient = new CommunicationIdentityClient("<COMMUNICATION_SERVICES_CONNECTION_STRING>");
let communicationIdentityToken = await identityClient.getTokenForTeamsUser(req.body.teamsToken, '<AAD_CLIENT_ID>', '<TEAMS_USER_OBJECT_ID>');
res.json({ communicationIdentityToken: communicationIdentityToken.token });
});
Em seguida, precisamos implementar um callback para atualização de token na aplicação cliente, cuja responsabilidade é:
- Atualizar o token de acesso do Microsoft Entra do Usuário do Teams.
- Trocar o token de acesso do Microsoft Entra do usuário do Teams para um token de acesso da Identidade de Comunicação.
const fetchTokenFromMyServerForUser = async function (abortSignal, username) {
// 1. Refresh the Azure AD access token of the Teams User
let teamsTokenResponse = await refreshAadToken(abortSignal, username);
// 2. Exchange the Azure AD access token of the Teams User for a Communication Identity access token
const response = await fetch(`${HOST_URI}/getTokenForTeamsUser`,
{
method: "POST",
body: JSON.stringify({ teamsToken: teamsTokenResponse.accessToken }),
signal: abortSignal,
headers: { 'Content-Type': 'application/json' }
});
if (response.ok) {
const data = await response.json();
return data.communicationIdentityToken;
}
}
Neste exemplo, usamos a MSAL (Biblioteca de Autenticação da Microsoft) para atualizar o token de acesso do Microsoft Entra. Seguindo o guia para adquirir um token do Microsoft Entra para chamar uma API, primeiro tentamos obter o token sem a interação do usuário. Se isso não for possível, dispararemos um dos fluxos interativos.
const refreshAadToken = async function (abortSignal, username) {
if (abortSignal.aborted === true) throw new Error("Operation canceled");
// MSAL.js v2 exposes several account APIs; the logic to determine which account to use is the responsibility of the developer.
// In this case, we'll use an account from the cache.
let account = (await publicClientApplication.getTokenCache().getAllAccounts()).find(u => u.username === username);
const renewRequest = {
scopes: [
"https://auth.msft.communication.azure.com/Teams.ManageCalls",
"https://auth.msft.communication.azure.com/Teams.ManageChats"
],
account: account,
forceRefresh: forceRefresh
};
let tokenResponse = null;
// Try to get the token silently without the user's interaction
await publicClientApplication.acquireTokenSilent(renewRequest).then(renewResponse => {
tokenResponse = renewResponse;
}).catch(async (error) => {
// In case of an InteractionRequired error, send the same request in an interactive call
if (error instanceof InteractionRequiredAuthError) {
// You can choose the popup or redirect experience (`acquireTokenPopup` or `acquireTokenRedirect` respectively)
publicClientApplication.acquireTokenPopup(renewRequest).then(function (renewInteractiveResponse) {
tokenResponse = renewInteractiveResponse;
}).catch(function (interactiveError) {
console.log(interactiveError);
});
}
});
return tokenResponse;
}
Fornecendo um token inicial
Para otimizar ainda mais seu código, você pode buscar o token na inicialização do aplicativo e passá-lo diretamente para a Credencial. Fornecer um token inicial vai ignorar a primeira chamada para a função de retorno de chamada de atualização enquanto preserva todas as chamadas subsequentes para ela.
const tokenCredential = new AzureCommunicationTokenCredential({
tokenRefresher: async () => fetchTokenFromMyServerForUser("<user_id>"),
token: "<initial_token>"
});
Atualização proativa de token
Use a atualização proativa para eliminar qualquer atraso possível durante a busca por demanda do token. A atualização proativa atualiza o token em segundo plano ao término de seu tempo de vida. Quando o token está prestes a expirar, 10 minutos antes do fim de sua validade, a Credencial começa a tentar recuperar o token. Ela dispara o retorno de chamada de atualização com uma frequência cada vez maior até obter sucesso e recuperar um token com uma validade longa o suficiente.
const tokenCredential = new AzureCommunicationTokenCredential({
tokenRefresher: async () => fetchTokenFromMyServerForUser("<user_id>"),
refreshProactively: true
});
Se você quiser cancelar as tarefas de atualização agendadas, descarte o objeto Credential.
Atualizando proativamente um token para um usuário do Teams
Para minimizar o número de viagens de ida e volta para a API de Identidade de Comunicação do Azure, verifique se o token do Microsoft Entra que você está passando para uma troca tem uma validade longa o suficiente (> 10 minutos). Caso a MSAL retorne um token armazenado em cache com uma validade mais curta, você terá as seguintes opções para ignorar o cache:
- Atualizar o token de modo forçado
- Aumentar a janela de renovação de token da MSAL para mais de 10 minutos
Opção 1: disparar o fluxo de aquisição de token com AuthenticationParameters.forceRefresh definido como true.
// Extend the `refreshAadToken` function
const refreshAadToken = async function (abortSignal, username) {
// ... existing refresh logic
// Make sure the token has at least 10-minute lifetime and if not, force-renew it
if (tokenResponse.expiresOn < (Date.now() + (10 * 60 * 1000))) {
const renewRequest = {
scopes: [
"https://auth.msft.communication.azure.com/Teams.ManageCalls",
"https://auth.msft.communication.azure.com/Teams.ManageChats"
],
account: account,
forceRefresh: true // Force-refresh the token
};
await publicClientApplication.acquireTokenSilent(renewRequest).then(renewResponse => {
tokenResponse = renewResponse;
});
}
}
Opção 2: inicializar o contexto de autenticação MSAL instanciando um PublicClientApplication com um SystemOptions.tokenRenewalOffsetSeconds personalizado.
const publicClientApplication = new PublicClientApplication({
system: {
tokenRenewalOffsetSeconds: 900 // 15 minutes (by default 5 minutes)
});
Como cancelar a atualização
Para que os clientes de Comunicação possam cancelar tarefas de atualização em andamento, é necessário passar um objeto de cancelamento para o retorno de chamada de atualização. Esse padrão se aplica somente ao JavaScript e ao .NET.
var controller = new AbortController();
var joinChatBtn = document.querySelector('.joinChat');
var leaveChatBtn = document.querySelector('.leaveChat');
joinChatBtn.addEventListener('click', function () {
// Wrong:
const tokenCredentialWrong = new AzureCommunicationTokenCredential({
tokenRefresher: async () => fetchTokenFromMyServerForUser("<user_name>")
});
// Correct: Pass abortSignal through the arrow function
const tokenCredential = new AzureCommunicationTokenCredential({
tokenRefresher: async (abortSignal) => fetchTokenFromMyServerForUser(abortSignal, "<user_name>")
});
// ChatClient is now able to abort token refresh tasks
const chatClient = new ChatClient("<endpoint-url>", tokenCredential);
// Pass the abortSignal to the chat client through options
const createChatThreadResult = await chatClient.createChatThread(
{ topic: "Hello, World!" },
{
// ...
abortSignal: controller.signal
}
);
// ...
});
leaveChatBtn.addEventListener('click', function() {
controller.abort();
console.log('Leaving chat...');
});
Se você quiser cancelar as tarefas de atualização subsequentes, descarte o objeto Credential.
Limpando recursos
Como o objeto Credential pode ser passado para várias instâncias de cliente de Chat ou Chamada, o SDK não faz suposições sobre seu tempo de vida e deixará a responsabilidade de sua eliminação para o desenvolvedor. Cabe aos aplicativos dos Serviços de Comunicação descartar a instância de Credencial quando ela não for mais necessária. Descartar a credencial também cancela as ações de atualização agendadas quando a atualização proativa estiver habilitada.
Chame a função .dispose().
const tokenCredential = new AzureCommunicationTokenCredential("<token>");
// Use the credential for Calling or Chat
const chatClient = new ChatClient("<endpoint-url>", tokenCredential);
// ...
tokenCredential.dispose()
Como lidar com uma saída
Dependendo do seu cenário, talvez você queira desconectar um usuário de um ou mais serviços:
- Para desconectar um usuário de um único serviço, descarte o objeto Credential.
- Para desconectar um usuário de vários serviços, implemente um mecanismo de sinalização para notificar todos os serviços para descartar o objeto Credential e, além disso, revogar todos os tokens de acesso para uma determinada identidade.
Próximas etapas
Este artigo descreveu como:
- Inicializar e descartar corretamente um objeto de Credencial
- Implementar um retorno de chamada da atualização do token
- Otimizar a lógica de atualização do token