你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

教程:从应用服务通过后端 API 到 Microsoft Graph 的身份验证流程

了解如何创建和配置后端应用服务以接受前端应用的用户凭据,然后将该凭据交换到下游 Azure 服务。 这样,用户便可以登录到前端应用服务,将其凭据传递给后端应用服务,然后使用同一标识访问 Azure 服务。

本教程中,您将学习如何:

  • 配置后端身份验证应用以提供适用于下游 Azure 服务的令牌
  • 使用 JavaScript 代码将已登录用户的访问令牌交换为下游服务的新令牌。
  • 使用 JavaScript 代码访问下游服务。

先决条件

请完整完成上一个教程 作为用户从受保护的 JavaScript 应用访问Microsoft Graph,然后再开始本教程,但不要在本教程结束时删除资源。 本教程假定你有两个应用服务及其相应的身份验证应用。

上一教程使用 Azure Cloud Shell 作为 Azure CLI 的 shell。 本教程将继续使用该用法。

建筑

本教程演示如何将前端应用提供的用户凭据传递到后端应用,然后传递到 Azure 服务。 在本教程中,下游服务是 Microsoft Graph。 用户的凭据用于从 Microsoft Graph 获取其个人资料。

应用服务代表已登录用户连接到 Microsoft Graph 的体系结构图。

用户在此体系结构中获取 Microsoft Graph 信息的身份验证流

上一篇教程 已介绍:

  1. 将用户登录到配置为使用 Active Directory 作为标识提供者的前端应用服务。
  2. 前端应用服务将用户的令牌传递给后端应用服务。
  3. 后端应用受到保护,允许前端发出 API 请求。 用户的访问令牌具有后端 API 的受众和范围 user_impersonation
  4. 后端应用注册已具有 Microsoft Graph,作用域为 User.Read。 默认情况下,这项会自动添加到所有应用注册中。
  5. 在上一教程结束时,由于 Graph 未连接,虚假的配置文件被返回到了前端应用。

本教程扩展了体系结构:

  1. 授予管理员同意以绕过后端应用的用户同意屏幕。
  2. 更改应用程序代码,将从前端应用发送的访问令牌转换为具有 Microsoft Graph 所需权限的访问令牌。
  3. 提供代码,让后端应用交换令牌,获取具有下游 Azure 服务(例如 Microsoft Graph)范围的新令牌。
  4. 提供代码,让后端应用 使用新令牌 作为当前身份验证用户访问下游服务。
  5. 使用 az webapp up 重新部署后端应用。
  6. 在本教程结束时,由于已连接 Graph,真实配置文件会返回到前端应用。

本指南不包括:

  • 更改上一教程中的前端应用。
  • 更改后端身份验证应用的范围权限,因为 User.Read 默认情况下会添加到所有身份验证应用。

在上一教程中,当用户登录到前端应用时,会显示一个弹出窗口,要求用户同意。

在本教程中,若要从 Microsoft Graph 读取用户配置文件,后端应用需要将已登录用户的访问令牌交换为具有 Microsoft Graph 所需权限的新 访问令牌 。 由于用户未直接连接到后端应用,因此他们无法以交互方式访问许可屏幕。 为了解决此问题,您必须在 Microsoft Entra ID 中配置后端应用的应用注册,以便授予管理员同意。 这是通常由 Active Directory 管理员完成的设置更改。

  1. 打开 Azure 门户,搜索后端应用服务的研究。

  2. 找到 “设置 -> 身份验证” 部分。

  3. 选择标识提供者以转到身份验证应用。

  4. 在身份验证应用中,选择“ 管理 -> API 权限”。

  5. 默认目录选择“授予管理员许可”。

    突出显示了“管理员同意”按钮的 Azure 门户身份验证应用的屏幕截图。

  6. 在弹出窗口中,选择“ ”以确认同意。

  7. 验证“状态”列是否为“为默认目录授予”。 使用此设置,不再需要后端应用向已登录用户显示同意屏幕,并且可以直接请求访问令牌。 已登录用户有权访问 User.Read 范围设置,因为这是创建应用注册的默认范围。

    Azure 门户身份验证应用的屏幕截图,其中“状态”列显示管理员同意已授予。

2. 安装 npm 包

