使用 Identity-Aware Proxy 进行用户身份验证

使用 Identity-Aware Proxy 进行用户身份验证

关于此 Codelab

subject上次更新时间:11月 12, 2019
account_circleengelke 编写

1. 简介

对 Web 应用的用户进行身份验证通常十分必要,并且通常需要在应用中进行特殊编程。对于 Google Cloud Platform 应用,您可以将这些责任移交给 Identity-Aware Proxy 服务。如果您只需要将访问权限限制到选定的用户,则无需对应用进行任何更改。如果应用需要知道用户的身份(例如,用于在服务器端保留用户偏好设置),Identity-Aware Proxy 只需极少的应用代码即可实现这一点。

什么是 Identity-Aware Proxy?

身份识别代理 (IAP) 是一项 Google Cloud Platform 服务,可拦截发送到您应用的 Web 请求、使用 Google Identity Service 对发出请求的用户进行身份验证,并仅允许这些请求来自您授权的用户。此外,它可以修改请求标头,以包含经过身份验证的用户的相关信息。

此 Codelab 将引导您创建自己的应用、限制应用的访问权限以及从 IAP 获取用户身份。

构建内容

在此 Codelab 中,您将使用 Google App Engine 构建一个最精简的 Web 应用,然后探索使用 Identity-Aware Proxy 限制应用访问权限和向应用提供用户身份信息的各种方式。您的应用将:

  • 显示欢迎页面
  • 访问 IAP 提供的用户身份信息
  • 使用加密验证技术防范仿冒用户身份信息

学习内容

  • 如何使用 Python 3.7 编写和部署简单的 App Engine 应用
  • 如何启用和停用 IAP 以限制对应用的访问
  • 如何将用户身份信息从 IAP 传递到您的应用
  • 如何对来自 IAP 的信息进行加密验证,以防止仿冒

所需条件

  • 新型网络浏览器,例如 Chrome
  • 具备 Python 编程语言方面的基础知识

本 Codelab 主要介绍 Google App Engine 和 IAP。对于不相关的概念,我们仅会略作介绍,但是会提供不相关的代码块供您复制和粘贴。

2. 准备工作

您将在 Cloud Shell 命令行环境中工作。首先打开该环境并提取示例代码。

启动控制台和 Cloud Shell

在实验页面的左上方,点击“打开 Google 控制台”按钮。您需要使用该按钮下方显示的用户名和密码登录。

此 Codelab 中的所有命令都将在为您创建并打开的项目在 Cloud Shell 中执行。点击控制台页面标题右侧的“激活 Cloud Shell”图标,打开 Cloud Shell。下半部分用于输入和运行命令。

您可以用自己的 PC 运行这些命令,但必须先安装和配置所需的开发软件。Cloud Shell 已包含您所需的所有软件工具。

下载代码

点击 Cloud Shell 中的命令行区域,以便输入命令。从 GitHub 提取代码,然后切换到代码文件夹:

git clone https://github.com/googlecodelabs/user-authentication-with-iap.git
cd iap
-codelab

此文件夹包含此 Codelab 的每个步骤的子文件夹。系统会切换到正确的文件夹以执行每个步骤。

3. 第 1 步 - 部署应用并通过 IAP 进行保护

这是一个用 Python 3.7 编写的 App Engine 标准应用,仅用于显示“Hello, World”欢迎页面。我们将部署并测试该应用,然后使用 IAP 限制对该应用的访问。

查看应用代码

从主项目文件夹更改为包含此步骤的代码的 1-HelloWorld 子文件夹。

cd 1-HelloWorld

应用代码位于 main.py 文件中。它使用 Flask Web 框架并使用模板内容响应网络请求。该模板文件位于 templates/index.html 中,在此步骤中仅包含纯 HTML。第二个模板文件包含 templates/privacy.html 中的框架示例隐私权政策。

还有另外两个文件:requirements.txt 列出应用使用的所有非默认 Python 库,app.yaml 告知 Google Cloud Platform 这是一个 Python 3.7 App Engine 应用。

