Crear un complemento de Node.js Office que usa el inicio de sesión único

Los usuarios pueden iniciar sesión en Office, y el complemento de Office Web puede aprovecharse de este proceso de inicio de sesión para autorizar a los usuarios a su complemento y a Microsoft Graph sin necesitar que los usuarios inicien sesión por segunda vez. Para obtener información general, vea Habilitar SSO en un complemento de Office.

Este artículo le guiará por el proceso de habilitación del inicio de sesión único (SSO) en un complemento. El complemento de ejemplo que cree tiene dos partes; un panel de tareas que se carga en Microsoft Excel y un servidor de nivel intermedio que controla las llamadas a Microsoft Graph para el panel de tareas. El servidor de nivel intermedio se compila con Node.js y Express y expone una única API REST, /getuserfilenames, que devuelve una lista de los primeros 10 nombres de archivo en la carpeta de OneDrive del usuario. El panel de tareas usa el getAccessToken() método para obtener un token de acceso para el usuario que ha iniciado sesión en el servidor de nivel intermedio. El servidor de nivel intermedio usa el flujo en nombre de (OBO) para intercambiar el token de acceso por uno nuevo con acceso a Microsoft Graph. Puede ampliar este patrón para acceder a cualquier dato de Microsoft Graph. El panel de tareas siempre llama a una API REST de nivel intermedio (pasando el token de acceso) cuando necesita servicios de Microsoft Graph. El nivel intermedio usa el token obtenido a través de OBO para llamar a los servicios de Microsoft Graph y devolver los resultados al panel de tareas.

Este artículo funciona con un complemento que usa Node.js y Express. Para obtener un artículo similar sobre un complemento basado en ASP.NET, vea Crear un complemento de ASP.NET Office que usa el inicio de sesión único.

Requisitos previos

  • Node.js (la última versión de LTS)

  • Git Bash (u otro cliente de GIT)

  • Editor de código: se recomienda Visual Studio Code

  • Al menos algunos archivos y carpetas almacenados en OneDrive para la Empresa en la suscripción de Microsoft 365

  • Compilación de Microsoft 365 que admite el conjunto de requisitos de IdentityAPI 1.3. Puede calificar para una suscripción de desarrollador de Microsoft 365 E5, que incluye un espacio aislado para desarrolladores, a través del Programa para desarrolladores de Microsoft 365; para obtener más información, consulte las preguntas más frecuentes. El espacio aislado para desarrolladores incluye una suscripción de Microsoft Azure que puede usar para los registros de aplicaciones en los pasos posteriores de este artículo. Si lo prefiere, puede usar una suscripción de Microsoft Azure independiente para los registros de aplicaciones. Obtenga una suscripción de prueba en Microsoft Azure.

Configurar el proyecto de inicio

  1. Clone o descargue el repositorio en Office Add-in NodeJS SSO.

    Nota:

    Existen dos versiones del ejemplo:

    • La carpeta Begin es un proyecto de inicio. La interfaz de usuario y otros aspectos del complemento que no están conectados directamente al SSO o a la autorización ya están listos. Las secciones posteriores de este artículo le guiarán a través del proceso para completarlo.
    • La carpeta Complete contiene el mismo ejemplo con todos los pasos de codificación de este artículo completados. Para usar la versión completada, siga las instrucciones de este artículo, pero reemplace "Begin" por "Complete" (Completar) y omita las secciones Code the client side (Código del lado cliente ) y Code the middle-tier server side (Código del servidor de nivel intermedio ).
  2. Abra un símbolo del sistema en la carpeta Begin .

  3. Escriba npm install en la consola para instalar todas las dependencias detalladas en el archivo package.json.

  4. Ejecute el comando npm run install-dev-certs. Seleccione en la solicitud para instalar el certificado.

Use los siguientes valores para los marcadores de posición para los pasos de registro de aplicaciones posteriores.

Marcador de posición Valor
<add-in-name> Office-Add-in-NodeJS-SSO
<fully-qualified-domain-name> localhost:3000
Permisos de Microsoft Graph profile, openid, Files.Read

Registre el complemento con Plataforma de identidad de Microsoft