在上一教程中,后端应用不需要任何 npm 包进行身份验证,因为唯一的身份验证是通过在 Azure 门户中配置标识提供者提供的。 在本教程中,必须将已登录用户的后端 API 访问令牌交换为包含 Microsoft Graph 范围的访问令牌。 此交换通过两个库完成,因为该交换不再使用应用服务身份验证,而是直接使用 Microsoft Entra ID 和 MSAL.js。

  1. 打开 Azure Cloud Shell,并切换到示例目录中的后端应用程序:

    cd js-e2e-web-app-easy-auth-app-to-app/backend
    
  2. 安装 Azure MSAL npm 包:

    npm install @azure/msal-node
    
  3. 安装 Microsoft Graph npm 包:

    npm install @microsoft/microsoft-graph-client
    

3.添加代码以交换当前令牌以获取 Microsoft Graph 令牌

提供完成此步骤的源代码。 使用以下步骤将其纳入。

  1. 打开 ./src/server.js 文件。

  2. 在文件顶部取消注释以下依赖项:

    import { getGraphProfile } from './with-graph/graph';
    
  3. 在同一文件中,取消注释 graphProfile 变量:

    let graphProfile={};
    
  4. 在同一文件中,取消注释 get-profile 路由中的以下 getGraphProfile 行,以从 Microsoft Graph 获取配置文件:

    // where did the profile come from
    profileFromGraph=true;
    
    // get the profile from Microsoft Graph
    graphProfile = await getGraphProfile(accessToken);
    
    // log the profile for debugging
    console.log(`profile: ${JSON.stringify(graphProfile)}`);
    
  5. 保存更改: Ctrl + s

  6. 重新部署后端应用:

    az webapp up --resource-group myAuthResourceGroup --name <back-end-app-name> 
    
    

4. 检查后端代码以将后端 API 令牌交换为 Microsoft Graph 令牌

若要更改 Microsoft Graph 令牌的后端 API 受众令牌,后端应用需要查找租户 ID,并将其用作 MSAL.js 配置对象的一部分。 由于后端应用程序配置为由Microsoft提供身份验证,因此租户ID和其他几个必要值已在应用服务的应用设置中。

示例应用中已提供以下代码。 你需要了解它的原因及其工作原理,以便你可以将此工作应用到需要相同功能的其他应用。

检查用于获取租户 ID 的代码

  1. 打开 ./backend/src/with-graph/auth.js 文件。

  2. 查看 getTenantId() 函数。

    export function getTenantId() {
    
        const openIdIssuer = process.env.WEBSITE_AUTH_OPENID_ISSUER;
        const backendAppTenantId = openIdIssuer.replace(/https:\/\/sts\.windows\.net\/(.{1,36})\/v2\.0/gm, '$1');
    
        return backendAppTenantId;
    }
    
  3. 此函数从 WEBSITE_AUTH_OPENID_ISSUER 环境变量中获取当前租户 ID。 ID 通过正则表达式从变量中分析出来。

检查代码以使用 MSAL.js 获取 Graph 令牌

  1. 还是在 ./backend/src/with-graph/auth.js 文件中,查看 getGraphToken() 函数。

  2. 生成 MSAL.js 配置对象,使用 MSAL 配置创建 clientCredentialAuthority。 配置代理关闭请求。 然后使用 acquireTokenOnBehalfOf 将后端 API 访问令牌交换为 Graph 访问令牌。

    // ./backend/src/auth.js
    // Exchange current bearerToken for Graph API token
    // Env vars were set by App Service
    export async function getGraphToken(backEndAccessToken) {
    
        const config = {
            // MSAL configuration
            auth: {
                // the backend's authentication CLIENT ID 
                clientId: process.env.WEBSITE_AUTH_CLIENT_ID,
                // the backend's authentication CLIENT SECRET 
                clientSecret: process.env.MICROSOFT_PROVIDER_AUTHENTICATION_SECRET,
                // OAuth 2.0 authorization endpoint (v2)
                // should be: https://login.microsoftonline.com/BACKEND-TENANT-ID
                authority: `https://login.microsoftonline.com/${getTenantId()}`
            },
            // used for debugging
            system: {
                loggerOptions: {
                    loggerCallback(loglevel, message, containsPii) {
                        console.log(message);
                    },
                    piiLoggingEnabled: true,
                    logLevel: MSAL.LogLevel.Verbose,
                }
            }
        };
    
        const clientCredentialAuthority = new MSAL.ConfidentialClientApplication(config);
    
        const oboRequest = {
            oboAssertion: backEndAccessToken,
            // this scope must already exist on the backend authentication app registration 
            // and visible in resources.azure.com backend app auth config
            scopes: ["https://graph.microsoft.com/.default"]
        }
    
        // This example has App service validate token in runtime
        // from headers that can't be set externally
    
        // If you aren't using App service's authentication, 
        // you must validate your access token yourself
        // before calling this code
        try {
            const { accessToken } = await clientCredentialAuthority.acquireTokenOnBehalfOf(oboRequest);
            return accessToken;
        } catch (error) {
            console.log(`getGraphToken:error.type = ${error.type}  ${error.message}`);
        }
    }
    