您可以使用 cat 命令列出 shell 中的每个文件,如下所示:

cat main.py

或者,您可以点击 Cloud Shell 窗口右上角的铅笔图标来打开 Cloud Shell 代码编辑器,然后以这种方式检查代码。

在此步骤中,您无需更改任何文件。

部署到 App Engine

现在将应用部署到 Python 3.7 版 App Engine 标准环境

gcloud app deploy

系统可能会要求您选择要部署到的区域。请选择您附近显示“支持标准”的任何一个。当系统询问您是否要继续时,请输入 Y 表示“是”。

部署将在几分钟内完成,届时您会看到一条消息,显示您可以使用 gcloud app browse 查看应用。输入该命令。如果您的浏览器中未打开新标签页,请点击所显示的链接,在新标签页中打开该标签页,或视需要将其复制到手动打开的新标签页。由于这是首次运行此应用,因此当云实例启动时,它将需要几秒钟的时间进行显示,您应该会看到以下窗口。

您可以从连接到互联网的任意计算机上打开同一网址,以查看对应的网页。访问权限尚未受限。

使用 IAP 限制访问权限

在 Cloud Console 窗口中,点击页面左上角的菜单图标,点击“安全性”,然后点击“Identity-Aware Proxy”。

由于这是您第一次为此项目启用身份验证选项,您会看到一条消息,要求您必须先配置 OAuth 同意屏幕,然后才能使用 IAP。

点击“配置同意屏幕”按钮。系统会打开一个新标签页,供您配置同意屏幕。

在适当的空白处填入适当的值:

应用名称

应用内购示例

支持电子邮件地址

您的电子邮件地址,因为系统可能已为您填入地址

已获授权的网域

应用网址的主机名部分,例如 iap-example-999999.appspot.com。您可以在之前打开的 Hello World 网页的地址栏中看到此网址。请勿添加该网址的开头https://或结尾/

填写此值后,您必须按 Enter 键。

应用首页链接

您用于查看应用的网址

应用隐私权政策链接

应用中的隐私权页面链接,与在末尾添加 /privacy 的首页链接相同

点击保存。系统会提示您创建凭据。您无需为此 Codelab 创建凭据,只需关闭此浏览器标签页即可。

返回 Identity-Aware Proxy 页面并刷新页面。您现在应该会看到可供保护的资源列表。

点击“App Engine 应用”行中“IAP”列中的切换按钮,以开启 IAP。

您会看到受 IAP 保护的域名。点击“开启”。

现在,打开浏览器标签页并导航到应用的网址。系统会向您显示“使用 Google 帐号登录”屏幕,您需要登录才能访问该应用。

使用 Google 或 G Suite 帐号登录。您将看到一个拒绝访问的屏幕。

您已成功使用 IAP 保护应用,但尚未告知 IAP 允许哪些帐号通过。

返回控制台的 Identity-Aware Proxy 页面,选中 App Engine 应用旁边的复选框,然后查看页面右侧的边栏。

每个要允许访问的电子邮件地址(或 Google 群组地址或 G Suite 域名)都必须添加为成员。点击“添加成员”。输入您的电子邮件地址,然后选择要分配给该地址的 Cloud IAP/IAP-Secured Web App User 角色。您可以用同样的方式输入更多地址或 G Suite 域名。

点击“保存”。窗口底部会显示“政策已更新”消息。

返回您的应用并重新加载页面。您现在应该会看到自己的 Web 应用,因为您已经使用自己授权的用户进行登录。不过,您可能仍会看到“您没有访问权限”页面,因为 IAP 可能不会重新检查您的授权。在这种情况下,请按以下步骤操作:

  • 打开您的网络浏览器并转到首页网址,并在网址末尾添加 /_gcp_iap/clear_login_cookie,例如 https://iap-example-999999.appspot.com/_gcp_iap/clear_login_cookie
  • 您将看到一个新的“使用 Google 帐号登录”屏幕,其中已经显示您的帐号。请勿点击该帐号,请改为点击“使用其他帐号”,然后重新输入您的凭据。
  • 执行这些步骤后,IAP 会重新检查您的访问权限,现在您应该会看到您的应用主屏幕。

