Crie um Suplemento do Office com Node.js que use logon único

Os usuários podem entrar no Office, e o Suplemento Web do Office pode aproveitar esse processo de entrada para autorizá-los a acessar seu suplemento e o Microsoft Graph sem exigir que os eles entrem uma segunda vez. Confira uma visão geral no artigo Habilitar o SSO em um Suplemento do Office.

Este artigo orienta você sobre o processo de habilitação do SSO (logon único) em um suplemento. O suplemento de exemplo que você cria tem duas partes; um painel de tarefas que carrega no Microsoft Excel e um servidor de camada média que manipula chamadas para o Microsoft Graph para o painel de tarefas. O servidor de camada intermediária é criado com Node.js e Express e expõe uma única API REST, /getuserfilenames, que retorna uma lista dos primeiros 10 nomes de arquivo na pasta OneDrive do usuário. O painel de tarefas usa o getAccessToken() método para obter um token de acesso para o usuário conectado ao servidor de camada intermediária. O servidor de camada intermediária usa o OBO (fluxo em nome de nome) para trocar o token de acesso por um novo com acesso ao Microsoft Graph. Você pode estender esse padrão para acessar todos os dados do Microsoft Graph. O painel de tarefas sempre chama uma API REST de camada intermediária (passando o token de acesso) quando precisa de serviços do Microsoft Graph. A camada intermediária usa o token obtido via OBO para chamar os serviços do Microsoft Graph e retornar os resultados para o painel de tarefas.

Este artigo funciona com um suplemento que usa Node.js e Express. Para ler um artigo semelhante sobre um suplemento baseado em ASP.NET, confira Criar um Suplemento do Office com ASP.NET que usa o logon único.

Pré-requisitos

  • Node.js (a versão mais recente de LTS)

  • Git Bash (ou outro cliente Git)

  • Um editor de código - recomendamos Visual Studio Code

  • Pelo menos alguns arquivos e pastas armazenados em OneDrive for Business na assinatura do Microsoft 365

  • Um build do Microsoft 365 que aceita o conjunto de requisitos do IdentityAPI 1.3. Você pode se qualificar para uma assinatura de desenvolvedor Microsoft 365 E5, que inclui uma área restrita do desenvolvedor, por meio do Programa de Desenvolvedor do Microsoft 365; para obter detalhes, consulte as perguntas frequentes. A área restrita do desenvolvedor inclui uma assinatura do Microsoft Azure que você pode usar para registros de aplicativo em etapas posteriores neste artigo. Se preferir, você pode usar uma assinatura separada do Microsoft Azure para registros de aplicativo. Obtenha uma assinatura de avaliação no Microsoft Azure.

Configure o projeto inicial

  1. Clone ou baixe o repositório em SSO com Suplemento NodeJS do Office.

    Observação

    Há duas versões do exemplo:

    • A pasta Begin é um projeto inicial. A interface do usuário e outros aspectos do suplemento que não estão diretamente ligados ao SSO ou à autorização já estão prontos. As próximas seções deste artigo apresentam uma orientação passo a passo para concluir o projeto.
    • A pasta Concluir contém o mesmo exemplo com todas as etapas de codificação deste artigo concluídas. Para usar a versão concluída, basta seguir as instruções neste artigo, mas substituir "Iniciar" por "Concluir" e ignorar as seções Codificar o lado do cliente e Codificar o lado do servidor de camada intermediária .
  2. Abra um prompt de comando na pasta Iniciar .

  3. Insira npm install no console para instalar todas as dependências discriminadas no arquivo package.json.

  4. Execute o comando npm run install-dev-certs. Selecione Sim à solicitação para instalar o certificado.

Use os valores a seguir para espaços reservados para as etapas de registro de aplicativo subsequentes.

Espaço reservado Valor
<add-in-name> Office-Add-in-NodeJS-SSO
<fully-qualified-domain-name> localhost:3000
Permissões do Microsoft Graph perfil, openid, Files.Read

Registrar o suplemento com plataforma de identidade da Microsoft