Debe crear un registro de aplicación en Azure que represente el servidor web. Esto permite la compatibilidad con la autenticación para que se puedan emitir tokens de acceso adecuados al código de cliente en JavaScript. Este registro admite tanto el inicio de sesión único en el cliente como la autenticación de reserva mediante la biblioteca de autenticación de Microsoft (MSAL).

  1. Inicie sesión en el Azure Portal con las credenciales de administrador en el inquilino de Microsoft 365. Por ejemplo, MyName@contoso.onmicrosoft.com.

  2. Seleccione Registros de aplicaciones. Si no ve el icono, busque "Registro de aplicaciones" en la barra de búsqueda.

    Página principal Azure Portal.

    Aparece la página Registros de aplicaciones.

  3. Seleccione Nuevo registro.

    Nuevo registro en el panel Registros de aplicaciones.

    Aparece la página Registrar una aplicación.

  4. En la página Registrar una aplicación, establezca los valores siguientes.

    • Establezca Nombre como <add-in-name>.
    • Establezca Tipos de cuenta admitidosen Cuentas en cualquier directorio organizativo (cualquier directorio de Azure AD: multiinquilino) y cuentas personales de Microsoft (por ejemplo, Skype, Xbox).
    • Establezca el URI de redirección para usar la aplicación de página única (SPA) de la plataforma y el URI en https://<fully-qualified-domain-name>/dialog.html.

    Registre un panel de aplicación con el nombre y la cuenta admitida completadas.

  5. Seleccione Registrar. Se muestra un mensaje que indica que se creó el registro de la aplicación.

    Mensaje que indica que se creó el registro de la aplicación.

  6. Copie y guarde los valores para el identificador de aplicación (cliente) y el identificador de directorio (inquilino). Deberá usar ambos en procedimientos posteriores.

    Panel de registro de aplicaciones para Contoso que muestra el identificador de cliente y el identificador de directorio.

Adición de un secreto de cliente

A veces denominado contraseña de aplicación, un secreto de cliente es un valor de cadena que la aplicación puede usar en lugar de un certificado para la identidad propia.

  1. En el panel izquierdo, seleccione Certificados & secretos. A continuación, en la pestaña Secretos de cliente, seleccione Nuevo secreto de cliente.

    El panel Certificados & secretos.

    Aparece el panel Agregar un secreto de cliente .

  2. Agregue una descripción para el secreto de cliente.

  3. Seleccione una expiración para el secreto o especifique una duración personalizada.

    • La duración del secreto de cliente está limitada a dos años (24 meses) o menos. No se puede especificar una duración personalizada de más de 24 meses.
    • Microsoft recomienda establecer un valor de expiración de menos de 12 meses.

    Agregue un panel secreto de cliente con la descripción y expire completado.

  4. Seleccione Agregar. Se crea el nuevo secreto y se muestra temporalmente el valor.

Importante

Registre el valor del secreto para usarlo en el código de la aplicación cliente. Este valor secreto nunca se vuelve a mostrar después de salir de este panel.

Exponer una API web

  1. En el panel izquierdo, seleccione Exponer una API.

    Aparece el panel Exponer una API .

    El panel Exponer una API de un registro de aplicación.

  2. Seleccione Establecer para generar un URI de identificador de aplicación.

    Botón Establecer en el panel Exponer una API del registro de la aplicación.

    La sección para establecer el URI del identificador de aplicación aparece con un URI de identificador de aplicación generado con el formato api://<app-id>.

  3. Actualice el URI del identificador de aplicación a api://<fully-qualified-domain-name>/<app-id>.

    Edite el panel URI del identificador de aplicación con el puerto localhost establecido en 44355.

    • El URI de id. de aplicación se rellena previamente con el identificador de aplicación (GUID) con el formato api://<app-id>.
    • El formato uri del identificador de aplicación debe ser: api://<fully-qualified-domain-name>/<app-id>
    • Inserte el fully-qualified-domain-name valor entre api:// y <app-id> (que es un GUID). Por ejemplo, api://contoso.com/<app-id>.
    • Si usa localhost, el formato debe ser api://localhost:<port>/<app-id>. Por ejemplo, api://localhost:3000/c6c1f32b-5e55-4997-881a-753cc1d563b7.

    Para obtener más detalles sobre el URI del identificador de aplicación, consulte Identificador de manifiesto de aplicaciónInquilinouris.

    Nota:

    Si recibe un error que indica que el dominio ya tiene propietario, pero es usted su propietario, siga el procedimiento de Inicio rápido: agregar un nombre de dominio personalizado a Azure Active Directory para registrarlo y repita este paso. (Este error también puede producirse si no ha iniciado sesión con las credenciales de un administrador en el inquilino de Microsoft 365. Consulte el paso 2. Cierre la sesión e inicie sesión de nuevo con las credenciales de administrador y repita el proceso desde el paso 3).

