在 Node.js 守护程序应用程序中调用 API

本指南使用示例 Node.js 守护程序应用程序来演示守护程序应用如何获取用于调用 Web API 的访问令牌。

守护程序应用程序可以代表自身(而不是用户)获取一个令牌。 用户无法与守护程序应用程序交互,因为它需要自己的标识。 此类型的应用程序可通过以下方式来请求访问令牌:使用其应用程序标识并向外部 ID 提供其应用程序 ID、凭据(密码或证书)以及应用程序 ID URI。

守护程序应用使用标准 OAuth 2.0 客户端凭据授予。 为了简化获取令牌的过程,本文中使用的示例使用适用于 Node (MSAL Node) 的 Microsoft 身份验证库

先决条件

注册守护程序应用程序和 Web API

在此步骤中,你将创建守护程序和 Web API 应用程序注册,并指定 Web API 的范围。

注册 Web API 应用程序

  1. 至少以应用程序开发人员的身份登录到 Microsoft Entra 管理中心

  2. 如果你有权访问多个租户,请使用顶部菜单中的“设置”图标 ,通过“目录 + 订阅”菜单切换到你的外部租户

  3. 浏览到“标识”>“应用程序”>“应用注册”。

  4. 选择“+ 新建注册”。

  5. 在出现的“注册应用程序”页面中,输入应用程序的注册信息:

    1. 在“名称”部分中,输入将向应用用户显示的有意义的应用程序名称,例如“ciam-ToDoList-api”。

    2. 在“支持的帐户类型”下,选择“仅此组织目录中的帐户” 。

  6. 选择“注册”以创建应用程序。

  7. 注册完成后,将显示应用程序的“概述”窗格。 记录要在应用程序源代码中使用的目录(租户)ID 和应用程序(客户端)ID。

配置应用角色

API 需要至少为应用程序发布一个应用角色(也称为应用程序权限),以便客户端应用以自己的身份获取访问令牌。 应用程序权限是 API 想要使客户端应用程序能够成功地以自己的身份进行身份验证(无需让用户登录)时应发布的权限类型。 若要发布应用程序权限,请执行下列步骤:

  1. 从“应用注册”页中,选择创建的应用程序(例如 ciam-ToDoList-api)以打开其“概述”页。

  2. 在“管理”下,选择“应用角色”。

  3. 选择“创建应用角色”,输入以下值,然后选择“应用”以保存更改:

    属性
    显示名称 ToDoList.Read.All
    允许的成员类型 应用程序
    ToDoList.Read.All
    说明 允许应用使用“TodoListApi”读写每个用户的待办事项列表
  4. 再次选择“创建应用角色”,为第二个应用角色输入以下值,然后选择“应用”以保存更改:

    属性
    显示名称 ToDoList.ReadWrite.All
    允许的成员类型 应用程序
    ToDoList.ReadWrite.All
    说明 允许应用使用“ToDoListApi”读写每个用户的 ToDo 列表

配置可选声明

可以包含 idtyp 可选声明,以帮助 Web API 确定令牌是应用令牌还是应用 + 用户令牌。 尽管可以将 scp 和 roles 声明的组合用于同一目的,但使用 idtyp 声明仍是区分应用令牌和应用 + 用户令牌的最简单方法。 例如,当令牌为仅限应用的令牌时,此声明的值为 app

注册守护程序应用

若要使应用程序能够让用户通过 Microsoft Entra 登录,必须让 Microsoft Entra 外部 ID 能够感知你创建的应用程序。 应用注册会在应用与 Microsoft Entra 之间建立信任关系。 注册应用程序时,外部 ID 会生成一个称为“应用程序(客户端)ID”的唯一标识符,该值用于在创建身份验证请求时标识应用。

以下步骤演示如何在 Microsoft Entra 管理中心注册应用:

  1. 至少以应用程序开发人员的身份登录到 Microsoft Entra 管理中心

  2. 如果你有权访问多个租户,请使用顶部菜单中的“设置”图标 ,通过“目录 + 订阅”菜单切换到你的外部租户

  3. 浏览到“标识”>“应用程序”>“应用注册”。

  4. 选择“+ 新建注册”。

  5. 在显示的“注册应用程序”页中;

    1. 输入一个向应用用户显示的、有意义的应用程序名称,例如 ciam-client-app
    2. 在“支持的帐户类型”下,选择“仅此组织目录中的帐户” 。
  6. 选择“注册”。

  7. 成功注册后,会显示应用程序的“概述”窗格。 记录要在应用程序源代码中使用的应用程序(客户端)ID

创建客户端机密

为注册的应用创建客户端机密。 应用程序在请求令牌时使用客户端密码来证明其身份。

  1. 从“应用注册”页中,选择创建的应用程序(例如 ciam-client-app)以打开其“概述”页。
  2. 在“管理”下,选择“证书和机密”
  3. 选择“新建客户端机密”。
  4. 在“说明”框中输入对客户端密码的说明(如 ciam 应用客户端密码)。
  5. 在“过期时间”下,选择密码的有效期(根据组织的安全规则),然后选择“添加”。
  6. 记下机密的“值”。 在稍后的步骤中将使用此值进行配置。 离开“证书和机密”后,机密值不会再次显示,并且无法以任何方式检索。 请确保记录它。