Você precisa criar um registro de aplicativo no Azure que represente seu servidor Web. Isso permite o suporte à autenticação para que tokens de acesso adequados possam ser emitidos para o código do cliente no JavaScript. Esse registro dá suporte ao SSO no cliente e à autenticação de fallback usando a MSAL (Biblioteca de Autenticação da Microsoft).

  1. Entre no portal do Azure com as credenciais de administrador para sua locação do Microsoft 365. Por exemplo, MyName@contoso.onmicrosoft.com.

  2. Selecione Registros de aplicativos. Se você não vir o ícone, pesquise por "registro de aplicativo" na barra de pesquisa.

    A página inicial portal do Azure.

    A página Registros de aplicativo é exibida.

  3. Selecione Novo registro.

    Novo registro no painel Registros de aplicativo.

    A página Registrar um aplicativo é exibida.

  4. Na página Registrar um aplicativo, defina os valores da seguinte forma.

    • Defina Nome para <add-in-name>.
    • Defina tipos de conta com suportecomo Contas em qualquer diretório organizacional (qualquer diretório Azure AD - multilocatário) e contas pessoais da Microsoft (por exemplo, Skype, Xbox).
    • Defina o URI de redirecionamento para usar o SPA (aplicativo de página única) da plataforma e o URI como https://<fully-qualified-domain-name>/dialog.html.

    Registre um painel de aplicativo com o nome e a conta com suporte concluída.

  5. Selecione Registrar. Uma mensagem é exibida informando que o registro do aplicativo foi criado.

    Mensagem informando que o registro do aplicativo foi criado.

  6. Copie e salve os valores da ID do Aplicativo (cliente) e da ID do Diretório (locatário). Use ambos os valores nos procedimentos posteriores.

    Painel de registro de aplicativo da Contoso que exibe a ID do cliente e a ID do diretório.

Adicionar um segredo do cliente

Às vezes chamado de senha de aplicativo, um segredo do cliente é um valor de cadeia de caracteres que seu aplicativo pode usar no lugar de um certificado para se identificar.

  1. No painel esquerdo, selecione Certificados & segredos. Em seguida, na guia Segredos do cliente , selecione Novo segredo do cliente.

    O painel Certificados & segredos.

    O painel Adicionar um segredo do cliente é exibido.

  2. Adicione uma descrição para o segredo do cliente.

  3. Selecione uma expiração para o segredo ou especifique um tempo de vida personalizado.

    • O tempo de vida do segredo do cliente é limitado a dois anos (24 meses) ou menos. Você não pode especificar uma vida útil personalizada com mais de 24 meses.
    • A Microsoft recomenda que você defina um valor de expiração inferior a 12 meses.

    Adicione um painel de segredo do cliente com a descrição e expira concluído.

  4. Selecione Adicionar. O novo segredo é criado e o valor é exibido temporariamente.

Importante

Registre o valor do segredo para uso no código do aplicativo cliente. Esse valor secreto nunca será exibido novamente depois que você sair deste painel.

Expor uma API Web

  1. No painel esquerdo, selecione Expor uma API.

    O painel Expor uma API é exibido.

    Um painel Expor uma API de um registro de aplicativo.

  2. Selecione Definir para gerar um URI de ID do aplicativo.

    Defina o botão no painel Expor uma API do registro do aplicativo.

    A seção para definir o URI de ID do aplicativo é exibida com um URI de ID de Aplicativo gerado no formulário api://<app-id>.

  3. Atualize o URI da ID do aplicativo para api://<fully-qualified-domain-name>/<app-id>.

    Edite o painel URI da ID do aplicativo com a porta localhost definida como 44355.

    • O URI da ID do aplicativo está preenchido previamente com a ID do aplicativo (GUID) no formato api://<app-id>.
    • O formato URI da ID do aplicativo deve ser: api://<fully-qualified-domain-name>/<app-id>
    • Insira o fully-qualified-domain-name entre api:// e <app-id> (que é um GUID). Por exemplo, api://contoso.com/<app-id>.
    • Se você estiver usando localhost, o formato deverá ser api://localhost:<port>/<app-id>. Por exemplo, api://localhost:3000/c6c1f32b-5e55-4997-881a-753cc1d563b7.

    Para obter detalhes adicionais do URI da ID do aplicativo, consulte Atributo identifierUris do manifesto do aplicativo.

    Observação

    Se você receber um erro dizendo que o domínio já pertence a alguém, mas você é o seu proprietário, siga o procedimento em Início Rápido: Adicionar um domínio personalizado ao Azure Active Directory para registrá-lo e, em seguida, repita esta etapa. (Esse erro também pode ocorrer se você não estiver conectado com credenciais de um administrador no locatário do Microsoft 365. Confira a etapa 2. Saia e entre novamente com credenciais de administrador e repita o processo da etapa 3.)