Agregar un ámbito

  1. En la página Exponer una API , seleccione Agregar un ámbito.

    Seleccione el botón Agregar un ámbito.

    Se abre el panel Agregar un ámbito .

  2. En el panel Agregar un ámbito , especifique los atributos del ámbito. En la tabla siguiente se muestran los valores de ejemplo para y el complemento de Outlook que requieren los profilepermisos , openid, Files.ReadWritey Mail.Read . Modifique el texto para que coincida con los permisos que necesita el complemento.

    Campo Description Valores
    Nombre de ámbito Nombre del ámbito. Una convención de nomenclatura de ámbito común es resource.operation.constraint. Para el inicio de sesión único, debe establecerse en access_as_user.
    Quién puede dar su consentimiento Determina si se requiere el consentimiento del administrador o si los usuarios pueden dar su consentimiento sin la aprobación del administrador. Para aprender el inicio de sesión único y los ejemplos, se recomienda establecerlo en Administradores y usuarios.

    Seleccione Solo administradores para permisos con privilegios superiores.
    Administración nombre para mostrar del consentimiento Una breve descripción del propósito del ámbito visible solo para los administradores. Read/write permissions to user files. Read permissions to user mail and profiles.
    Administración descripción del consentimiento Una descripción más detallada del permiso concedido por el ámbito que solo ven los administradores. Allow Office to have read/write permissions to all user files and read permissions to all user mail. Office can call the app's web APIs as the current user.
    Nombre para mostrar del consentimiento del usuario Breve descripción del propósito del ámbito. Se muestra a los usuarios solo si establece Who can consent to Admins and users (Quién puede dar su consentimiento a administradores y usuarios). Read/write permissions to your files. Read permissions to your mail and profile.
    Descripción del consentimiento del usuario Descripción más detallada del permiso concedido por el ámbito. Se muestra a los usuarios solo si establece Who can consent to Admins and users (Quién puede dar su consentimiento a administradores y usuarios). Allow Office to have read/write permissions to your files, and read permissions to your mail and profile.
  3. Establezca Estadoen Habilitado y, a continuación, seleccione Agregar ámbito.

    Establezca el estado en habilitado y seleccione el botón Agregar ámbito.

    El nuevo ámbito definido se muestra en el panel.

    Nuevo ámbito que se muestra en el panel Exponer una API.

    Nota:

    La parte del dominio del Nombre de ámbito que aparece justo debajo del campo de texto debe coincidir automáticamente con el URI de identificador de aplicación establecido en el paso anterior, con /access_as_user anexado al final; por ejemplo, api://localhost:6789/c6c1f32b-5e55-4997-881a-753cc1d563b7/access_as_user.

  4. Seleccione Agregar una aplicación cliente.

    Seleccione Agregar una aplicación cliente.

    Aparece el panel Agregar una aplicación cliente .

  5. En Id . de cliente , escriba ea5a67f6-b6f3-4338-b240-c655ddc3cc8e. Este valor autoriza previamente todos los puntos de conexión de aplicación de Microsoft Office. Si también desea autorizar previamente Office cuando se usa dentro de Microsoft Teams, agregue 1fec8e78-bce4-4aaf-ab1b-5451cc387264 (escritorio de Microsoft Teams y dispositivos móviles de Teams) y 5e3ce6c0-2b1f-4285-8d4b-75ee78787346 (Teams en la web).

    Nota:

    El ea5a67f6-b6f3-4338-b240-c655ddc3cc8e identificador autoriza previamente a Office en todas las plataformas siguientes. Como alternativa, puede escribir un subconjunto adecuado de los siguientes identificadores si, por cualquier motivo, desea denegar la autorización a Office en algunas plataformas. Si lo hace, deje fuera los identificadores de las plataformas desde las que desea retener la autorización. Los usuarios del complemento en esas plataformas no podrán llamar a las API web, pero otras funciones del complemento seguirán funcionando.

    • d3590ed6-52b3-4102-aeff-aad2292ab01c (Microsoft Office)
    • 93d53678-613d-4013-afc1-62e9e444a0a5 (Office en la Web)
    • bc59ab01-8403-45c6-8796-ac3ef710b3e3 (Outlook en la Web)
  6. En Ámbitos autorizados, active la api://<fully-qualified-domain-name>/<app-id>/access_as_user casilla .

  7. Seleccione Agregar aplicación.

    Panel Agregar una aplicación cliente.