5.检查后端代码以使用新令牌访问 Microsoft Graph

若要以登录到前端应用程序的用户身份访问 Microsoft Graph,更改包括:

  • 具有对下游服务 Microsoft Graph 的 API 权限的 Active Directory 应用注册的配置,其必要范围为 User.Read
  • 授予管理员同意以绕过后端应用的用户同意屏幕。
  • 更改应用程序代码,将从前端应用发送的访问令牌转换为具有下游服务所需权限的访问令牌,Microsoft Graph。

现在代码有了Microsoft Graph的正确令牌,使用它创建一个连接到Microsoft Graph的客户端,然后获取用户的个人资料。

  1. 打开 ./backend/src/graph.js

  2. getGraphProfile() 函数中,获取令牌,然后从令牌获取经过身份验证的客户端,然后获取配置文件。

    // 
    import graph from "@microsoft/microsoft-graph-client";
    import { getGraphToken } from "./auth.js";
    
    // Create client from token with Graph API scope
    export function getAuthenticatedClient(accessToken) {
        const client = graph.Client.init({
            authProvider: (done) => {
                done(null, accessToken);
            }
        });
    
        return client;
    }
    export async function getGraphProfile(accessToken) {
        // exchange current backend token for token with 
        // graph api scope
        const graphToken = await getGraphToken(accessToken);
    
        // use graph token to get Graph client
        const graphClient = getAuthenticatedClient(graphToken);
    
        // get profile of user
        const profile = await graphClient
            .api('/me')
            .get();
    
        return profile;
    }
    

6.测试更改

  1. 在浏览器中使用前端网站。 如果令牌已过期,可能需要刷新令牌。

  2. 选择 Get user's profile。 这会将持有者令牌中的身份验证传递到后端。

  3. 后端使用帐户的真实 Microsoft Graph 配置文件进行响应。

    Web 浏览器的屏幕截图,显示了前端应用程序在成功从后端应用获取真实用户档案后。

7. 清理

在前面的步骤中,你在资源组中创建了 Azure 资源。

  1. 通过在 Cloud Shell 中运行以下命令来删除资源组。 此命令可能需要花费一点时间运行。

    az group delete --name myAuthResourceGroup
    
  2. 使用身份验证应用的客户端 ID,你之前在后端和前端应用的 部分中找到并记下了此 ID。Enable authentication and authorization

  3. 删除前端和后端应用的应用注册。

    # delete app - do this for both frontend and backend client ids
    az ad app delete <client-id>
    

常见问题

我收到错误 80049217,这意味着什么?

此错误 CompactToken parsing failed with error code: 80049217表示后端应用服务无权返回 Microsoft Graph 令牌。 之所以出现此错误,是因为应用注册缺少 User.Read 权限。

我收到错误 AADSTS65001,这意味着什么?

此错误 AADSTS65001: The user or administrator has not consented to use the application with ID \<backend-authentication-id>. Send an interactive authorization request for this user and resource表示尚未为管理员同意配置后端身份验证应用。 由于错误显示在后端应用的日志中,前端应用程序无法告诉用户为什么在前端应用中看不到其配置文件。

如何以用户身份连接到其他下游 Azure 服务?

本教程演示了向 Microsoft Graph 进行身份验证的 API 应用,但是,可以应用相同的常规步骤来代表用户访问任何 Azure 服务。

  1. 对前端应用程序没有更改。 仅更改后端的身份验证应用注册和后端应用源代码。
  2. 将限定为后端 API 的用户令牌交换为要访问的下游服务的令牌。
  3. 在下游服务的 SDK 中使用令牌创建客户端。
  4. 使用下游客户端访问服务功能。

后续步骤