使用 Cloud Run 托管登录页面

要将外部身份与 Identity-Aware Proxy (IAP) 搭配使用,您的应用需要登录页面。IAP 会将用户重定向到此页面进行身份验证,然后用户才能访问安全资源。

本文档介绍如何使用 Cloud Run 部署和自定义预构建的登录页面。这是开始使用外部身份的最快方式,您无需编写任何代码。

您还可以自行构建登录页面。构建自己的页面比较复杂,但可以加强您对身份验证流程和体验的控制。如需了解详情,请参阅使用 FirebaseUI 创建登录页面创建自定义登录页面

登录页面限制

如果您的项目启用了电子邮件枚举保护,则您无法使用预构建的登录页面。

如果您的项目启用了电子邮件枚举保护,请先停用 email-enumeration-protection,然后再继续执行本文档中的过程。

准备工作

  • 启用 Compute Engine API。

    启用 Compute Engine API

  • 启用外部身份,并在设置期间选择为我创建登录页面选项。这样,Cloud Run 和 FirebaseUI 就可以为您创建登录页面。

  • 确保 Cloud Run 使用的服务帐号 (PROJECT_NUMBER-compute@developer.gserviceaccount.com) 具备以下预定义角色

    • roles/identitytoolkit.viewer
    • roles/iap.settingsAdmin
    • roles/compute.networkViewer

设置托管网页的重定向网址

托管登录页面使用自己的网域作为 Firebase 身份验证网域,以确保通过重定向登录在所有环境中都能正常运行。您必须将托管网页的网址添加为提供商配置中的已授权重定向网址。

要将托管登录页面的网址添加为已获授权的重定向网址,请执行以下操作:

  1. 选择您的应用后,复制 Login 网址(登录网址)。

  2. 在 Google Cloud 控制台中,转到凭据页面。

    前往“凭据”页面

  3. LOGIN_URL/__/auth/handler 添加为应用的 OAuth 2.0 客户端的已授权重定向 URI 之一。选择您在配置提供方时使用的相同 OAuth 客户端 ID 和密钥。

  4. 如果您的应用在使用其他 SAML 和 OIDC 提供方,请将 LOGIN_URL/__/auth/handler 添加为已获授权的重定向 URI 或 ACS 网址。

或者,您也可以使用弹出式登录流程自定义登录页面,从而使用 PROJECT_ID.firebaseapp.com(而不是 LOGIN_URL/__/auth/handler)作为身份验证网域。

如需为您的页面实现弹出式登录流程,请执行以下操作:

  1. 点击自定义页面

  2. 在 JSON 格式的配置文件中,将 authDomain 设置为 PROJECT_ID.firebaseapp.com,将 signInFlow 设置为 popup

  3. 要保存配置,请点击保存

替换以下内容:

  • LOGIN_URL:您的托管登录页面的域名
  • PROJECT_ID:Firebase 项目 ID

以下是弹出式登录流程配置的示例:

{
  "AIzaSyC5DtmRUR...": {
    "authDomain": "example.firebaseapp.com",
    "displayMode": "optionFirst",
    ...
    ...
    "tenants": {
      "tenant-a-id": {
        "fullLabel": "Company A Portal",
        "displayName": "Company A",
        ...
        ...
        "signInFlow": "popup",
        ...
        ...
      }
    }
  }
}

如需详细了解重定向最佳实践和存储分区,请参阅在阻止第三方访问存储空间的浏览器上使用 signInWithRedirect 的最佳实践

测试登录页面

IAP 创建的初始登录页面可以完全正常运行。要进行测试,请按以下步骤操作:

  1. 导航到受 IAP 保护的资源。系统应该会自动将您重定向至登录页面。

  2. 选择用于登录的租户和提供商。如果您没有看到任何租户或提供商,请确保您已使用 Identity Platform 配置了一个租户或提供商。

  3. 使用凭据登录。

系统应该会将您重定向到受保护的资源。

自定义登录页面

您可以使用 JSON 配置文件来自定义登录页面。选项包括:

  • 在登录页面中添加标头和徽标。
  • 指定可用的租户和提供商。
  • 自定义每个租户和提供商按钮的图标和样式。
  • 添加指向应用隐私权政策和服务条款的链接。

以下部分介绍了如何访问和更新 JSON 配置文件。

获取访问令牌

为了管理登录页面,您需要有 Google 访问令牌。获取 Google 访问令牌最简单的方法是让 Google 成为 Identity Platform 的提供商。如果您的应用已经将 Google 用作身份提供商,则您可以跳过本部分。

  1. 前往 Google Cloud 控制台中的 Identity Platform Providers 页面。

    转到“Identity Platform 提供商”页面

  2. 点击添加提供商

  3. 从提供商列表中选择 Google

  4. 配置 Web 客户端 IDWeb 客户端密钥

    1. 在单独的标签页中,打开 IAP 页面。

      转到 IAP 页面

    2. 展开资源的展开菜单,然后点击修改 OAuth 客户端

    3. 客户端 ID客户端密钥字段复制到 Identity Platform 的 Google 提供商配置中。

    4. 将 Identity Platform 重定向网址添加到 OAuth 客户端的已获授权的重定向 URI 列表中。网址的格式类似于 https://PROJECT_ID.firebaseapp.com/__/auth/handler

  5. 在这两个页面上点击保存