Adición de permisos de Microsoft Graph

  1. En el panel izquierdo, seleccione Permisos de API.

    Panel Permisos de API.

    Se abre el panel Permisos de API .

  2. Seleccione Agregar un permiso

    Agregar un permiso en el panel permisos de API.

    Se abre el panel Solicitar permisos de API .

  3. Seleccione Microsoft Graph.

    El panel Solicitar permisos de API con el botón Microsoft Graph.

  4. Seleccione Permisos delegados

    El panel Solicitar permisos de API con permisos delegados.

  5. En el cuadro de búsqueda Seleccionar permisos , busque los permisos que necesita el complemento. Por ejemplo, para un complemento de Outlook, puede usar profile, openid, Files.ReadWritey Mail.Read.

    Nota:

    El permiso User.Read podría aparecer ya de forma predeterminada. Se recomienda solicitar solo los permisos necesarios, por lo que se recomienda desactivar la casilla para este permiso si el complemento no lo necesita realmente.

  6. Active la casilla para cada permiso tal como aparece. Tenga en cuenta que los permisos no permanecerán visibles en la lista a medida que seleccione cada uno de ellos. Después de seleccionar los permisos que necesita el complemento, seleccione Agregar permisos.

    El panel Solicitar permisos de API con algunos permisos seleccionados.

  7. Seleccione Conceder consentimiento de administrador para [nombre de inquilino]. Seleccione para la confirmación que aparece.

Configuración de la versión del token de acceso

Debe definir la versión del token de acceso que sea aceptable para la aplicación. Esta configuración se realiza en el manifiesto de aplicación de Azure Active Directory.

Definición de la versión del token de acceso

La versión del token de acceso puede cambiar si elige un tipo de cuenta distinto de Cuentas en cualquier directorio organizativo (cualquier directorio de Azure AD: multiinquilino) y cuentas personales de Microsoft (por ejemplo, Skype, Xbox). Siga estos pasos para asegurarse de que la versión del token de acceso es correcta para el uso del inicio de sesión único de Office.

  1. En el panel izquierdo, seleccione Manifiesto.

    Seleccione Manifiesto de Azure.

    Aparece el manifiesto de aplicación de Azure Active Directory.

  2. Introduzca 2 como valor de la accessTokenAcceptedVersion propiedad.

    Valor de la versión del token de acceso aceptado.

  3. Seleccione Guardar.

    Aparece un mensaje en el explorador que indica que el manifiesto se actualizó correctamente.

    Mensaje actualizado del manifiesto.

Enhorabuena. Ha completado el registro de la aplicación para habilitar el inicio de sesión único para el complemento de Office.