Adicionar um escopo

  1. Na página Expor uma API , selecione Adicionar um escopo.

    Selecione Adicionar um botão de escopo.

    O painel Adicionar um escopo é aberto.

  2. No painel Adicionar um escopo , especifique os atributos do escopo. A tabela a seguir mostra valores de exemplo para e o suplemento do Outlook que exige as profilepermissões , openid, Files.ReadWritee Mail.Read . Modifique o texto para corresponder às permissões que seu suplemento precisa.

    Campo Descrição Values
    Nome do Escopo O nome do escopo. Uma convenção de nomenclatura de escopo comum é resource.operation.constraint. Para SSO, isso deve ser definido como access_as_user.
    Quem pode consentir Determina se o consentimento do administrador é necessário ou se os usuários podem consentir sem uma aprovação de administrador. Para aprender SSO e exemplos, recomendamos que você defina isso como administradores e usuários.

    Selecione Administradores somente para permissões com privilégios mais altos.
    Administração nome de exibição de consentimento Uma breve descrição da finalidade do escopo visível apenas para administradores. Read/write permissions to user files. Read permissions to user mail and profiles.
    Administração descrição do consentimento Uma descrição mais detalhada da permissão concedida pelo escopo que somente os administradores veem. 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.
    Nome de exibição de consentimento do usuário Uma breve descrição da finalidade do escopo. Mostrado aos usuários somente se você definir Quem pode consentir com administradores e usuários. Read/write permissions to your files. Read permissions to your mail and profile.
    Descrição do consentimento do usuário Uma descrição mais detalhada da permissão concedida pelo escopo. Mostrado aos usuários somente se você definir Quem pode consentir com administradores e usuários. Allow Office to have read/write permissions to your files, and read permissions to your mail and profile.
  3. Defina o Estado como Habilitado e selecione Adicionar escopo.

    Defina o estado como habilitado e selecione o botão adicionar escopo.

    O novo escopo definido é exibido no painel.

    O novo escopo exibido no painel Expor uma API.

    Observação

    A parte de domínio do Nome de escopo exibidos logo abaixo do campo de texto deve corresponder automaticamente ao URI de ID do aplicativo definidos na etapa anterior com /access_as_user acrescentado ao final; por exemplo, api://localhost:6789/c6c1f32b-5e55-4997-881a-753cc1d563b7/access_as_user.

  4. Selecione Adicionar um aplicativo cliente.

    Selecione adicionar um aplicativo cliente.

    O painel Adicionar um aplicativo cliente é exibido.

  5. Na ID do cliente, insiraea5a67f6-b6f3-4338-b240-c655ddc3cc8e. Esse valor autoriza previamente todos os pontos de extremidade do aplicativo do Microsoft Office. Se você também quiser pré-autorizar o Office quando usado dentro do Microsoft Teams, adicione 1fec8e78-bce4-4aaf-ab1b-5451cc387264 (Microsoft Teams desktop e Teams mobile) e 5e3ce6c0-2b1f-4285-8d4b-75ee78787346 (Teams na Web).

    Observação

    A ea5a67f6-b6f3-4338-b240-c655ddc3cc8e ID pré-autoriza o Office em todas as plataformas a seguir. Como alternativa, você pode inserir um subconjunto adequado das seguintes IDs se, por qualquer motivo, desejar negar a autorização ao Office em algumas plataformas. Se você fizer isso, deixe de fora as IDs das plataformas das quais deseja reter a autorização. Os usuários do suplemento nessas plataformas não poderão chamar suas APIs Web, mas outras funcionalidades no suplemento ainda funcionarão.

    • d3590ed6-52b3-4102-aeff-aad2292ab01c (Microsoft Office)
    • 93d53678-613d-4013-afc1-62e9e444a0a5(Office na Web)
    • bc59ab01-8403-45c6-8796-ac3ef710b3e3(Outlook na Web)
  6. Em Escopos autorizados, selecione a caixa de seleção api://<fully-qualified-domain-name>/<app-id>/access_as_user .

  7. Selecione Adicionar aplicativo.

    O painel Adicionar um aplicativo cliente.

