Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este artículo se proporcionan procedimientos recomendados para administrar tokens de acceso de usuario en los SDK de Azure Communication Services. Siga estas instrucciones para optimizar los recursos usados por la aplicación y reducir el número de recorridos de ida y vuelta a Azure Communication Identity API.
Credencial de token de Communication
La credencial de token de Communication (credencial) es un tipo primitivo de autenticación que encapsula los tokens de acceso de usuario. Se usa para autenticar a los usuarios en Communication Services, como Chat o Llamadas. Además, proporciona una funcionalidad integrada de actualización de tokens para la comodidad del desarrollador.
Elección de la duración de la sesión
En función de su escenario, es posible que desee ajustar la duración de los tokens emitidos para la aplicación. Los siguientes procedimientos recomendados o su combinación pueden ayudarle a lograr la solución óptima para su escenario:
- Personalice el tiempo de expiración del token para sus necesidades específicas.
- Inicialice la credencial con un token estático para mensajes de chat únicos o sesiones de llamada con tiempo limitado.
- Use una función de devolución de llamada para agentes que usan la aplicación durante períodos de tiempo más largos.
Establecimiento de una hora de expiración del token personalizado
Al solicitar un nuevo token, se recomienda usar tokens de duración corta para mensajes de chat únicos o sesiones de llamada con tiempo limitado. Se recomiendan tokens de duración más largos para los agentes que usan la aplicación durante períodos de tiempo más largos. El tiempo de expiración del token predeterminado es de 24 horas. Puede personalizar la hora de expiración proporcionando un valor entre una hora y 24 horas para el parámetro opcional de la siguiente manera:
const tokenOptions = { tokenExpiresInMinutes: 60 };
const user = { communicationUserId: userId };
const scopes = ["chat"];
let communicationIdentityToken = await identityClient.getToken(user, scopes, tokenOptions);
Token estático
Para los clientes de corta duración, inicialice la credencial con un token estático. Este enfoque es adecuado para escenarios como el envío de mensajes de chat de un solo uso o sesiones de llamadas con tiempo limitado.
let communicationIdentityToken = await identityClient.getToken({ communicationUserId: userId }, ["chat", "voip"]);
const tokenCredential = new AzureCommunicationTokenCredential(communicationIdentityToken.token);
Función de devolución de llamada
Para los clientes de larga duración, inicialice la credencial con una función de devolución de llamada que garantice un estado de autenticación continua durante las comunicaciones. Este enfoque es adecuado, por ejemplo, para sesiones largas de llamadas.
const tokenCredential = new AzureCommunicationTokenCredential({
tokenRefresher: async (abortSignal) => fetchTokenFromMyServerForUser(abortSignal, "<user_name>")
});
Actualización del token
Para implementar correctamente el callback de actualización de tokens, el código debe devolver una cadena con un token web JSON (JWT) válido. El token devuelto siempre debe ser válido y su fecha de expiración establecida en el futuro. Algunas plataformas, como JavaScript y .NET, ofrecen una manera de anular la operación de actualización y pasar AbortSignal o CancellationToken a su función. Se recomienda aceptar estos objetos, usarlos o pasarlos más adelante.
Ejemplo 1: Actualización de un token para un usuario de comunicación
Supongamos que tenemos una aplicación Node.js creada en Express con el /getToken punto de conexión que permite capturar un nuevo token válido para un usuario especificado por nombre.
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 });
});
A continuación, es necesario implementar una devolución de llamada del actualizador de tokens en la aplicación cliente, utilizando correctamente AbortSignal y devolviendo una cadena JWT desencapsulada.
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;
}
};
Ejemplo 2: Actualización de un token para un usuario de Teams
Supongamos que tenemos una aplicación de Node.js integrada en Express con el punto de conexión /getTokenForTeamsUser que permite intercambiar un token de acceso de Microsoft Entra de un usuario de Teams por un nuevo token de acceso de Communication Identity con una hora de expiración correspondiente.
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 });
});
A continuación, debemos implementar un callback de refresco de tokens en la aplicación cliente, cuya responsabilidad es:
- Actualice el token de acceso de Microsoft Entra del usuario de Teams.
- Intercambiar el token de acceso de Microsoft Entra del usuario de Teams por un token de acceso de identidad comunicativa.
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;
}
}
En este ejemplo, usamos la Biblioteca de autenticación de Microsoft (MSAL) para actualizar el token de acceso de Microsoft Entra. Siguiendo la guía para adquirir un token de Microsoft Entra para llamar a una API, primero intentamos obtener el token sin la interacción del usuario. Si no es posible, desencadenamos uno de los flujos interactivos.
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;
}
Proporcionar un token inicial
Para optimizar aún más el código, puede capturar el token en el inicio de la aplicación y pasarlo directamente a la credencial. Al proporcionar un token inicial, se omite la primera llamada a la función de devolución de llamada del actualizador, a la vez que se conservan todas las llamadas posteriores a ella.
const tokenCredential = new AzureCommunicationTokenCredential({
tokenRefresher: async () => fetchTokenFromMyServerForUser("<user_id>"),
token: "<initial_token>"
});
Actualización proactiva del token
Usar la actualización proactiva para eliminar cualquier retraso posible durante la obtención bajo demanda del token. La actualización proactiva actualiza el token en segundo plano al final de su vigencia. Cuando el token está a punto de expirar, 10 minutos antes del final de su validez, la credencial comienza a intentar recuperar el token. Desencadena la devolución de llamada del actualizador con una frecuencia creciente hasta que se realiza correctamente y recupera un token con suficiente validez.
const tokenCredential = new AzureCommunicationTokenCredential({
tokenRefresher: async () => fetchTokenFromMyServerForUser("<user_id>"),
refreshProactively: true
});
Si desea cancelar las tareas de actualización programadas, elimine el objeto Credential.
Actualización proactiva de un token para un usuario de Teams
Para minimizar el número de ciclos de ida y vuelta con la API de Azure Communication Identity, asegúrese de que el token de Microsoft Entra que está pasando para un intercambio tiene una validez suficientemente larga (> 10 minutos). En caso de que MSAL devuelva un token almacenado en caché con una validez más corta, tiene las siguientes opciones para omitir la memoria caché:
- Actualizar el token de forma forzada
- Aumentar la ventana de renovación de tokens de MSAL a más de 10 minutos
Opción 1: desencadene el flujo de adquisición de tokens con AuthenticationParameters.forceRefresh establecido en 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;
});
}
}
Opción 2: Inicialice el contexto de autenticación de MSAL instanciando un PublicClientApplication con un SystemOptions.tokenRenewalOffsetSeconds personalizado.
const publicClientApplication = new PublicClientApplication({
system: {
tokenRenewalOffsetSeconds: 900 // 15 minutes (by default 5 minutes)
});
Cancelación de la actualización
Para que los clientes de comunicación puedan cancelar las tareas de actualización en curso, es necesario pasar un objeto de cancelación a la devolución de llamada del actualizador. Este patrón solo se aplica a JavaScript y .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...');
});
Si desea cancelar las tareas de actualización posteriores, elimine el objeto Credential.
Limpiar recursos
Dado que el objeto Credential se puede pasar a varias instancias de cliente de chat o llamada, el SDK no supone su duración y deja la responsabilidad de su eliminación al desarrollador. Es necesario que las aplicaciones de Communication Services eliminen la instancia de credencial cuando ya no sea necesaria. La eliminación de la credencial también cancela las acciones de actualización programadas cuando se habilita la actualización proactiva.
Llame a la función .dispose().
const tokenCredential = new AzureCommunicationTokenCredential("<token>");
// Use the credential for Calling or Chat
const chatClient = new ChatClient("<endpoint-url>", tokenCredential);
// ...
tokenCredential.dispose()
Gestión de cierre de sesión
En función de su escenario, puede que desee cerrar la sesión de un usuario desde uno o varios servicios:
- Para cerrar la sesión de un usuario desde un único servicio, elimine el objeto Credential.
- Para cerrar la sesión de un usuario desde varios servicios, implemente un mecanismo de señalización para notificar a todos los servicios que eliminen el objeto Credential y, además, revoque todos los tokens de acceso para una identidad determinada.
Pasos siguientes
En este artículo se describe cómo:
- Inicialización y eliminación correcta de un objeto Credential
- Implementar una devolución de llamada del actualizador de tokens
- Optimizar la lógica de actualización de tokens