Configurar el complemento

  1. Abra la carpeta \Begin del proyecto clonado en el editor de código.

  2. Abra el .ENV archivo y use los valores que copió anteriormente del registro de la aplicación Office-Add-in-NodeJS-SSO . Establezca los valores como se indica a continuación:

    Nombre Valor
    CLIENT_ID Id. de aplicación (cliente) de la página de información general del registro de la aplicación.
    CLIENT_SECRET Secreto de cliente guardado en la página Certificados & secretos .

    Los valores no deben estar entre comillas. Cuando termine, el archivo debería ser similar al siguiente:

    CLIENT_ID=8791c036-c035-45eb-8b0b-265f43cc4824
    CLIENT_SECRET=X7szTuPwKNts41:-/fa3p.p@l6zsyI/p
    NODE_ENV=development
    SERVER_SOURCE=<https://localhost:3000>
    
  3. Abra el archivo de manifiesto de complemento "manifest\manifest_local.xml" y, después, desplácese hasta la parte inferior del archivo. Justo encima de la </VersionOverrides> etiqueta final, encontrará el marcado siguiente.

    <WebApplicationInfo>
      <Id>$app-id-guid$</Id>
      <Resource>api://localhost:3000/$app-id-guid$</Resource>
      <Scopes>
          <Scope>Files.Read</Scope>
          <Scope>profile</Scope>
          <Scope>openid</Scope>
      </Scopes>
    </WebApplicationInfo>
    
  4. Reemplace el marcador de posición "$app-id-guid$" en ambos lugares del marcado por el identificador de aplicación que copió al crear el registro de la aplicación Office-Add-in-NodeJS-SSO . Los símbolos "$" no forman parte del identificador, por lo que no los incluya. Este es el mismo identificador que usó para la CLIENT_ID en . Archivo ENV.

    Nota:

    El <valor de Recurso> es el URI del identificador de aplicación que estableció al registrar el complemento. La <sección Ámbitos> solo se usa para generar un cuadro de diálogo de consentimiento si el complemento se vende a través de AppSource.

  5. Abra el archivo \public\javascripts\fallback-msal\authConfig.js. Reemplace el marcador de posición "$app-id-guid$" por el identificador de aplicación que guardó en el registro de la aplicación Office-Add-in-NodeJS-SSO que creó anteriormente.

  6. Guarde los cambios realizados en el archivo.

Codificar el lado cliente