向守护程序应用授予 API 权限

  1. 从“应用注册”页中,选择创建的应用程序(例如 ciam-client-app)。

  2. 在“管理”下选择“API 权限” 。

  3. 在“已配置权限”下,选择“添加权限”。

  4. 选择“我的组织使用的 API”选项卡。

  5. 在 API 列表中,选择 API(例如 ciam-ToDoList-api)。

  6. 选择“应用程序权限”选项。 我们选择此选项是因为应用以自身身份登录,而不是以用户身份登录。

  7. 从权限列表中,选择“TodoList.Read.All”、“ToDoList.ReadWrite.All”(必要时使用搜索框)。

  8. 选择“添加权限”按钮。

  9. 此时,你已正确分配了权限。 但是,由于守护程序应用不允许用户与之交互,因此用户本身无法同意这些权限。 若要解决此问题,作为管理员的你必须代表租户中的所有用户同意这些权限:

    1. 选择“为 <租户名称> 授予管理员同意”,然后选择“是”。
    2. 选择“刷新”,然后验证两个权限的“状态”下是否均显示“已为 <租户名称> 授予”。

克隆或下载示例守护程序应用程序和 Web API

若要获取示例应用程序,可以从 GitHub 克隆它或将其下载为 .zip 文件。

  • 若要克隆示例,请打开命令提示符并导航到要创建项目的位置,然后输入以下命令:

    git clone https://github.com/Azure-Samples/ms-identity-ciam-javascript-tutorial.git
    
  • 或者,下载示例 .zip 文件,然后将其解压缩到名称长度少于 260 个字符的文件路径。

安装项目依赖项

  1. 打开控制台窗口,切换到包含 Node.js 示例应用的目录:

    cd 2-Authorization\3-call-api-node-daemon\App
    
  2. 运行以下命令以安装应用依赖项:

    npm install && npm update
    

配置示例守护程序应用和 API

若要在客户端 Web 应用示例中使用应用注册,请执行以下操作:

  1. 在代码编辑器中打开 App\authConfig.js 文件。

  2. 查找占位符:

    • 查找 Enter_the_Application_Id_Here 并将其替换为之前注册的守护程序应用的应用程序(客户端)ID。

    • 查找 Enter_the_Tenant_Subdomain_Here 并将其替换为目录(租户)子域。 例如,如果租户主域为 contoso.onmicrosoft.com,请使用 contoso。 如果没有租户名称,请了解如何读取租户详细信息

    • 查找 Enter_the_Client_Secret_Here 并将其替换为之前复制的守护程序应用机密值。

    • 查找 Enter_the_Web_Api_Application_Id_Here 并将其替换为之前复制的 Web API 的应用程序(客户端)ID。

若要在 Web API 示例中使用应用注册,请执行以下操作:

  1. 在代码编辑器中打开 API\ToDoListAPI\appsettings.json 文件。

  2. 查找占位符:

    • 查找 Enter_the_Application_Id_Here 并将其替换为复制的 Web API 的应用程序(客户端)ID。

    • 查找 Enter_the_Tenant_Id_Here 并将其替换为之前复制的目录(租户)ID。

    • 查找 Enter_the_Tenant_Subdomain_Here 并将其替换为目录(租户)子域。 例如,如果租户主域为 contoso.onmicrosoft.com,请使用 contoso。 如果没有租户名称,请了解如何读取租户详细信息

运行并测试示例守护程序应用和 API

  1. 打开控制台窗口,然后使用以下命令运行 Web API:

    cd 2-Authorization\3-call-api-node-daemon\API\ToDoListAPI
    dotnet run
    
  2. 使用以下命令运行 Web 应用客户端:

    2-Authorization\3-call-api-node-daemon\App
    node . --op getToDos
    
  • 如果守护程序应用和 Web API 成功运行,则应在控制台窗口中看到类似于以下 JSON 数组的内容

    {
        "id": 1,
        "owner": "3e8....-db63-43a2-a767-5d7db...",
        "description": "Pick up grocery"
    },
    {
        "id": 2,
        "owner": "c3cc....-c4ec-4531-a197-cb919ed.....",
        "description": "Finish invoice report"
    },
    {
        "id": 3,
        "owner": "a35e....-3b8a-4632-8c4f-ffb840d.....",
        "description": "Water plants"
    }
    

工作原理

Node.js 应用使用 OAuth 2.0 客户端凭据授予来为自己获取访问令牌,而不是为用户获取访问令牌。 应用请求的访问令牌包含表示为角色的权限。 对于应用程序令牌,客户端凭据流使用此权限集来代替用户范围。 你之前在 Web API 中公开了这些应用程序权限,然后将它们授予守护程序应用

在 API 端,Web API 必须验证访问令牌是否具有所需的权限(应用程序权限)。 Web API 无法接受没有所需权限的访问令牌。

对数据的访问

Web API 终结点应准备好接受来自用户和应用程序的调用。 因此,它应有一种方法来相应地响应每个请求。 例如,通过委托的权限/范围从用户发出的调用会收到用户的数据待办事项列表。 另一方面,通过应用程序权限/角色从应用程序发出的调用则可能会收到整个待办事项列表。 但在本文中,我们只进行应用程序调用,因此不需要配置委托的权限/范围。