如果您可以使用其他浏览器,或能在浏览器中使用无痕模式,并且有其他有效的 Gmail 或 G Suite 帐号,那么您可以使用该浏览器转到应用页面,然后使用其他帐号登录。由于该帐号尚未获得授权,因此您会看到“您没有访问权限”屏幕,而不是您的应用。

4. 第 2 步 - 访问用户身份信息

如果应用受到 IAP 的保护,则它可以使用 IAP 在它传递的网络请求标头中提供的身份信息。在此步骤中,应用将获取已登录用户的电子邮件地址以及 Google Identity Service 为该用户分配的永久性唯一用户 ID。该数据会在欢迎页面中向用户显示。

这是第 2 步,最后一步是在 iap-codelab/1-HelloWorld 文件夹中打开 Cloud Shell 的情况下完成的。切换到此步骤所在的文件夹:

cd ~/iap-codelab/2-HelloUser

部署至 App Engine

由于部署需要几分钟时间,因此请先将应用部署到 Python 3.7 版 App Engine 标准环境:

gcloud app deploy

当系统询问您是否要继续时,请输入 Y 表示“是”。部署将在几分钟内完成。在等待期间,您可以检查应用文件,如下所述。

部署准备就绪后,您会看到一条消息,显示可通过 gcloud app browse 查看您的应用。输入该命令。如果浏览器中没有打开新的标签页,请复制显示的链接,然后正常在新标签页中打开。您应该会看到一个类似于以下内容的页面:

您可能需要等待几分钟,等待应用的新版本取代之前的版本。根据需要刷新页面,以查看与上面类似的页面。

检查应用文件

该文件夹包含第 1 步中显示的同一组文件,但更改了其中的两个文件:main.pytemplates/index.html。该程序已更改,以检索 IAP 在请求标头中提供的用户信息,而模板现在会显示该数据。

main.py 中有两行用于获取 IAP 提供的身份数据:

user_email = request.headers.get('X-Goog-Authenticated-User-Email')
user_id
= request.headers.get('X-Goog-Authenticated-User-ID')

X-Goog-Authenticated-User- 标头由 IAP 提供,且名称不区分大小写,因此可以根据需要以全小写或全大写形式提供它们。render_template 语句现在包含这些值,以便可以显示它们:

page = render_template('index.html', email=user_email, id=user_id)

index.html 模板可以通过用双括号括住名称来显示这些值:

Hello, {{ email }}! Your persistent ID is {{ id }}.

如您所见,所提供的数据带有前缀 accounts.google.com:,显示信息的来源。如果需要,您的应用可以移除所有的内容,包括冒号,以获取原始值。

关闭 IAP

如果 IAP 停用或因某种原因被绕过(例如被同一云项目中运行的其他应用),会发生什么情况?关闭 IAP 即可查看。

在 Cloud Console 窗口中,点击页面左上角的菜单图标,点击“安全性”,然后点击“Identity-Aware Proxy”。点击 App Engine 应用旁边的 IAP 切换开关以关闭 IAP。

应用会被警告后,所有用户都可以访问该应用。

刷新应用网页。您应该会看到同一个网页,但其中没有任何用户信息:

由于应用现在不受保护,因此用户可能会发送看似已通过 IAP 的网络请求。例如,您可以从 Cloud Shell 运行以下 curl 命令(将 <your-url-here> 替换为您应用的正确网址):

curl -X GET <your-url-here> -H "X-Goog-Authenticated-User-Email: totally fake email"

网页将在命令行中显示,如下所示:

<!doctype html>
<html>
<head>
  <title>IAP Hello User</title>
</head>
<body>
  <h1>Hello World</h1>

  <p>
    Hello, totally fake email! Your persistent ID is None.
  </p>

  <p>
    This is step 2 of the <em>User Authentication with IAP</em>
    codelab.
 </p>

</body>
</html>

应用无法知道应用内购商品是否已停用或被绕过。对于存在潜在风险的情况,第 3 步会显示解决方案。