Llamada a nuestra API REST del servidor web

  1. Abra el archivo public\javascripts\ssoAuthES6.js en el editor de código. Ya tiene código que garantiza que se admiten las promesas, incluso en el control de vista web Trident (Internet Explorer 11) y una Office.onReady llamada para asignar un controlador al único botón del complemento.

    Nota:

    Como el nombre sugiere, ssoAuthES6.js usa la sintaxis ES6 de JavaScript porque el uso de async y await muestra mejor la simplicidad esencial de la API de SSO. Cuando se inicia el servidor localhost, este archivo se transpila a la sintaxis ES5 para que el ejemplo admita Trident.

  2. En la función getFileNameList, reemplace TODO 1 por el siguiente código. Sobre este código, tenga en cuenta:

    • Se llama a la función getFileNameList cuando el usuario elige el botón Obtener nombres de archivo de OneDrive en el panel de tareas.
    • Llama a la callWebServerAPI función que especifica a qué API REST llamar. Esto devuelve JSON que contiene una lista de nombres de archivo de OneDrive del usuario.
    • El json se pasa a la writeFileNamesToOfficeDocument función para enumerar los nombres de archivo del documento.
    try {
        const jsonResponse = await callWebServerAPI('GET', '/getuserfilenames');
        if (jsonResponse === null) {
            // Null is returned when a message was displayed to the user
            // regarding an authentication error that cannot be resolved.
            return;
        }
        await writeFileNamesToOfficeDocument(jsonResponse);
        showMessage('Your OneDrive filenames are added to the document.');
    } catch (error) {
        console.log(error.message);
        showMessage(error.message);
    }
    
  3. En la función callWebServerAPI, reemplace TODO 2 por el siguiente código. Sobre este código, tenga en cuenta:

    • La función llama a getAccessToken nuestra propia función que encapsula mediante el inicio de sesión único de Office o la reserva de MSAL según sea necesario para obtener el token. Si devuelve un token null, se muestra un mensaje para una condición de error de autenticación que no se puede resolver, por lo que la función también devuelve null.
    • La función usa la fetch API para llamar al servidor web y, si se ejecuta correctamente, devuelve el cuerpo JSON.
    const accessToken = await getAccessToken(authSSO);
    if (accessToken === null) {
        return null;
    }
    const response = await fetch(path, {
        method: method,
        headers: {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + accessToken,
        },
    });
    
    // Check for success condition: HTTP status code 2xx.
    if (response.ok) {
        return response.json();
    }
    
  4. En la función callWebServerAPI, reemplace TODO 3 por el siguiente código. Sobre este código, tenga en cuenta:

    • Este código controla el escenario en el que expiró el token de SSO. Si es así, debemos llamar Office.auth.getAccessToken a para obtener un token actualizado. La manera más sencilla es realizar una llamada recursiva que da como resultado una nueva llamada a Office.auth.getAccessToken. El retryRequest parámetro garantiza que la llamada recursiva solo se intenta una vez.
    • Nuestro TokenExpiredError servidor web establece la cadena cada vez que detecta un token expirado.
     // Check for fail condition: Is SSO token expired? If so, retry the call which will get a refreshed token.
    const jsonBody = await response.json();
    if (
        authSSO === true &&
        jsonBody != null &&
        jsonBody.type === 'TokenExpiredError'
    ) {
        if (!retryRequest) {
            return callWebServerAPI(method, path, true); // Try the call again. The underlying call to Office JS getAccessToken will refresh the token.
        } else {
            // Indicates a second call to retry and refresh the token failed.
            authSSO = false;
            return callWebServerAPI(method, path, true); // Try the call again, but now using MSAL fallback auth.
        }
    }
    
  5. En la función callWebServerAPI, reemplace TODO 4 por el siguiente código. Sobre este código, tenga en cuenta:

    • El Microsoft Graph servidor web establece la cadena cada vez que se produce un error en una llamada a Microsoft Graph.
    // Check for fail condition: Did we get a Microsoft Graph API error, which is returned as bad request (403)?
    if (response.status === 403 && jsonBody.type === 'Microsoft Graph') {
        throw new Error('Microsoft Graph error: ' + jsonBody.errorDetails);
    }
    
  6. En la función callWebServerAPI, reemplace TODO 5 por el siguiente código.

    // Handle other errors.
    throw new Error(
        'Unknown error from web server: ' + JSON.stringify(jsonBody)
    );
    
  7. En la función getAccessToken, reemplace TODO 6 por el siguiente código. Sobre este código, tenga en cuenta:

    • authSSO realiza un seguimiento de si se usa el inicio de sesión único o si se usa la reserva de MSAL. Si se usa sso, la función llama a Office.auth.getAccessToken y devuelve el token.
    • La función controla handleSSOErrors los errores, que devolverá un token si cambia a la autenticación MSAL de reserva.
    • La autenticación de reserva usa la biblioteca MSAL para iniciar sesión en el usuario. El propio complemento es un SPA y usa un registro de aplicación SPA para acceder al servidor web.
    if (authSSO) {
        try {
            // Get the access token from Office host using SSO.
            // Note that Office.auth.getAccessToken modifies the options parameter. Create a copy of the object
            // to avoid modifying the original object.
            const options = JSON.parse(JSON.stringify(ssoOptions));
            const token = await Office.auth.getAccessToken(options);
            return token;
        } catch (error) {
            console.log(error.message);
            return handleSSOErrors(error);
        }
    } else {
        // Get access token through MSAL fallback.
        try {
            const accessToken = await getAccessTokenMSAL();
            return accessToken;
        } catch (error) {
            console.log(error);
            throw new Error(
                'Cannot get access token. Both SSO and fallback auth failed. ' +
                    error
            );
        }
    }
    
  8. En la función handleSSOErrors, reemplace TODO 7 por el siguiente código. Para obtener más información sobre estos errores, vea Solucionar problemas de SSO en los complementos de Office.

    switch (error.code) {
        case 13001:
            // No one is signed into Office. If the add-in cannot be effectively used when no one
            // is logged into Office, then the first call of getAccessToken should pass the
            // `allowSignInPrompt: true` option. Since this sample does that, you should not see
            // this error.
            showMessage(
                'No one is signed into Office. But you can use many of the add-ins functions anyway. If you want to log in, press the Get OneDrive File Names button again.'
            );
            break;
        case 13002:
            // The user aborted the consent prompt. If the add-in cannot be effectively used when consent
            // has not been granted, then the first call of getAccessToken should pass the `allowConsentPrompt: true` option.
            showMessage(
                'You can use many of the add-ins functions even though you have not granted consent. If you want to grant consent, press the Get OneDrive File Names button again.'
            );
            break;
        case 13006:
            // Only seen in Office on the web.
            showMessage(
                'Office on the web is experiencing a problem. Please sign out of Office, close the browser, and then start again.'
            );
            break;
        case 13008:
            // Only seen in Office on the web.
            showMessage(
                'Office is still working on the last operation. When it completes, try this operation again.'
            );
            break;
        case 13010:
            // Only seen in Office on the web.
            showMessage(
                "Follow the instructions to change your browser's zone configuration."
            );
            break;
    
  9. Reemplace TODO 8 por el código siguiente. Para los errores que no se pueden controlar, el código cambia a la autenticación de reserva mediante MSAL.

    default: //recursive call.
            // For all other errors, including 13000, 13003, 13005, 13007, 13012, and 50001, fall back
            // to MSAL sign-in.
            showMessage('SSO failed. Trying fallback auth.');
            authSSO = false;
            return getAccessToken(false);
    }
    return null; // Return null for errors that show a message to the user.
    