Adicionar permissões do Microsoft Graph

  1. No painel esquerdo, selecione permissões de API.

    O painel permissões de API.

    O painel de permissões de API é aberto.

  2. Selecione Adicionar uma permissão.

    Adicionando uma permissão no painel de permissões de API.

    O painel Solicitar permissões de API é aberto.

  3. Selecione Microsoft Graph.

    O painel Solicitar permissões de API com o botão Microsoft Graph.

  4. Selecione Permissões delegadas.

    O painel Solicitar permissões de API com o botão permissões delegadas.

  5. Na caixa de pesquisa Selecionar permissões, pesquise as permissões que seu suplemento precisa. Por exemplo, para um suplemento do Outlook, você pode usar profile, openid, Files.ReadWritee Mail.Read.

    Observação

    A permissão User.Read pode já estar listada por padrão. É uma boa prática solicitar apenas permissões necessárias, portanto, recomendamos que você desmarque a caixa para essa permissão se o suplemento realmente não precisar dela.

  6. Selecione a caixa de seleção para cada permissão conforme ela aparece. Observe que as permissões não permanecerão visíveis na lista enquanto você seleciona cada uma delas. Depois de selecionar as permissões que seu suplemento precisa, selecione Adicionar permissões.

    O painel Solicitar permissões de API com algumas permissões selecionadas.

  7. Selecione Conceder consentimento de administrador para [nome do locatário]. Selecione Sim para a confirmação exibida.

Configurar a versão do token de acesso

Você deve definir a versão do token de acesso aceitável para seu aplicativo. Essa configuração é feita no manifesto do aplicativo do Azure Active Directory.

Definir a versão do token de acesso

A versão do token de acesso poderá ser alterada se você escolher um tipo de conta diferente de Contas em qualquer diretório organizacional (Qualquer diretório Azure AD – Multilocatário) e contas pessoais da Microsoft (por exemplo, Skype, Xbox). Use as etapas a seguir para garantir que a versão do token de acesso esteja correta para o uso do SSO do Office.

  1. No painel esquerdo, selecione Manifesto.

    Selecione Manifesto do Azure.

    O manifesto do aplicativo do Azure Active Directory é exibido.

  2. Insira 2 como o valor da propriedade accessTokenAcceptedVersion.

    Valor para a versão do token de acesso aceito.

  3. Selecione Salvar.

    Uma mensagem é exibida no navegador informando que o manifesto foi atualizado com êxito.

    Mensagem atualizada de manifesto.

Parabéns! Você concluiu o registro do aplicativo para habilitar o SSO para seu suplemento do Office.

Configurar o suplemento

  1. Abra a pasta \Begin no projeto clonado no editor de códigos.

  2. Abra o .ENV arquivo e use os valores copiados anteriormente do registro do aplicativo Office-Add-in-NodeJS-SSO . Defina os valores da seguinte maneira:

    Nome Valor
    CLIENT_ID ID do aplicativo (cliente) da página de visão geral do registro do aplicativo.
    CLIENT_SECRET Segredo do cliente salvo da página Certificados & Segredos .

    Os valores não devem estar entre aspas. Quando terminar, o arquivo deverá ser semelhante ao seguinte:

    CLIENT_ID=8791c036-c035-45eb-8b0b-265f43cc4824
    CLIENT_SECRET=X7szTuPwKNts41:-/fa3p.p@l6zsyI/p
    NODE_ENV=development
    SERVER_SOURCE=<https://localhost:3000>
    
  3. Abra o arquivo de manifesto de suplemento "manifest\ manifest_local.xml" e role até a parte inferior do arquivo. Logo acima da </VersionOverrides> marca final, você encontrará a marcação a seguir.

    <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. Substitua o espaço reservado "$app-id-guid$" em ambos os lugares na marcação pela ID do aplicativo copiada quando você criou o registro do aplicativo Office-Add-in-NodeJS-SSO . Os símbolos "$" não fazem parte da ID, portanto, não os inclua. Essa é a mesma ID que você usou para o CLIENT_ID no . Arquivo ENV.

    Observação

    O <valor do recurso> é o URI da ID do Aplicativo que você define quando registrou o suplemento. A <seção Escopos> é usada apenas para gerar uma caixa de diálogo de consentimento se o suplemento for vendido por meio do AppSource.

  5. Abra o arquivo \public\javascripts\fallback-msal\authConfig.js. Substitua o espaço reservado "$app-id-guid$" pela ID do aplicativo que você salvou do registro de aplicativo Office-Add-in-NodeJS-SSO que você criou anteriormente.

  6. Salve as alterações no arquivo.

