使用 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

為 Identity Platform 供應商設定已授權的重新導向 URI

如果您使用需要重新導向登入 (重新導向至外部 IdP 登入頁面) 的 Identity Platform 供應商,您必須在供應商設定中,將代管登入頁面的網址新增為已授權的重新導向網址。

舉例來說,如果是 Google 供應商,您需要執行以下操作:

  1. 選取受 IAP 保護的應用程式後,複製「登入網址」

  2. 在 Google Cloud 控制台中,前往「Credentials」頁面。

    前往「憑證」

  3. LOGIN_URL/__/auth/handler 新增為應用程式 OAuth 2.0 用戶端的其中一個已授權的重新導向 URI。選取與設定 Google 供應器時相同的 OAuth 用戶端 ID。

如為其他 SAML 和 OIDC 供應商,請將 LOGIN_URL/__/auth/handler 新增為已授權的重新導向 URI 或 ACS 網址。

測試登入頁面

IAP 建立的初始登入頁面運作正常。如要測試這項功能,請按照下列步驟操作:

  1. 前往受 IAP 保護的資源。系統應會自動將您重新導向登入頁面。

  2. 選取要登入的租用戶和供應商。如果您沒有看到任何用戶群或供應者,請確認您已使用 Identity Platform 設定一個。

  3. 使用憑證登入。

系統應會將您重新導向至受保護的資源。

自訂登入頁面

您可以使用 JSON 設定檔自訂登入頁面。部分選項包括:

  • 在登入頁面中加入標頭和標誌。
  • 指定可用的租戶和供應者。
  • 自訂每個租用戶和供應商按鈕的圖示和樣式。
  • 加入應用程式隱私權政策和服務條款的連結。

以下各節說明如何存取及更新 JSON 設定檔。

取得存取權杖

您必須具備 Google 存取權權杖,才能管理登入網頁。取得這項權限最簡單的方法,就是將 Google 設為 Identity Platform 的供應商。如果您的應用程式已使用 Google 做為識別資訊提供者,可以略過本節。

  1. 前往Google Cloud 控制台的「Identity Platform Providers」頁面。

    前往「Identity Platform Providers」頁面

  2. 按一下「新增供應商」

  3. 從供應商清單中選取「Google」Google

  4. 設定 Web Client IDWeb Client Secret

    1. 在 Google Cloud 控制台中,前往「Credentials」頁面。

      前往「憑證」

    2. 使用現有的 OAuth 2.0 用戶端或建立新用戶端。將 Client IDClient secret 設為「Web Client ID」和「Web Client Secret」。將 LOGIN_URL/__/auth/handler 新增為 OAuth 2.0 用戶端的其中一個已授權的重新導向 URI。LOGIN_URL 是 IAP 在選取「Create a sign-in page for me」(建立登入頁面) 選項後建立的登入網址您可以前往 Google Cloud 控制台的 IAP 頁面,選取受 IAP 保護的資源,即可找到這項資訊。

  5. 在兩個頁面上按一下「儲存」

登入管理面板

LOGIN_URL/admin 面板中,由 Cloud Run 代管的登入頁面 JSON 設定。下列步驟說明如何存取面板。請注意,您必須具備「儲存空間管理員」(roles/storage.admin) 角色。

  1. 前往 Google Cloud 控制台的「IAP」頁面。

    前往 IAP 頁面

  2. 從清單中選取所需資源。

  3. 在資訊面板中,點選「自訂頁面」下方列出的網址。它看起來應該像 https://servicename-xyz-uc.a.run.app/admin

  4. 使用設定應用程式內購時所用的 Google 帳戶登入。畫面上會顯示包含 JSON 設定檔的文字編輯器。

修改設定

登入頁面的設定結構定義以 FirebaseUI 為基礎,並繼承其許多屬性。您可以改用 PROJECT_ID.firebaseapp.com,而非使用 IAP 建立的 LOGIN_URL 做為預設的 authDomain。

如果您想使用 PROJECT_ID.firebaseapp.com 做為 authDomain,請將 signInFlow 變更為 popup,以避免在主要瀏覽器上發生第三方儲存空間存取問題(請參閱「在封鎖第三方儲存空間存取權的瀏覽器上使用 signInWithRedirect 的最佳做法」)。此外,請按照「為 Identity Platform 供應商設定已授權的重新導向 URI 」中的指示,將 PROJECT_ID.firebaseapp.com/__/auth/handler 新增為 Identity Platform 供應商的其中一個已授權的重新導向 URI 或 ACS 網址,供使用者登入。

以下程式碼為含有三個租用戶的設定範例:

{
  "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",
        "signInFlow": "popup",
        "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,
        "signInFlow": "popup",
        "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,
        "signInFlow": "popup",
        "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 執行個體。情境範例包括:

  • 新增、修改或移除身分識別資訊提供者
  • 修改租用戶設定
  • 設定環境變數
  • 將容器映像檔更新為最新版本

定期更新及重新部署容器映像檔,可確保您取得最新的錯誤修正和安全性修補程式。您可以在 GitHub 上查看各版本之間的變更清單。

您可以使用 /versionz 端點取得已部署容器的目前版本。例如:

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

如要重新部署 Cloud Run 執行個體,請按照下列步驟操作:

  1. 前往 Google Cloud 控制台的「Cloud Run」頁面。

    前往 Cloud Run 頁面

  2. 選取代管登入頁面的執行個體。

  3. 按一下「Edit & Deploy New Revision」

  4. 您可以視需要為修訂版本指定進階設定,或是按一下「變數與密鑰」分頁標籤來新增環境變數。

  5. 按一下 [Deploy] (部署)

進階選項

以程式設計方式自訂登入頁面

除了使用 /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 範圍,且必須在 Authorization 標頭中附加有效的 OAuth 權杖。

設定環境變數

您可以在 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 資源。這麼做可減少管理多個設定的相關工作。

如要重複使用登入頁面,請按照下列步驟操作:

  1. 請按照本文的步驟,為 IAP 保護的第一個資源部署驗證頁面。

  2. 為第二個資源啟用 IAP。系統提示您指定登入頁面時,請選取「I'll provide my own」,然後輸入 Cloud Run 服務的網址做為「網址」

  3. 重新部署 Cloud Run 服務。

疑難排解

瀏覽器中的第三方 Cookie 和儲存空間分區

如果瀏覽器停用第三方 Cookie 或實作儲存空間分割,登入頁面或管理頁面可能無法正常運作。如要解決這個問題,請按照下列步驟操作:

  1. 重新部署登入頁面,以便使用最新的 1.0.1 版。

  2. 如果您使用「自訂登入頁面」功能,請務必將 authDomain 設為 IAP 建立的 LOGIN_URL。或者,如果 signInFlow 設為 popup,您可以將 authDomain 設為 PROJECT_ID.firebaseapp.com

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

    {
      "AIzaSyC5DtmRUR...": {
        "authDomain": "PROJECT_ID.firebaseapp.com",
        "tenants": {
          "tenant-a-id": {
            ...
            "signInFlow": "popup"
            ...
          }
        }
        ...
      }
    }
    

後續步驟