Codificación de la API REST del servidor web

El servidor web proporciona API REST para que el cliente llame. Por ejemplo, la API /getuserfilenames REST obtiene una lista de nombres de archivo de la carpeta de OneDrive del usuario. Cada llamada a la API REST requiere un token de acceso por parte del cliente para asegurarse de que el cliente correcto tiene acceso a sus datos. El token de acceso se intercambia por un token de Microsoft Graph a través del flujo en nombre de (OBO). La biblioteca MSAL almacena en caché el nuevo token de Microsoft Graph para las llamadas API posteriores. Nunca se envía fuera del servidor web. Para obtener más información, consulte Solicitud de token de acceso de nivel intermedio.

Creación de la ruta e implementación del flujo en nombre de

  1. Abra el archivo routes\getFilesRoute.js y reemplace por TODO 9 el código siguiente. Sobre este código, tenga en cuenta:

    • Llama a authHelper.validateJwt. Esto garantiza que el token de acceso es válido y no se ha alterado.
    • Para obtener más información, consulte Validación de tokens.
    router.get(
     "/getuserfilenames",
     authHelper.validateJwt,
     async function (req, res) {
       // TODO 10: Exchange the access token for a Microsoft Graph token
       //          by using the OBO flow.
     }
    );
    
  2. Reemplace TODO 10 por el código siguiente. Sobre este código, tenga en cuenta:

    • Solo solicita los ámbitos mínimos que necesita, como files.read.
    • Usa MSAL authHelper para realizar el flujo de OBO en la llamada a acquireTokenOnBehalfOf.
    try {
      const authHeader = req.headers.authorization;
      let oboRequest = {
        oboAssertion: authHeader.split(' ')[1],
        scopes: ["files.read"],
      };
    
      // The Scope claim tells you what permissions the client application has in the service.
      // In this case we look for a scope value of access_as_user, or full access to the service as the user.
      const tokenScopes = jwt.decode(oboRequest.oboAssertion).scp.split(' ');
      const accessAsUserScope = tokenScopes.find(
        (scope) => scope === 'access_as_user'
      );
      if (!accessAsUserScope) {
        res.status(401).send({ type: "Missing access_as_user" });
        return;
      }
      const cca = authHelper.getConfidentialClientApplication();
      const response = await cca.acquireTokenOnBehalfOf(oboRequest);
      // TODO 11: Call Microsoft Graph to get list of filenames.
    } catch (err) {
      // TODO 12: Handle any errors.
    }
    
  3. Reemplace TODO 11 por el código siguiente. Sobre este código, tenga en cuenta:

    • Construye la dirección URL de la llamada de Microsoft Graph API y, a continuación, realiza la llamada a través de la getGraphData función .
    • Devuelve errores enviando una respuesta HTTP 500 junto con detalles.
    • Si se ejecuta correctamente, devuelve el ARCHIVO JSON con la lista de nombres de archivo al cliente.
    // Minimize the data that must come from MS Graph by specifying only the property we need ("name")
    // and only the top 10 folder or file names.
    const rootUrl = '/me/drive/root/children';
    
    // Note that the last parameter, for queryParamsSegment, is hardcoded. If you reuse this code in
    // a production add-in and any part of queryParamsSegment comes from user input, be sure that it is
    // sanitized so that it cannot be used in a Response header injection attack.
    const params = '?$select=name&$top=10';
    
    const graphData = await getGraphData(
      response.accessToken,
      rootUrl,
      params
    );
    
    // If Microsoft Graph returns an error, such as invalid or expired token,
    // there will be a code property in the returned object set to a HTTP status (e.g. 401).
    // Return it to the client. On client side it will get handled in the fail callback of `makeWebServerApiCall`.
    if (graphData.code) {
      res
        .status(403)
        .send({
          type: "Microsoft Graph",
          errorDetails:
            "An error occurred while calling the Microsoft Graph API.\n" +
            graphData,
        });
    } else {
      // MS Graph data includes OData metadata and eTags that we don't need.
      // Send only what is actually needed to the client: the item names.
      const itemNames = [];
      const oneDriveItems = graphData["value"];
      for (let item of oneDriveItems) {
        itemNames.push(item["name"]);
      }
    
      res.status(200).send(itemNames);
    }
    // TODO 12: Check for expired token.
    
  4. Reemplace TODO 12 por el código siguiente. Este código comprueba específicamente si el token expiró porque el cliente puede solicitar un nuevo token y volver a llamar a.

    } catch (err) {
       // On rare occasions the SSO access token is unexpired when Office validates it,
       // but expires by the time it is used in the OBO flow. Microsoft identity platform will respond
       // with "The provided value for the 'assertion' is not valid. The assertion has expired."
       // Construct an error message to return to the client so it can refresh the SSO token.
       if (err.errorMessage.indexOf('AADSTS500133') !== -1) {
         res.status(401).send({ type: "TokenExpiredError", errorDetails: err });
       } else {
         res.status(403).send({ type: "Unknown", errorDetails: err });
       }
    }
    

