Ejercicio: Incorporación del inicio de sesión único

Completado

En este ejercicio, agregará el inicio de sesión único a la extensión de mensaje para autenticar las consultas de usuario.

Captura de pantalla de un desafío de autenticación en una extensión de mensaje basada en búsqueda. Se muestra un vínculo para iniciar sesión.

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:

  1. Vaya a Azure Portal.
  2. Abra el menú del portal y seleccione Microsoft Entra ID
  3. Seleccione Registros de aplicaciones y, a continuación, seleccione Nuevo registro.
  4. En el formulario Registrar una aplicación, especifique los valores siguientes:
    1. Nombre: API de productos
    2. Tipos de cuenta de soporte técnico: cuentas en cualquier directorio organizativo (cualquier inquilino de Microsoft Entra ID: multiinquilino)
  5. Seleccione Registrar para crear el registro de la aplicación.
  6. En el menú izquierdo del registro de aplicaciones, seleccione Exponer una API.
  7. Seleccione Add and Save create a new Application ID URI (Agregar y guardar ) para crear un nuevo URI de identificador de aplicación.
  8. En la sección Ámbitos definidos por esta API, seleccione Agregar un ámbito.
  9. En el formulario Agregar un ámbito, especifique los valores siguientes:
    1. Nombre de ámbito: Product.Read
    2. ¿Quién puede dar su consentimiento?: Administradores y usuarios
    3. Nombre para mostrar del consentimiento del administrador: Leer productos
    4. Descripción del consentimiento del administrador: permite que la aplicación lea los datos del producto.
    5. Nombre para mostrar del consentimiento del usuario: Leer productos
    6. Descripción del consentimiento del usuario: permite que la aplicación lea los datos del producto.
    7. Estado: Habilitado
  10. 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.

  1. En el menú izquierdo del registro de la aplicación, seleccione Manifiesto.
  2. Copie el valor de la propiedad appId y guárdelo para su uso posterior.
  3. 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:

  1. En la carpeta env , abra .env.local.

  2. 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>
    
  3. 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:

  1. En la carpeta infra\entra , cree un archivo denominado entra.products.api.manifest.json

  2. 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"
        }
      ]
    }
    
  3. 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:

  1. Abrir teamsapp.local.yml

  2. En el archivo, busque el paso que usa la acción addApp/update .

  3. 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"
    
  4. 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:

  1. En la carpeta env , abra .env.local.

  2. En el archivo, agregue el código siguiente:

    CONNECTION_NAME=ProductsAPI
    
  3. Abrir teamsapp.local.yml

  4. 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}}
    
  5. 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:

  1. Abrir Config.cs

  2. 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; }
    }
    
  3. Save your changes

  4. Abra Program.cs

  5. 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;
    
  6. 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.

  1. En la carpeta Buscar , abra SearchApp.cs

  2. 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"];
      }  
    }
    
  3. 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:

  1. En la carpeta infra , abra azure.parameters.local.json

  2. 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}}"
        }
      }
    }
    
  3. Save your changes

A continuación, actualice el archivo de Bicep para incluir los nuevos parámetros y pasarlos al recurso bot de Azure.

  1. En la carpeta infra, abra el archivo denominado azure.local.bicep.

  2. 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
    
  3. 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
      }
    }
    
  4. Guarde los cambios.

Por último, actualice el archivo bicep de registro del bot para incluir la nueva configuración de conexión.

  1. En la carpeta infra/botRegistration, abra azurebot.bicep.

  2. 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
    
  3. 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}'
          }
        ]
      }
    }
    
  4. 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:

  1. Creación de una nueva carpeta denominada Helpers

  2. En la carpeta Helpers , cree un nuevo archivo de clase denominado AuthHelpers.cs

  3. 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);
    }
    
  4. 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.

  1. En la carpeta Buscar , abra SearchApp.cs

  2. En la parte superior del archivo, agregue la siguiente instrucción using:

    using Microsoft.Bot.Connector.Authentication;
    
  3. 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);
    }
    
  4. 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:

  1. En la carpeta appPackage , abra manifest.json

  2. En el archivo, actualice la matriz validDomains y agregue el dominio del servicio de token:

    "validDomains": [
        "token.botframework.com",
        "${{BOT_DOMAIN}}"
    ]
    
  3. 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:

  1. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto TeamsApp
  2. Expanda el menú Kit de herramientas de Teams y seleccione Preparar dependencias de aplicaciones de Teams.
  3. En el cuadro de diálogo Cuenta de Microsoft 365, seleccione Continuar.
  4. En el cuadro de diálogo Aprovisionar , seleccione Aprovisionar.
  5. En el cuadro de diálogo de advertencia del kit de herramientas de Teams , seleccione Aprovisionar.
  6. 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.

  1. Para iniciar una nueva sesión de depuración, presione F5 o seleccione Iniciar en la barra de herramientas.

  2. 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.

  3. En el cuadro de diálogo de instalación de la aplicación, seleccione Agregar.

  4. Abrir un chat de Microsoft Teams nuevo o existente

  5. En el área de redacción de mensajes, seleccione + para abrir el selector de aplicaciones.

  6. En la lista de aplicaciones, seleccione Productos de Contoso para abrir la extensión de mensaje.

  7. En el cuadro de texto, escriba hello

  8. Se muestra un mensaje en el que deberá iniciar sesión para usar esta aplicación .

    Captura de pantalla de un desafío de autenticación en una extensión de mensaje basada en búsqueda. Se muestra un vínculo para iniciar sesión.

  9. Siga el vínculo de inicio de sesión para iniciar el flujo de autenticación.

  10. Dar su consentimiento a los permisos solicitados y volver a Microsoft Teams

    Captura de pantalla del cuadro de diálogo de consentimiento de permisos de microsoft Entra API.

  11. Espere a que se complete la búsqueda y se muestren los resultados.

  12. 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.