iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0
Build on AWS

一步步帶你認識 Cloud Native —— 用AWS免費服務打造雲原生專案系列 第 17

Day17. 用 CDK 建立 Cognito 資源 | Amplify 串接 & 聊聊 Secrets Manager

  • 分享至 

  • xImage
  •  

前情回顧

昨天,我們已經手動在 Cognito Console 綁定了 Google IdP(因為需要 Client ID/Secret)。
今天,我們要把 Cognito 的基本架構(User Pool、App Client、Domain) 自動化,用 CDK 來管理,讓專案更有雲原生味道。


用 CDK 建立 Cognito 基本架構

以下是一個最小範例,創建 User Pool + User Pool Client + Domain

python
from aws_cdk import (
    Stack,
    aws_cognito as cognito
)
from constructs import Construct

class CognitoStack(Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # 建立 User Pool
        user_pool = cognito.UserPool(
            self, "MyUserPool",
            user_pool_name="MyCognitoUserPool",
            self_sign_up_enabled=True,
            sign_in_aliases=cognito.SignInAliases(email=True)
        )

        # 建立 User Pool Client
        user_pool_client = cognito.UserPoolClient(
            self, "MyUserPoolClient",
            user_pool=user_pool,
            generate_secret=False,
            auth_flows=cognito.AuthFlow(
                user_password=True,
                user_srp=True
            ),
            o_auth=cognito.OAuthSettings(
                flows=cognito.OAuthFlows(authorization_code_grant=True),
                scopes=[
                    cognito.OAuthScope.OPENID,
                    cognito.OAuthScope.EMAIL,
                    cognito.OAuthScope.PROFILE
                ],
                callback_urls=["http://localhost:3000/"],
                logout_urls=["http://localhost:3000/"]
            )
        )

        # 建立 Cognito Domain (用來產生 Hosted UI 登入頁)
        cognito.UserPoolDomain(
            self, "CognitoDomain",
            user_pool=user_pool,
            cognito_domain=cognito.CognitoDomainOptions(
                domain_prefix="my-demo-app"
            )
        )
        

這樣我們就用 CDK 把 Cognito 的骨架 建立起來了。

--

為什麼 Google OAuth 的部分(IdP) 選擇人工設定?

「既然用 CDK 建立 User Pool,為什麼不把 Google 的 IdP 也寫進 CDK?」

嗯... 關於這個問題,其實主要是關於 Client ID 和 Client Secret 的管理方法不同所導致的選擇

  1. Client Secret 屬於敏感資訊 → 不應該 Hard Code 在 GitHub Repo
  2. 如果要用 CDK 配置,為了能與CI/CD流程整合,勢必要結合 Secrets Manager 來管理,複雜度增加
  3. IdP 並不是會天天更改的設定,通常設定一次就能長期使用

所以這裡我們的策略是:

  • IdP → Console 手動設定
  • Cognito 基本資源 → CDK 自動化

小插曲:AWS Secrets Manager

雖然這次我們沒用 Secrets Manager,但還是可以認識一下他的功能:

  • Secrets Manager 可以安全儲存像 Google OAuth Client ID/Secret 這樣的敏感資訊 (有點像Github Secret,但與 AWS 集成更方便且安全)
  • 之後你可以透過 SDK 去讀取 Secrets,而不需要手動配置或是hardcode

只不過Secret Manager並非持久免費的服務,AWS提供30天試用,30天過後以每個secret每月0.4美金收費(截至撰稿日)

以下是一個簡單的範例

import boto3

def getGoogleOAuthSecret(event, context):
    client = boto3.client("secretsmanager")
    response = client.get_secret_value(SecretId="GoogleOAuthSecret")
    print(response["SecretString"])

Amplify 前端串接 Cognito

有了 Cognito User Pool + Hosted UI,我們在前端可以用 Amplify 很輕鬆地串接。

首先需要安裝

npm install aws-amplify

在使用Amplify串接Cognito時,我們基本上需要做的事情就是兩件
1.初始化Amplify實例,Configure Cognito相關的參數

程式碼如下:

import { Amplify } from 'aws-amplify';

/// 使用 Amplify.configure 來設定 AWS Cognito 的驗證 (Auth) 模組
Amplify.configure({
  Auth: {
    /// Cognito User Pool 所在的區域 (Region)
    region: 'ap-east-1',

    /// User Pool 的唯一識別碼 (在 AWS Cognito 介面可找到)
    userPoolId: 'ap-east-1_xxxxxxxx',

    /// User Pool App Client ID (前端應用程式對應的 Client ID)
    userPoolWebClientId: 'xxxxxxxxxxxxxxxxxxxx',

    /// OAuth 相關設定(主要用於 Hosted UI)
    oauth: {
      /// 你的 Cognito User Pool Domain (必須在 AWS Cognito 或CDK裡先設定)
      domain: 'your-user-pool-domain.auth.ap-east-1.amazoncognito.com',

      /// 指定要求的使用者資料範圍 (scope)
      /// - 'email': 允許存取使用者 email
      /// - 'openid': 基本 OIDC 權杖
      /// - 'profile': 使用者基本資訊 (名字等)
      scope: ['email', 'openid', 'profile'],

      /// 使用者登入成功後,會被導向到的 URL
      /// 一般在本地開發會用 http://localhost:3000/callback
      redirectSignIn: 'http://localhost:3000/callback',

      /// 使用者登出後,會被導向的 URL
      redirectSignOut: 'http://localhost:3000/signout',

      /// 使用的授權流程
      /// - 'code': Authorization Code Grant (安全性較佳,建議使用)
      /// - 'token': Implicit Grant (舊式方法,不建議)
      responseType: 'code',
    },
  },
});


這些值都是在之前的 CDK 或 Console 建置 Cognito 時產生的資源 ID。

接著我們需要實作的是登入流程
如果有跟著昨天的內容,我們大概可以感受到使用者點擊「Google 登入」時,背後的流程是長怎樣

瀏覽器導向 Cognito Hosted UI -> Cognito 與 Google OAuth 交換 code
-> 前端使用 Amplify 交換 code 取得 JWT Token

在 Amplify 中,可以這樣觸發:

import { Auth } from 'aws-amplify';

// 導向 Hosted UI
Auth.federatedSignIn({ provider: 'Google' });

登入成功後,可取得使用者資訊或 Session:

// 取得目前使用者資訊
const user = await Auth.currentAuthenticatedUser();

// 取得 JWT Token
const session = await Auth.currentSession();
const idToken = session.getIdToken().getJwtToken();

這就是前端與 Cognito Hosted UI 的串接核心流程。

結語

原本想要直接在今天藉由 Amplify 直接帶入專案的實作的但結果發現我們系統中需要注意的細節太多可能會一路串到資料庫去,如此一來知識點會太混雜,於是乎就打算將注意力先集中在 AWS 產品的介紹與基礎實作,再來切入實戰級的專案產品的實作內容,這樣的內容應該會比較順暢,請期待專案實作的各位再稍等一下啦 QQ


上一篇
Day16:用 Google 登入你的 App | 從 Google OAuth 到 Cognito Hosted UI (附實作repo)
下一篇
Day18 Cognito + API Gateway + Lambda | 完全Serverless的用戶系統串接 (上)
系列文
一步步帶你認識 Cloud Native —— 用AWS免費服務打造雲原生專案24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
viiccwen
iT邦新手 5 級 ‧ 2025-08-28 09:24:12

期待喔

我要留言

立即登入留言