Ejercicio: Incorporación del inicio de sesión único
En este ejercicio, agregará el inicio de sesión único a la extensión de mensaje para autenticar las consultas de usuario.
Configuración del registro de aplicaciones de API de back-end
En primer lugar, cree un registro de aplicación de Microsoft Entra para la API de back-end. Para los fines de este ejercicio, cree uno nuevo, pero, en un entorno de producción, usaría un registro de aplicación existente.
En una ventana del explorador:
- Vaya a Azure Portal.
- Abra el menú del portal y seleccione Microsoft Entra ID
- Seleccione Registros de aplicaciones y, a continuación, seleccione Nuevo registro.
- En el formulario Registrar una aplicación, especifique los valores siguientes:
- Nombre: API de productos
- Tipos de cuenta de soporte técnico: cuentas en cualquier directorio organizativo (cualquier inquilino de Microsoft Entra ID: multiinquilino)
- Seleccione Registrar para crear el registro de la aplicación.
- En el menú izquierdo del registro de aplicaciones, seleccione Exponer una API.
- Seleccione Add and Save create a new Application ID URI (Agregar y guardar ) para crear un nuevo URI de identificador de aplicación.
- En la sección Ámbitos definidos por esta API, seleccione Agregar un ámbito.
- En el formulario Agregar un ámbito, especifique los valores siguientes:
- Nombre de ámbito: Product.Read
- ¿Quién puede dar su consentimiento?: Administradores y usuarios
- Nombre para mostrar del consentimiento del administrador: Leer productos
- Descripción del consentimiento del administrador: permite que la aplicación lea los datos del producto.
- Nombre para mostrar del consentimiento del usuario: Leer productos
- Descripción del consentimiento del usuario: permite que la aplicación lea los datos del producto.
- Estado: Habilitado
- Seleccione Agregar ámbito para crear el ámbito.
A continuación, tome nota del identificador de registro de la aplicación y del identificador de ámbito. Necesita estos valores para configurar el registro de la aplicación que se usa para obtener un token de acceso para la API de back-end.
- En el menú izquierdo del registro de la aplicación, seleccione Manifiesto.
- Copie el valor de la propiedad appId y guárdelo para su uso posterior.
- Copie el valor de la propiedad api.oauth2PermissionScopes[0].id y guárdelo para su uso posterior.
Como necesitamos estos valores en el proyecto, agréguelos al archivo de entorno.
En Visual Studio y el proyecto TeamsApp:
En la carpeta env , abra .env.local.
En el archivo, cree las siguientes variables de entorno y establezca los valores en el identificador de registro y el identificador de ámbito de la aplicación:
BACKEND_API_ENTRA_APP_ID=<app-registration-id> BACKEND_API_ENTRA_APP_SCOPE_ID=<scope-id>
Save your changes
Creación de un archivo de manifiesto de registro de aplicaciones para la autenticación con la API back-end
Para autenticarse con la API de back-end, necesita un registro de aplicación para obtener un token de acceso con el que llamar a la API.
A continuación, cree un archivo de manifiesto de registro de aplicación. El manifiesto define los ámbitos de permisos de API y el URI de redirección en el registro de la aplicación.
En Visual Studio y el proyecto TeamsApp:
En la carpeta infra\entra , cree un archivo denominado entra.products.api.manifest.json
En el archivo, agregue el código siguiente:
{ "id": "${{PRODUCTS_API_ENTRA_APP_OBJECT_ID}}", "appId": "${{PRODUCTS_API_ENTRA_APP_ID}}", "name": "${{APP_INTERNAL_NAME}}-product-api-${{TEAMSFX_ENV}}", "accessTokenAcceptedVersion": 2, "signInAudience": "AzureADMultipleOrgs", "optionalClaims": { "idToken": [], "accessToken": [ { "name": "idtyp", "source": null, "essential": false, "additionalProperties": [] } ], "saml2Token": [] }, "requiredResourceAccess": [ { "resourceAppId": "${{BACKEND_API_ENTRA_APP_ID}}", "resourceAccess": [ { "id": "${{BACKEND_API_ENTRA_APP_SCOPE_ID}}", "type": "Scope" } ] } ], "oauth2Permissions": [], "preAuthorizedApplications": [], "identifierUris": [], "replyUrlsWithType": [ { "url": "https://token.botframework.com/.auth/web/redirect", "type": "Web" } ] }
Save your changes
La propiedad requiredResourceAccess especifica el identificador de registro de la aplicación y el identificador de ámbito de la API de back-end.
La propiedad replyUrlsWithType especifica el URI de redireccionamiento usado por Bot Framework Token Service para devolver el token de acceso al servicio de token después de que el usuario se autentique.
A continuación, actualice el flujo de trabajo automatizado para crear y actualizar el registro de la aplicación.
En el proyecto TeamsApp:
Abrir teamsapp.local.yml
En el archivo, busque el paso que usa la acción addApp/update .
Después de la acción, agregue las acciones aadApp/create y aadApp/update para crear y actualizar el registro de la aplicación:
- uses: aadApp/create with: name: ${{APP_INTERNAL_NAME}}-products-api-${{TEAMSFX_ENV}} generateClientSecret: true signInAudience: AzureADMultipleOrgs writeToEnvironmentFile: clientId: PRODUCTS_API_ENTRA_APP_ID clientSecret: SECRET_PRODUCTS_API_ENTRA_APP_CLIENT_SECRET objectId: PRODUCTS_API_ENTRA_APP_OBJECT_ID tenantId: PRODUCTS_API_ENTRA_APP_TENANT_ID authority: PRODUCTS_API_ENTRA_APP_OAUTH_AUTHORITY authorityHost: PRODUCTS_API_ENTRA_APP_OAUTH_AUTHORITY_HOST - uses: aadApp/update with: manifestPath: "./infra/entra/entra.products.api.manifest.json" outputFilePath : "./infra/entra/build/entra.products.api.${{TEAMSFX_ENV}}.json"
Save your changes
La acción aadApp/create crea un nuevo registro de aplicación con el nombre, audiencia y genera un secreto de cliente especificados. La propiedad writeToEnvironmentFile escribe el identificador de registro de la aplicación, el secreto de cliente, el identificador de objeto, el identificador de inquilino, la autoridad y el host de autoridad en los archivos de entorno. El secreto de cliente se cifra y almacena de forma segura en el archivo env.local.user . El nombre de la variable de entorno para el secreto de cliente tiene el prefijo SECRET_, indica al kit de herramientas de Teams que no escriba el valor en los registros.
La acción aadApp/update actualiza el registro de la aplicación con el archivo de manifiesto especificado.
Centralizar el nombre de la configuración de conexión
En primer lugar, centralice el nombre de la configuración de conexión en el archivo de entorno y actualice la configuración de la aplicación para acceder al valor de la variable de entorno en tiempo de ejecución.
Continuando en Visual Studio y en el proyecto TeamsApp:
En la carpeta env , abra .env.local.
En el archivo, agregue el código siguiente:
CONNECTION_NAME=ProductsAPI
Abrir teamsapp.local.yml
En el archivo, busque el paso que usa la acción file/createOrUpdateJsonFile destinada a ./appsettings. Development.json archivo. Actualice la matriz de contenido para incluir la variable de entorno CONNECTION_NAME y escriba el valor en las appsettings. Development.json archivo:
- uses: file/createOrUpdateJsonFile with: target: ../ProductsPlugin/appsettings.Development.json content: BOT_ID: ${{BOT_ID}} BOT_PASSWORD: ${{SECRET_BOT_PASSWORD}} CONNECTION_NAME: ${{CONNECTION_NAME}}
Save your changes
A continuación, actualice la configuración de la aplicación para acceder a la variable de entorno CONNECTION_NAME .
En el proyecto ProductsPlugin:
Abrir Config.cs
En la clase ConfigOptions , agregue una nueva propiedad denominada CONNECTION_NAME
public class ConfigOptions { public string BOT_ID { get; set; } public string BOT_PASSWORD { get; set; } public string CONNECTION_NAME { get; set; } }
Save your changes
Abra Program.cs
En el archivo, actualice el código que lee la configuración de la aplicación para incluir la propiedad CONNECTION_NAME .
var config = builder.Configuration.Get<ConfigOptions>(); builder.Configuration["MicrosoftAppType"] = "MultiTenant"; builder.Configuration["MicrosoftAppId"] = config.BOT_ID; builder.Configuration["MicrosoftAppPassword"] = config.BOT_PASSWORD; builder.Configuration["ConnectionName"] = config.CONNECTION_NAME;
Save your changes
A continuación, actualice el código del bot para usar el nombre de la configuración de conexión en tiempo de ejecución.
En la carpeta Buscar , abra SearchApp.cs
En la clase SearchApp, cree un constructor que acepte un objeto IConfiguration y asigne el valor de la propiedad CONNECTION_NAME a un campo privado denominado connectionName.
public class SearchApp : TeamsActivityHandler { private readonly string connectionName; public SearchApp(IConfiguration configuration) { connectionName = configuration["CONNECTION_NAME"]; } }
Save your changes
Configuración de la configuración de conexión de products API
Para autenticarse con la API de back-end, debe configurar una configuración de conexión en el recurso bot de Azure.
Continuar en Visual Studio y el proyecto TeamsApp:
En la carpeta infra , abra azure.parameters.local.json
En el archivo, agregue los parámetros backendApiEntraAppClientId, productsApiEntraAppClientId, productsApiEntraAppClientSecret y connectionName .
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "resourceBaseName": { "value": "bot-${{RESOURCE_SUFFIX}}-${{TEAMSFX_ENV}}" }, "botEntraAppClientId": { "value": "${{BOT_ID}}" }, "botDisplayName": { "value": "${{APP_DISPLAY_NAME}}" }, "botAppDomain": { "value": "${{BOT_DOMAIN}}" }, "backendApiEntraAppClientId": { "value": "${{BACKEND_API_ENTRA_APP_ID}}" }, "productsApiEntraAppClientId": { "value": "${{PRODUCTS_API_ENTRA_APP_ID}}" }, "productsApiEntraAppClientSecret": { "value": "${{SECRET_PRODUCTS_API_ENTRA_APP_CLIENT_SECRET}}" }, "connectionName": { "value": "${{CONNECTION_NAME}}" } } }
Save your changes
A continuación, actualice el archivo de Bicep para incluir los nuevos parámetros y pasarlos al recurso bot de Azure.
En la carpeta infra, abra el archivo denominado azure.local.bicep.
En el archivo, después de la declaración del parámetro botAppDomain , agregue las declaraciones de parámetro backendApiEntraAppClientId, productsApiEntraAppClientId, productsApiEntraAppClientSecret y connectionName .
param backendApiEntraAppClientId string param productsApiEntraAppClientId string @secure() param productsApiEntraAppClientSecret string param connectionName string
En la declaración del módulo azureBotRegistration , agregue los nuevos parámetros.
module azureBotRegistration './botRegistration/azurebot.bicep' = { name: 'Azure-Bot-registration' params: { resourceBaseName: resourceBaseName botEntraAppClientId: botEntraAppClientId botAppDomain: botAppDomain botDisplayName: botDisplayName backendApiEntraAppClientId: backendApiEntraAppClientId productsApiEntraAppClientId: productsApiEntraAppClientId productsApiEntraAppClientSecret: productsApiEntraAppClientSecret connectionName: connectionName } }
Guarde los cambios.
Por último, actualice el archivo bicep de registro del bot para incluir la nueva configuración de conexión.
En la carpeta infra/botRegistration, abra azurebot.bicep.
En el archivo, después de la declaración del parámetro botAppDomain , agregue las declaraciones de parámetro backendApiEntraAppClientId, productsApiEntraAppClientId, productsApiEntraAppClientSecret y connectionName .
param backendApiEntraAppClientId string param productsApiEntraAppClientId string @secure() param productsApiEntraAppClientSecret string param connectionName string
En el archivo, cree un nuevo recurso denominado botServicesProductsApiConnection.
resource botServicesProductsApiConnection 'Microsoft.BotService/botServices/connections@2022-09-15' = { parent: botService name: connectionName location: 'global' properties: { serviceProviderDisplayName: 'Azure Active Directory v2' serviceProviderId: '30dd229c-58e3-4a48-bdfd-91ec48eb906c' clientId: productsApiEntraAppClientId clientSecret: productsApiEntraAppClientSecret scopes: 'api://${backendApiEntraAppClientId}/Product.Read' parameters: [ { key: 'tenantID' value: 'common' } { key: 'tokenExchangeUrl' value: 'api://${botAppDomain}/botid-${botEntraAppClientId}' } ] } }
Save your changes
Configuración de la autenticación en la extensión de mensaje
Para autenticar consultas de usuario en la extensión de mensaje, use bot framework SDK para obtener un token de acceso para el usuario desde Bot Framework Token Service. A continuación, el token de acceso se puede usar para acceder a los datos desde un servicio externo.
Para simplificar el código, cree una clase auxiliar que controle la autenticación de usuario.
Continuando en Visual Studio y el proyecto ProductsPlugin:
Creación de una nueva carpeta denominada Helpers
En la carpeta Helpers , cree un nuevo archivo de clase denominado AuthHelpers.cs
En el archivo, agregue el código siguiente:
using Microsoft.Bot.Connector.Authentication; using Microsoft.Bot.Schema; using Microsoft.Bot.Schema.Teams; internal static class AuthHelpers { internal static async Task<MessagingExtensionResponse> CreateAuthResponse(UserTokenClient userTokenClient, string connectionName, Activity activity, CancellationToken cancellationToken) { var resource = await userTokenClient.GetSignInResourceAsync(connectionName, activity, null, cancellationToken); return new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "auth", SuggestedActions = new MessagingExtensionSuggestedAction { Actions = [ new() { Type = ActionTypes.OpenUrl, Value = resource.SignInLink, Title = "Sign In", }, ], }, }, }; } internal static async Task<TokenResponse> GetToken(UserTokenClient userTokenClient, string state, string userId, string channelId, string connectionName, CancellationToken cancellationToken) { var magicCode = string.Empty; if (!string.IsNullOrEmpty(state)) { if (int.TryParse(state, out var parsed)) { magicCode = parsed.ToString(); } } return await userTokenClient.GetUserTokenAsync(userId, connectionName, channelId, magicCode, cancellationToken); } internal static bool HasToken(TokenResponse tokenResponse) => tokenResponse != null && !string.IsNullOrEmpty(tokenResponse.Token); }
Save your changes
Los tres métodos auxiliares de la clase AuthHelpers controlan la autenticación de usuario en la extensión de mensaje.
- El método CreateAuthResponse crea una respuesta que representa un vínculo de inicio de sesión en la interfaz de usuario. El vínculo de inicio de sesión se recupera del servicio de token mediante el método GetSignInResourceAsync .
- El método GetToken usa el cliente del servicio de token para obtener un token de acceso para el usuario actual. El método usa un código mágico para comprobar la autenticidad de la solicitud.
- El método HasToken comprueba si la respuesta del servicio de token contiene un token de acceso. Si el token no es null o está vacío, el método devuelve true.
A continuación, actualice el código de extensión de mensaje para usar los métodos auxiliares para autenticar las consultas de usuario.
En la carpeta Buscar , abra SearchApp.cs
En la parte superior del archivo, agregue la siguiente instrucción using:
using Microsoft.Bot.Connector.Authentication;
En el método OnTeamsMessagingExtensionQueryAsync , agregue el código siguiente al principio del método:
var userTokenClient = turnContext.TurnState.Get<UserTokenClient>(); var tokenResponse = await AuthHelpers.GetToken(userTokenClient, query.State, turnContext.Activity.From.Id, turnContext.Activity.ChannelId, connectionName, cancellationToken); if (!AuthHelpers.HasToken(tokenResponse)) { return await AuthHelpers.CreateAuthResponse(userTokenClient, connectionName, (Activity)turnContext.Activity, cancellationToken); }
Save your changes
A continuación, agregue el dominio de Token Service al archivo de manifiesto de la aplicación para asegurarse de que el cliente puede confiar en el dominio al iniciar un flujo de inicio de sesión único.
En el proyecto TeamsApp:
En la carpeta appPackage , abra manifest.json
En el archivo, actualice la matriz validDomains y agregue el dominio del servicio de token:
"validDomains": [ "token.botframework.com", "${{BOT_DOMAIN}}" ]
Save your changes
Creación y actualización de recursos
Con todo listo, ejecute el proceso Preparar dependencias de aplicaciones de Teams para crear nuevos recursos y actualizar los existentes.
Continuar en Visual Studio:
- En el Explorador de soluciones, haga clic con el botón derecho en el proyecto TeamsApp
- Expanda el menú Kit de herramientas de Teams y seleccione Preparar dependencias de aplicaciones de Teams.
- En el cuadro de diálogo Cuenta de Microsoft 365, seleccione Continuar.
- En el cuadro de diálogo Aprovisionar , seleccione Aprovisionar.
- En el cuadro de diálogo de advertencia del kit de herramientas de Teams , seleccione Aprovisionar.
- En el cuadro de diálogo Información del kit de herramientas de Teams , seleccione el icono cruzado para cerrar el cuadro de diálogo.
Ejecución y depuración
Con los recursos aprovisionados, inicie una sesión de depuración para probar la extensión de mensaje.
Para iniciar una nueva sesión de depuración, presione F5 o seleccione Iniciar en la barra de herramientas.
Espere hasta que se abra una ventana del explorador y aparezca el cuadro de diálogo de instalación de la aplicación en el cliente web de Microsoft Teams. Si se le solicita, escriba las credenciales de la cuenta de Microsoft 365.
En el cuadro de diálogo de instalación de la aplicación, seleccione Agregar.
Abrir un chat de Microsoft Teams nuevo o existente
En el área de redacción de mensajes, seleccione + para abrir el selector de aplicaciones.
En la lista de aplicaciones, seleccione Productos de Contoso para abrir la extensión de mensaje.
En el cuadro de texto, escriba hello
Se muestra un mensaje en el que deberá iniciar sesión para usar esta aplicación .
Siga el vínculo de inicio de sesión para iniciar el flujo de autenticación.
Dar su consentimiento a los permisos solicitados y volver a Microsoft Teams
Espere a que se complete la búsqueda y se muestren los resultados.
En la lista de resultados, seleccione hello para insertar una tarjeta en el cuadro de mensaje de redacción.
Vuelva a Visual Studio y seleccione Detener en la barra de herramientas o presione Mayús + F5 para detener la sesión de depuración.