El ejemplo debe controlar la autenticación de reserva a través de MSAL y la autenticación sso a través de Office. El ejemplo probará primero el inicio de sesión único y el authSSO valor booleano en la parte superior del archivo realiza un seguimiento si el ejemplo usa sso o ha cambiado a la autenticación de reserva.

Ejecutar el proyecto

  1. Asegúrese de que tiene algunos archivos en OneDrive para que pueda comprobar los resultados.

  2. Abra un símbolo del sistema en la raíz de la carpeta \Begin.

  3. Ejecute el comando npm install para instalar todas las dependencias del paquete.

  4. Ejecute el comando npm start para iniciar el servidor de nivel intermedio.

  5. Debe transferir el complemento a una aplicación de Office (Excel, Word o PowerPoint) para probarlo. Las instrucciones dependen de la plataforma. Hay vínculos a instrucciones en Transferir un complemento de Office para probarlo.

  6. En la aplicación de Office, en la cinta de opciones Inicio, seleccione el botón Mostrar complemento en el grupo SSO Node.js para abrir el complemento del panel de tareas.

  7. Haga clic en el botón Obtener nombres de archivo de OneDrive. Si ha iniciado sesión en Office con una cuenta Microsoft 365 Educación o profesional, o una cuenta de Microsoft, y el inicio de sesión único funciona según lo esperado, los primeros 10 nombres de archivo y carpeta de la OneDrive para la Empresa se insertan en el documento. (Puede tardar hasta 15 segundos la primera vez). Si no ha iniciado sesión o está en un escenario que no admite el inicio de sesión único o el inicio de sesión único no funciona por ningún motivo, se le pedirá que inicie sesión. Después de iniciar sesión, aparecen los nombres de archivo y carpeta.

Nota:

Si ha iniciado sesión previamente en Office con un identificador distinto y algunas aplicaciones de Office que estaban abiertas en el momento siguen abiertas, es posible que Office no cambie el identificador de manera confiable aunque parezca haberlo hecho. Si esto ocurre, puede que la llamada a Microsoft Graph no se realice o que se devuelvan datos del identificador anterior. Para evitarlo, asegúrese de cerrar las demás aplicaciones de Office antes de presionar Obtener los nombres de archivos de OneDrive.

Notas de seguridad

  • La /getuserfilenames ruta en getFilesroute.js usa una cadena literal para redactar la llamada a Microsoft Graph. Si cambia la llamada para que cualquier parte de la cadena provenga de la entrada del usuario, desintegre la entrada para que no se pueda usar en un ataque de inyección de encabezado de respuesta.

  • En app.js la siguiente directiva de seguridad de contenido está en vigor para los scripts. Es posible que desee especificar restricciones adicionales en función de las necesidades de seguridad del complemento.

    "Content-Security-Policy": "script-src https://appsforoffice.microsoft.com https://ajax.aspnetcdn.com https://alcdn.msauth.net " + process.env.SERVER_SOURCE,

Siga siempre los procedimientos recomendados de seguridad en la documentación de Plataforma de identidad de Microsoft.