5. 第 3 步 - 使用加密验证

如果应用存在关闭或绕过 IAP 的风险,您的应用可进行检查以确保收到的身份信息有效。此操作将使用由 IAP 添加的第 3 个网络请求标头,称为 X-Goog-IAP-JWT-Assertion。标头的值是经过加密的签名对象,其中还包含用户身份数据。您的应用可以验证数字签名,并使用此对象中提供的数据来确保由 IAP 提供且不加改动。

数字签名验证需要执行一些额外的步骤,例如检索最新的 Google 公钥集。您可以根据可能有人关闭或绕过 IAP 的风险以及应用的敏感程度来决定您的应用是否需要这些额外的步骤。

这是第 3 步,最后一步是在 iap-codelab/2-HelloUser 文件夹中打开您的 Cloud Shell。切换到此步骤所在的文件夹:

cd ~/iap-codelab/3-HelloVerifiedUser

部署到 App Engine

将应用部署到适用于 Python 3.7 的 App Engine 标准环境:

gcloud app deploy

当系统询问您是否要继续时,请输入 Y 表示“是”。部署将在几分钟内完成。在等待期间,您可以检查应用文件,如下所述。

部署准备就绪后,您会看到一条消息,显示可通过 gcloud app browse 查看您的应用。输入该命令。如果浏览器中没有打开新的标签页,请复制显示的链接,然后正常在新标签页中打开。

回想一下,您在第 2 步中停用了 IAP,因此并未向应用提供任何 IAP 数据。您应该会看到一个类似于以下内容的页面:

与以前一样,您可能需要等待几分钟才能看到最新版本的网页上线。

由于 IAP 已停用,因此没有可用的用户信息。现在,重新开启 IAP。

在 Cloud Console 窗口中,点击页面左上角的菜单图标,点击“安全性”,然后点击“Identity-Aware Proxy”。点击 App Engine 应用旁边的 IAP 切换开关,以重新启用 IAP。

刷新页面。页面应如下所示:

请注意,由经过验证的方法提供的电子邮件地址没有 accounts.google.com: 前缀。

如果 IAP 已关闭或被绕过,那么除非这些数据是由 Google 私钥的持有者创建,否则它可能会缺失或无效,因为它无法拥有有效签名。

检查应用文件

此文件夹包含与第 2 步中相同的文件集,并更改了两个文件和一个新文件。新文件是 auth.py,它提供了一个 user() 方法,用于检索和验证经过加密签名的身份信息。更改后的文件是 main.pytemplates/index.html,它们现在使用该方法的结果。第 2 步中发现的未经验证的标题也会进行比较。

新功能主要位于 user() 函数中:

def user():
    assertion
= request.headers.get('X-Goog-IAP-JWT-Assertion')
   
if assertion is None:
       
return None, None

    info
= jwt.decode(
        assertion
,
        keys
(),
        algorithms
=['ES256'],
        audience
=audience()
   
)

   
return info['email'], info['sub']

assertion 是指定请求标头中提供的加密签名数据。该代码使用库来验证和解码该数据。验证功能使用 Google 提供的公钥来检查签名以及了解数据准备的受众(实际上就是受保护的 Google Cloud 项目)。辅助函数 keys()audience() 会收集并返回这些值。

已签名的对象需要两部分数据:经过验证的电子邮件地址,以及唯一 ID 值(对于订阅者、标准字段,在 sub 中提供)。

至此,完成第 3 步。

6. 总结

您部署了一个 App Engine Web 应用。在第 1 步中,您仅允许自己选择用户访问该应用。在第 2 步中,您检索并显示了 IAP 允许访问您应用的用户的身份,并了解在 IAP 被停用或绕过后,这些信息可能会遭到仿冒。在第 3 步中,您验证了用户身份的加密签名,该声明不可仿冒。

7. 清理

您在此 Codelab 中使用的唯一 Google Cloud Platform 资源是 App Engine 实例。每次您部署应用时,系统都会创建一个新版本并继续保留,直到删除为止。退出实验,删除项目及其中的所有资源。