Codificar o lado do cliente

Chame nossa API REST do servidor Web

  1. No editor de códigos, abra o arquivo public\javascripts\ssoAuthES6.js. Ele já tem um código que garante que o Promises tenha suporte, mesmo no controle webview trident (Internet Explorer 11) e uma Office.onReady chamada para atribuir um manipulador ao único botão do suplemento.

    Observação

    Como o nome sugere, o ssoAuthES6.js usa a sintaxe JavaScript ES6, pois usar async e await mostra melhor a simplicidade fundamental da API de SSO. Quando o servidor localhost é iniciado, esse arquivo é transpilado para a sintaxe ES5 para que o exemplo dê suporte a Trident.

  2. Na função getFileNameList, substitua TODO 1 pelo seguinte código. Sobre este código, observe:

    • A função getFileNameList é chamada quando o usuário escolhe o botão Obter Nomes de Arquivo do OneDrive no painel de tarefas.
    • Ele chama a callWebServerAPI função que especifica qual API REST chamar. Isso retorna json contendo uma lista de nomes de arquivo do OneDrive do usuário.
    • O JSON é passado para a writeFileNamesToOfficeDocument função para listar os nomes de arquivo no 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. Na função callWebServerAPI, substitua TODO 2 pelo seguinte código. Sobre este código, observe:

    • A função chama getAccessToken que é nossa própria função que encapsula usando o SSO do Office ou o fallback MSAL conforme necessário para obter o token. Se ele retornar um token nulo, uma mensagem será mostrada para uma condição de erro de auth que não pode ser resolvida, portanto, a função também retornará nulo.
    • A função usa a fetch API para chamar o servidor Web e, se bem-sucedida, retorna o corpo 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. Na função callWebServerAPI, substitua TODO 3 pelo seguinte código. Sobre este código, observe:

    • Esse código manipula o cenário em que o token SSO expirou. Nesse caso, precisamos chamar Office.auth.getAccessToken para obter um token atualizado. A maneira mais simples é fazer uma chamada recursiva que resulta em uma nova chamada para Office.auth.getAccessToken. O retryRequest parâmetro garante que a chamada recursiva só seja tentada uma vez.
    • A TokenExpiredError cadeia de caracteres é definida pelo nosso servidor Web sempre que detecta um 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. Na função callWebServerAPI, substitua TODO 4 pelo seguinte código. Sobre este código, observe:

    • A Microsoft Graph cadeia de caracteres é definida pelo nosso servidor Web sempre que uma chamada do Microsoft Graph falha.
    // 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. Na função callWebServerAPI, substitua TODO 5 pelo seguinte código.

    // Handle other errors.
    throw new Error(
        'Unknown error from web server: ' + JSON.stringify(jsonBody)
    );
    
  7. Na função getAccessToken, substitua TODO 6 pelo seguinte código. Sobre este código, observe:

    • authSSO rastreia se estivermos usando o SSO ou usando o fallback do MSAL. Se o SSO for usado, a função chamará Office.auth.getAccessToken e retornará o token.
    • Os erros são tratados pela handleSSOErrors função que retornará um token se ele mudar para autenticação MSAL de fallback.
    • A autenticação fallback usa a biblioteca MSAL para entrar no usuário. O suplemento em si é um SPA e usa um registro de aplicativo SPA para acessar o 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. Na função handleSSOErrors, substitua TODO 7 pelo seguinte código. Para saber mais sobre esses erros, confira Solucionar problemas de SSO em suplementos do Office em.

    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. Substitua TODO 8 pelo código a seguir. Para quaisquer erros que não possam ser tratados, o código muda para autenticação de fallback usando 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.
    

Codificar a API REST do servidor Web