登录到管理控制台面板

由 Cloud Run 托管的登录页面的 JSON 配置。以下步骤显示了如何访问面板。请注意,您将需要 Storage Admin (roles/storage.admin) 角色。

  1. 前往 Google Cloud 控制台中的 IAP 页面。

    转到 IAP 页面

  2. 从列表中选择您的资源。

  3. 启动在信息面板的自定义页面下列出的网址。其格式应为 https://servicename-xyz-uc.a.run.app/admin

  4. 使用您用于配置 IAP 的同一 Google 账号进行登录。此时将显示包含 JSON 配置文件的文本编辑器。

修改配置

登录页面的配置架构基于 FirebaseUI,并沿用其多项属性。以下代码展示了一个包含三个租户的配置示例:

{
  "AIzaSyC5DtmRUR...": {
    "authDomain": "awesomeco.firebaseapp.com",
    "displayMode": "optionFirst",
    "selectTenantUiTitle": "Awesome Company Portal",
    "selectTenantUiLogo": "https://awesome.com/abcd/logo.png",
    "styleUrl": "https://awesome.com/abcd/overrides/stylesheet.css",
    "tosUrl": "https://awesome.com/abcd/tos.html",
    "privacyPolicyUrl": "https://awesome.com/abcd/privacypolicy.html",
    "tenants": {
      "tenant-a-id": {
        "fullLabel": "Company A Portal",
        "displayName": "Company A",
        "iconUrl": "https://companya.com/img/icon.png",
        "logoUrl": "https://companya.com/img/logo.png",
        "buttonColor": "#007bff",
        "signInOptions": [
          {
            "provider": "password",
            "requireDisplayName": false,
            "disableSignUp": {
              "status": true,
              "adminEmail": "admin@example.com",
              "helpLink": "https://www.example.com/trouble_signing_in"
            }
          },
          "facebook.com",
          "google.com",
          "microsoft.com",
          {
            "provider": "saml.okta-cicp-app",
            "providerName": "Corp Account",
            "fullLabel": "Employee Corporate Login",
            "buttonColor": "#ff0000",
            "iconUrl": "https://companya.com/abcd/icon-1.png"
          },
          {
            "provider": "oidc.okta-oidc",
            "providerName": "Contractor Account",
            "fullLabel": "Contractor Account Portal",
            "buttonColor": "#00ff00",
            "iconUrl": "https://companya.com/abcd/icon-2.png"
          }
        ],
        "tosUrl": "https://companya.com/abcd/tos.html",
        "privacyPolicyUrl": "https://companya.com/abcd/privacypolicy.html"
      },
      "tenant-b-id": {
        "fullLabel": "Company B Portal",
        "displayName": "Company B",
        "iconUrl": "https://companyb.com/img/icon.png",
        "logoUrl": "https://companyb.com/img/logo.png",
        "buttonColor": "#007bff",
        "immediateFederatedRedirect": true,
        "signInOptions": [
          {
            "provider": "saml.okta-bla-app",
            "providerName": "Corp Account",
            "buttonColor": "#0000ff",
            "iconUrl": "https://companyb.com/abcd/icon.png"
          }
        ],
        "tosUrl": "https://companyb.com/abcd/tos.html",
        "privacyPolicyUrl": "https://companyb.com/abcd/privacypolicy.html"
      },
      "tenant-c-id": {
        "fullLabel": "Company C Portal",
        "displayName": "Company C",
        "iconUrl": "https://companyc.com/img/icon.png",
        "logoUrl": "https://companyc.com/img/logo.png",
        "buttonColor": "#007bff",
        "immediateFederatedRedirect": true,
        "signInOptions": [
          {
            "provider": "password",
            "requireDisplayName": false
          },
          {
            "provider": "google.com",
            "scopes": ["scope1", "scope2", "https://example.com/scope3"],
            "loginHintKey": "login_hint",
            "customParameters": {
              "prompt": "consent",
            },
          }
        ],
        "tosUrl": "https://companyc.com/abcd/tos.html",
        "privacyPolicyUrl": "https://companyc.com/abcd/privacypolicy.html",
        "adminRestrictedOperation": {
          "status": true,
          "adminEmail": "admin@example.com",
          "helpLink": "https://www.example.com/trouble_signing_in"
        }
      },
    }
  }
}

如需查看可用属性的完整列表,请参阅参考文档

替换 CSS

您可以使用 styleUrl 属性指定自定义 CSS 文件。此文件中的样式将替换默认的 CSS。该文件必须可使用 HTTPS 进行公开访问(例如,托管在 Cloud Storage 存储桶中)。

