你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
教程:在 Azure 应用服务中对用户进行端到端身份验证和授权
Azure 应用服务提供高度可缩放、自修复的 Web 托管服务。 另外,应用服务提供对用户身份验证和授权的内置支持。 本教程介绍如何通过应用服务身份验证和授权来确保应用的安全性。 它以带视图前端的 Express.js 为例。 应用服务身份验证和授权支持所有的语言运行时,你可以按照本教程的说明来了解如何将其应用到首选语言。
Azure 应用服务使用 Linux 操作系统,提供高度可缩放的自修补 Web 托管服务。 另外,应用服务提供对用户身份验证和授权的内置支持。 本教程介绍如何通过应用服务身份验证和授权来确保应用的安全性。 它使用带视图的 Express.js。 应用服务身份验证和授权支持所有的语言运行时,你可以按照本教程的说明来了解如何将其应用到首选语言。
在本教程中,你将了解:
- 启用内置身份验证和授权
- 确保应用能够防范未经身份验证的请求
- 使用 Microsoft Entra ID 作为标识提供者
- 代表登录的用户访问远程应用
- 使用令牌身份验证确保服务间调用的安全性
- 使用服务器代码中的访问令牌
提示
完成此方案后,请继续执行下一过程,了解如何以经过身份验证的用户身份连接到 Azure 服务。 常见方案包括作为拥有特定能力或有权访问特定表或文件的用户访问 Azure 存储或数据库。
此过程中的身份验证由 Azure 应用服务在托管平台层提供。 必须部署前端和后端应用,并针对此 Web 应用配置身份验证才能成功使用。
前端应用配置为安全地使用后端 API。 前端应用程序为用户提供 Microsoft 登录,然后允许用户从后端获取其虚构配置文件。 本教程使用虚构配置文件来简化完成方案的步骤。
在前端执行源代码之前,应用服务从应用服务 x-ms-token-aad-access-token
标头注入经过验证的 accessToken
。 然后,前端源代码将访问 accessToken 并将其作为 bearerToken
发送到后端服务器,从而安全地访问后端 API。 后端服务器在将 bearerToken 传递到后端源代码之前会对其进行验证。 后端源代码收到 bearerToken 后,可以使用它。
在本系列的下一篇文章中,将 bearerToken 交换为具有 Microsoft Graph API 访问范围的令牌。 Microsoft Graph API 返回用户的配置文件信息。
如果没有 Azure 订阅,请在开始之前创建一个 Azure 免费帐户。
在 Azure Cloud Shell 中,运行下列命令以克隆示例存储库。
git clone https://github.com/Azure-Samples/js-e2e-web-app-easy-auth-app-to-app
创建资源组、Web 应用计划、Web 应用,并在一个步骤中部署。
更改到前端 Web 应用目录。
cd js-e2e-web-app-easy-auth-app-to-app/frontend
使用 az webapp up 创建和部署前端 Web 应用。 由于 Web 应用名称必须全局唯一,因此请将 <front-end-app-name>
替换为唯一名称。
az webapp up --resource-group myAuthResourceGroup --name <front-end-app-name> --plan myPlan --sku FREE --os-type Windows --location "West Europe" --runtime "NODE:16LTS"
更改到后端 Web 应用目录。
cd ../backend
将后端 Web 应用部署到同一资源组和应用计划。 由于 Web 应用名称必须全局唯一,因此请将 <back-end-app-name>
替换为首字母或数字的唯一集合。
az webapp up --resource-group myAuthResourceGroup --name <back-end-app-name> --plan myPlan --os-type Windows --location "West Europe" --runtime "NODE:16LTS"
更改到前端 Web 应用目录。
cd frontend
使用 az webapp up 创建和部署前端 Web 应用。 由于 Web 应用名称必须全局唯一,因此请将 <front-end-app-name>
替换为首字母或数字的唯一集合。
az webapp up --resource-group myAuthResourceGroup --name <front-end-app-name> --plan myPlan --sku FREE --location "West Europe" --os-type Linux --runtime "NODE:16-lts"
更改到后端 Web 应用目录。
cd ../backend
将后端 Web 应用部署到同一资源组和应用计划。 由于 Web 应用名称必须全局唯一,因此请将 <back-end-app-name>
替换为首字母或数字的唯一集合。
az webapp up --resource-group myAuthResourceGroup --name <back-end-app-name> --plan myPlan --sku FREE --location "West Europe" --runtime "NODE:16-lts"
前端应用程序需要知道 API 请求的后端应用程序的 URL。 使用以下 Azure CLI 命令配置应用设置。 URL 的格式应为 https://<back-end-app-name>.azurewebsites.net
。
az webapp config appsettings set --resource-group myAuthResourceGroup --name <front-end-app-name> --settings BACKEND_URL="https://<back-end-app-name>.azurewebsites.net"
浏览到前端应用,并从后端返回虚构配置文件。 此操作验证前端是否从后端成功请求配置文件,以及后端是否成功返回配置文件。
在浏览器中打开前端 Web 应用 (https://<front-end-app-name>.azurewebsites.net
)。
选择 Get user's profile
链接。
查看从后端 Web 应用返回的虚构配置文件。
withAuthentication
值为 false 表示尚未设置身份验证。
在此步骤中,请为两个 Web 应用启用身份验证和授权。 本教程使用 Microsoft Entra ID 作为标识提供程序。
还可以将前端应用配置为:
- 向前端应用授予对后端应用的访问权限
- 对应用服务进行配置,使之返回可用令牌
- 在代码中使用该令牌。
有关详细信息,请参阅为应用程序服务应用程序配置 Microsoft Entra 身份验证。
在 Azure 门户菜单上,选择“资源组”,或在任意页面中搜索并选择“资源组”。
在“资源组”中,查找并选择资源组。 在“概述”中,选择后端应用。
在后端应用的左侧菜单中,选择“身份验证”,然后选择“添加标识提供者”。
在“添加标识提供者”页上,选择“Microsoft”作为“标识提供者”以登录 Microsoft 和 Microsoft Entra 标识。
接受默认设置,然后选择“添加”。
这时会显示“身份验证”页。 将 Microsoft Entra 应用程序的“客户端 ID”复制到记事本。 稍后需要用到此值。
如果到此为止,你将拥有一个已受应用服务身份验证和授权保护的独立应用。 其余部分介绍如何将经过身份验证的用户从前端“流式传输”到后端,以便保护多应用解决方案。
在 Azure 门户菜单上,选择“资源组”,或在任意页面中搜索并选择“资源组”。
在“资源组”中,查找并选择资源组。 在“概述”中,选择前端应用的管理页。
在前端应用的左侧菜单中,选择“身份验证”,然后选择“添加标识提供者”。
在“添加标识提供者”页上,选择“Microsoft”作为“标识提供者”以登录 Microsoft 和 Microsoft Entra 标识。
接受默认设置,然后选择“添加”。
这时会显示“身份验证”页。 将 Microsoft Entra 应用程序的“客户端 ID”复制到记事本。 稍后需要用到此值。
启用对两种应用的身份验证和授权以后,即可通过 AD 应用程序对每种应用提供支持。 要完成身份验证,需要执行以下三项操作:
- 向前端应用授予对后端应用的访问权限
- 对应用服务进行配置,使之返回可用令牌
- 在代码中使用该令牌。
提示
如果在遇到错误后重新配置应用的身份验证/授权设置,则可能无法通过新的设置在令牌存储中重新生成令牌。 若要确保重新生成令牌,需在注销后重新登录应用。 若要这样做,一个简单的方法是在专用模式下使用浏览器,在应用中更改设置后关闭该浏览器,然后再在专用模式下将其重新打开。
在此步骤中,将代表用户向前端应用授予对后端应用的访问权限。 (严格说来就是,请为前端的 AD 应用程序授予代表用户访问后端的 AD 应用程序的权限。)
在前端应用的“身份验证”页面中,在“标识提供者”下选择前端应用名称。 此应用注册是自动为你生成的。 在左侧菜单中选择“API 权限”。
选择“添加权限”,然后选择“我的 API”><back-end-app-name>。
在后端应用的“请求 API 权限”页中,选择“委托的权限”和“user_impersonation”,然后选择“添加权限”。
现在,前端应用具有以登录用户身份访问后端应用所需的权限。 在此步骤中,请配置应用服务身份验证和授权,以便获取可以用来访问后端的访问令牌。 执行此步骤时,需要后端的客户端 ID,该 ID 是从为后端应用启用身份验证和授权复制的。
在 Cloud Shell 中,在前端应用上运行以下命令,以将 scope
参数添加到身份验证设置 identityProviders.azureActiveDirectory.login.loginParameters
。 替换 <front-end-app-name> 和 <back-end-client-id>。
az extension add --name authV2
authSettings=$(az webapp auth show -g myAuthResourceGroup -n <front-end-app-name>)
authSettings=$(echo "$authSettings" | jq '.properties' | jq '.identityProviders.azureActiveDirectory.login += {"loginParameters":["scope=openid offline_access api://<back-end-client-id>/user_impersonation"]}')
az webapp auth set --resource-group myAuthResourceGroup --name <front-end-app-name> --body "$authSettings"
这些命令有效地添加了具有额外自定义范围的 loginParameters
属性。 下面解释了请求的范围:
提示
- 若要在 Azure 门户中查看
api://<back-end-client-id>/user_impersonation
范围,请转到后端应用的“身份验证”页,单击“标识提供者”下的链接,然后在左侧菜单中单击“公开 API”。
- 若要改为使用 Web 界面配置所需的范围,请参阅刷新身份验证令牌中的 Microsoft 步骤。
- 某些范围需要管理员同意或用户同意。 此要求会导致当用户在浏览器中登录前端应用时显示同意请求页面。 为避免出现此同意页面,请在“公开 API”页面中将前端应用注册添加为授权客户端应用程序,方法是单击“添加客户端应用程序”并提供前端应用注册的客户端 ID。
现在已配置好了应用。 前端现在可以通过适当的访问令牌访问后端了。
若要了解如何为其他提供程序配置访问令牌,请参阅刷新标识提供者令牌。
还应当将后端应用服务配置为仅接受来自前端应用服务的令牌。 如果不这样做,在将令牌从前端传递到后端时可能会导致“403:禁止访问错误”。
可以通过上一步中使用的同一 Azure CLI 过程来执行此设置。
获取前端应用服务的 appId
(可以在前端应用服务的“身份验证”边栏选项卡上获取此项)。
运行以下 Azure CLI,并替换 <back-end-app-name>
和 <front-end-app-id>
。
authSettings=$(az webapp auth show -g myAuthResourceGroup -n <back-end-app-name>)
authSettings=$(echo "$authSettings" | jq '.properties' | jq '.identityProviders.azureActiveDirectory.validation.defaultAuthorizationPolicy.allowedApplications += ["<front-end-app-id>"]')
az webapp auth set --resource-group myAuthResourceGroup --name <back-end-app-name> --body "$authSettings"
authSettings=$(az webapp auth show -g myAuthResourceGroup -n <back-end-app-name>)
authSettings=$(echo "$authSettings" | jq '.properties' | jq '.identityProviders.azureActiveDirectory.validation.jwtClaimChecks += { "allowedClientApplications": ["<front-end-app-id>"]}')
az webapp auth set --resource-group myAuthResourceGroup --name <back-end-app-name> --body "$authSettings"
前端应用需要将具有正确 user_impersonation
范围的用户身份验证传递到后端。 以下步骤查看了为此功能提供的示例代码。
查看前端应用的源代码:
使用前端应用服务注入标头 x-ms-token-aad-access-token
,以编程方式获取用户的 accessToken。
// ./src/server.js
const accessToken = req.headers['x-ms-token-aad-access-token'];
使用标头 Authentication
中的 accessToken 作为 bearerToken
值。
// ./src/remoteProfile.js
// Get profile from backend
const response = await fetch(remoteUrl, {
cache: "no-store", // no caching -- for demo purposes only
method: 'GET',
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
if (response.ok) {
const { profile } = await response.json();
console.log(`profile: ${profile}`);
} else {
// error handling
}
本教程返回虚构配置文件以简化方案。 本系列中的下一个教程演示了如何将后端 bearerToken 交换为具有下游 Azure 服务(如 Microsoft Graph)范围的新令牌。
如果来自前端的请求未授权,后端应用服务会在请求送达应用程序代码之前拒绝请求,并显示 401 HTTP 错误代码。 当后端代码到达时(因为其包括授权令牌),提取 bearerToken 以获取 accessToken。
查看后端应用的源代码:
// ./src/server.js
const bearerToken = req.headers['Authorization'] || req.headers['authorization'];
if (bearerToken) {
const accessToken = bearerToken.split(' ')[1];
console.log(`backend server.js accessToken: ${!!accessToken ? 'found' : 'not found'}`);
// TODO: get profile from Graph API
// provided in next article in this series
// return await getProfileFromMicrosoftGraph(accessToken)
// return fake profile for this tutorial
return {
"displayName": "John Doe",
"withAuthentication": !!accessToken ? true : false
}
}
在浏览器中使用前端网站。 该 URL 的格式为 https://<front-end-app-name>.azurewebsites.net/
。
浏览器向 Web 应用请求身份验证。 完成身份验证。
身份验证完成后,前端应用程序将返回应用的主页。
选择 Get user's profile
。 这会将持有者令牌中的身份验证传递到后端。
后端使用虚构的硬编码配置文件名称进行响应:John Doe
。
withAuthentication
值为 true 表示已设置身份验证。
在前面的步骤中,你在资源组中创建了 Azure 资源。
通过在 Cloud Shell 中运行以下命令来删除资源组。 此命令可能需要花费一点时间运行。
az group delete --name myAuthResourceGroup
使用身份验证应用的客户端 ID,你之前在后端和前端应用的 Enable authentication and authorization
部分中找到并记下了此 ID。
删除前端和后端应用的应用注册。
# delete app - do this for both frontend and backend client ids
az ad app delete <client-id>
此过程中的身份验证由 Azure 应用服务在托管平台层提供。 没有等效的仿真器。 必须逐个部署前端和后端应用,并对身份验证进行配置,才能使用身份验证。
当此应用程序不返回虚构的配置文件时,前端应用和后端应用都具备可帮助调试身份验证的 /debug
路由。 前端调试路由提供用于验证的关键部分:
- 环境变量:
BACKEND_URL
已正确配置为 https://<back-end-app-name>.azurewebsites.net
。 请勿包含尾随正斜杠或路由。
- HTTP 标头:
- 将显示已登录用户的 Microsoft Graph 配置文件名称。
- 令牌的前端应用的范围具有
user_impersonation
。 如果范围不包含此内容,则可能是计时问题。 验证 Azure 资源中的前端应用的 login
参数。 等待几分钟后才能复制身份验证。
应用程序源代码是否已正确部署到每个 Web 应用?
在 Web 应用的 Azure 门户中,选择“开发工具 -> 高级工具”,然后选择“转到 ->”。 此操作将打开新的浏览器选项卡或窗口。
在新的浏览器选项卡中,选择“浏览目录 -> 站点 wwwroot”。
验证目录中的以下内容:
- package.json
- node_modules.tar.gz
- /src/index.js
验证 package.json 的 name
属性是否与 Web 名称相同(frontend
或 backend
)。
如果更改了源代码,并且需要重新部署,请使用包含该应用的 package.json 文件的目录中的 az webapp up。
请求主页时,这两个 Web 应用都应返回一些内容。 如果无法访问 Web 应用上的 /debug
,则表示该应用无法正常启动。 查看该 Web 应用的错误日志。
- 在 Web 应用的 Azure 门户中,选择“开发工具 -> 高级工具”,然后选择“转到 ->”。 此操作将打开新的浏览器选项卡或窗口。
- 在新的浏览器选项卡中,选择“浏览目录 -> 部署日志”。
- 查看每个日志以查找任何报告的问题。
由于前端应用从服务器源代码调用后端应用,因此不会在浏览器网络流量中看到相应内容。 使用以下列表来确定后端配置文件请求是否成功:
- 后端 Web 应用在到达前端应用时会将任何错误返回给前端应用。 如果未到达,前端应用将报告状态代码和消息。
- 401:用户未正确传递身份验证。 这表示范围未设置正确。
- 404:服务器的 URL 与服务器具有的路由不匹配
- 使用后端应用的流式处理日志监视用户配置文件的前端请求。 包含
console.log
的源代码中有调试信息,可用于帮助确定故障发生位置。
访问令牌在一段时间后会过期。 若要了解如何在不需用户通过应用重新进行身份验证的情况下刷新访问令牌,请参阅刷新标识提供者令牌。
如果我在前端应用上有一个基于浏览器的应用,它可以直接与后端对话吗?
这种方法要求服务器代码将访问令牌传递给客户端浏览器中运行的 JavaScript 代码。 由于没有办法保护浏览器中的访问令牌,因此不推荐这种方法。 目前,建议采用“后端服务前端”模式。 如果应用于本教程中的示例,则前端应用上的浏览器代码将在经过身份验证的会话中向其作为中介的服务器代码发出 API 调用,而前端应用上的服务器代码则会依次使用 x-ms-token-aad-access-token
标头值作为持有者令牌向后端应用发出 API 调用。 从浏览器代码到服务器代码的所有调用都已受到经过身份验证的会话的保护。
你已了解:
- 启用内置身份验证和授权
- 确保应用能够防范未经身份验证的请求
- 使用 Microsoft Entra ID 作为标识提供者
- 代表登录的用户访问远程应用
- 使用令牌身份验证确保服务间调用的安全性
- 使用服务器代码中的访问令牌
转到下一教程,了解如何使用此用户的标识访问 Azure 服务。