O servidor Web fornece APIs REST para o cliente chamar. Por exemplo, a API /getuserfilenames REST obtém uma lista de nomes de arquivo da pasta OneDrive do usuário. Cada chamada de API REST requer um token de acesso do cliente para garantir que o cliente correto esteja acessando seus dados. O token de acesso é trocado por um token do Microsoft Graph por meio do OBO (fluxo em nome de nome). O novo token do Microsoft Graph é armazenado em cache pela biblioteca MSAL para chamadas de API subsequentes. Ele nunca é enviado para fora do servidor Web. Para obter mais informações, confira Solicitação de token de acesso de camada intermediária

Criar a rota e implementar o fluxo On-Behalf-Of

  1. Abra o arquivo routes\getFilesRoute.js e substitua TODO 9 pelo código a seguir. Sobre este código, observe:

    • Ele chama authHelper.validateJwt. Isso garante que o token de acesso seja válido e não tenha sido adulterado.
    • Para obter mais informações, confira Validando 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. Substitua TODO 10 pelo código a seguir. Sobre este código, observe:

    • Ele só solicita os escopos mínimos necessários, como files.read.
    • Ele usa o MSAL authHelper para executar o fluxo OBO na chamada para 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. Substitua TODO 11 pelo código a seguir. Sobre este código, observe:

    • Ele constrói a URL para a chamada microsoft API do Graph e, em seguida, faz a chamada por meio da getGraphData função.
    • Ele retorna erros enviando uma resposta HTTP 500 junto com detalhes.
    • Com êxito, ele retorna o JSON com a lista de nome de arquivo para o 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. Substitua TODO 12 pelo código a seguir. Esse código verifica especificamente se o token expirou porque o cliente pode solicitar um novo token e chamar novamente.

    } 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 });
       }
    }
    

O exemplo deve lidar com a autenticação de fallback por meio da autenticação MSAL e SSO por meio do Office. O exemplo tentará primeiro o SSO e o authSSO booliano na parte superior do arquivo rastreará se o exemplo estiver usando SSO ou tiver mudado para auth fallback.

Executar o projeto

  1. Certifique-se de ter alguns arquivos no seu OneDrive para que você possa verificar os resultados.

  2. Abra um aviso de comando na raiz da pasta \Begin.

  3. Execute o comando npm install para instalar todas as dependências do pacote.

  4. Execute o comando npm start para iniciar o servidor de camada intermediária.

  5. Você deve fazer o sideload do suplemento em um aplicativo do Office (Excel, Word ou PowerPoint) para testá-lo. As instruções dependem da plataforma. Há links para instruções no Fazer sideload de suplemento para teste.

  6. No aplicativo do Office, na faixa de opções Home, selecione o botão Mostrar suplemento no grupoSSO Node.js para abrir o suplemento do painel de tarefas.

  7. Clique no botão Definir Nome de Arquivos do One Drive. Se você estiver conectado ao Office com uma conta de trabalho ou Microsoft 365 Education ou ou uma conta microsoft, e o SSO estiver funcionando conforme o esperado, os primeiros 10 nomes de arquivo e pasta em seu OneDrive for Business serão inseridos no documento. (Pode levar até 15 segundos na primeira vez.) Se você não estiver conectado ou estiver em um cenário que não dê suporte ao SSO ou o SSO não estiver funcionando por nenhum motivo, você será solicitado a entrar. Depois de entrar, os nomes do arquivo e da pasta aparecem.

Observação

Se você entrou no Office com uma ID diferente e se alguns aplicativos do Office que estavam abertos no momento continuam abertos, o Office pode não alterar de forma confiável sua ID, mesmo que pareça ter feito isso. Se isso acontecer, a chamada para o Microsoft Graph pode falhar ou os dados da ID anterior podem ser retornados. Para evitar isso, certifique-se de fechar todos os outros aplicativos do Office antes de pressionar Obter nomes de arquivos do OneDrive.

Notas de segurança

  • A /getuserfilenames rota em getFilesroute.js usa uma cadeia de caracteres literal para compor a chamada para o Microsoft Graph. Se você alterar a chamada para que qualquer parte da cadeia de caracteres venha da entrada do usuário, higienize a entrada para que ela não possa ser usada em um ataque de injeção de cabeçalho de resposta.

  • Na app.js política de segurança de conteúdo a seguir está em vigor para scripts. Talvez você queira especificar restrições adicionais dependendo de suas necessidades de segurança de suplemento.

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

Siga sempre as práticas recomendadas de segurança na documentação plataforma de identidade da Microsoft.