以下示例演示了如何替换默认 CSS:

/** Change header title style. */
.heading-center {
  color: #7181a5;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 20px;
  font-weight: bold;
}

/** Use round edged borders for container. */
.main-container {
  border-radius: 5px;
}

/** Change page background color. */
body {
  background-color: #f8f9fa;
}

重新部署 Cloud Run 实例

在某些情况下,您可能希望重新部署托管登录页面的 Cloud Run 实例。示例场景包括:

  • 添加、修改或移除身份提供商
  • 修改租户配置
  • 设置环境变量
  • 将容器映像更新为最新版本

定期更新和重新部署容器映像可确保您获得最新的 Bug 修复和安全补丁程序。您可以在 GitHub 上查看版本之间的更改的列表。

您可以使用 /versionz 端点获取已部署容器的当前版本。例如:

curl 'https://servicename-xyz-uc.a.run.app/versionz'

如需重新部署 Cloud Run 实例,请执行以下操作:

  1. 前往 Google Cloud 控制台中的 Cloud Run 页面。

    转到 Cloud Run 页面

  2. 选择托管登录页面的实例。

  3. 点击修改和部署新修订版本

  4. (可选)指定修订版本的高级设置,或点击变量和密钥标签页来添加环境变量。

  5. 点击部署

高级选项

以编程方式自定义登录页面

除了使用 /admin 控制台之外,您还可以通过编程方式更新 JSON 配置。

要获取当前配置,请使用 /get_admin_config 端点。例如:

curl -H 'Authorization: Bearer [TOKEN]'
  'https://servicename-xyz-uc.a.run.app/get_admin_config'

要更新配置,请使用 /set_admin_config。例如:

curl -XPOST -H 'Authorization: Bearer [TOKEN]' -H "Content-type: application/json"
  -d '[UPDATED-CONFIG]' 'https://servicename-xyz-uc.a.run.app/set_admin_config'

这两种 REST 调用都需要 https://www.googleapis.com/auth/devstorage.read_write 范围,并且必须将有效的 OAuth 令牌附加到 Authorization 标头。

设置环境变量

您可以在 Cloud Run 实例上设置环境变量,以自定义高级设置。下表列出了可用的变量:

变量 说明
DEBUG_CONSOLE 指示是否记录所有网络请求错误和详细信息的布尔值(01)。系统将不会记录敏感数据。默认情况下,处于停用状态 (0)。
UI_CONFIG 包含登录页面的 JSON 配置的字符串。使用此变量而不是 /admin 面板可以避免在访问配置时对 Cloud Storage 执行读写操作。系统会忽略无效配置。在设置此变量之前使用 /admin 面板验证您的 JSON,有助于最大限度地减少语法错误。
GCS_BUCKET_NAME 字符串,替换用于存储 JSON 配置的默认 Cloud Storage 存储桶。该文件名为 config.json,默认位置为 gcip-iap-bucket-[CLOUD-RUN-SERVICE-NAME]-[PROJECT-NUMBER]
ALLOW_ADMIN 布尔值(01),指示是否允许访问 /admin 配置面板。默认情况下,处于启用状态 (1)。

更新变量后,您需要部署新版 Cloud Run 实例以使更改生效。如需详细了解环境变量,请参阅 Cloud Run 文档

自定义网域

默认情况下,用户会在登录时查看 Cloud Run 实例的网址。要改为指定自定义网域,请执行以下操作:

  1. 按照映射自定义网域中的步骤为 Cloud Run 实例设置自定义网域。

  2. 将 IAP 配置为使用新的身份验证网址:

    1. 前往 Google Cloud 控制台中的 IAP 页面。

      转到 IAP 页面

    2. 选择受 IAP 保护的资源。

    3. 在侧边栏中,选择登录网址字段旁边的修改图标。

    4. 选择使用现有托管的登录页面,然后从下拉菜单中选择网域。

    5. 点击保存

使用一个登录页面来保护多个 IAP 资源

您可以使用相同的登录页面保护多个 IAP 资源。这样做可以减少与管理多个配置相关的工作。

要重新使用登录页面,请执行以下操作:

  1. 按照本文中的步骤为受 IAP 保护的第一个资源部署身份验证页面。

  2. 为第二个资源启用 IAP。当系统提示您指定登录页面时,请选择我将提供自己的登录页面,然后输入 Cloud Run 服务的网址作为网址

  3. 重新部署 Cloud Run 服务。

问题排查

在停用第三方 Cookie 或实施存储分区的浏览器上,登录页面无法使用。

如需解决此问题,请执行以下操作:

  1. 重新部署登录页面。最新版本的登录页面将登录页面的网域用作 authDomain

  2. 自定义登录页面的配置,确保将 authDomain 设置为受 IAP 保护的应用的登录页面的网址。

    {
      "AIzaSyC5DtmRUR...": {
        "authDomain": "LOGIN_URL",
        ...
      }
    }
    

后续步骤