📝

Cognito へのサインアップで地域制限してみた

に公開

サインアップ前の Lambda トリガー - Amazon Cognito
サインアップ前の Lambda トリガーで地域制限を実装してみました。

1. Cognito ユーザープールの作成

以下の設定で作成しました。

  • アプリケーション: 従来のウェブアプリケーション
  • サインイン識別子のオプション: メールアドレス

上記以外はデフォルト設定で作成しました。

2. アプリケーションクライアントの再作成

[小ネタ] Cognito ユーザープールのアプリケーションクライアントでシークレットを生成しない方法
手順 1 が完了した時点でアプリケーションクライアントが自動的に作成されますが、今回はクライアントシークレットを使用しません。
そのため、クライアントシークレットを使用しないクライアントを明示的に作成します。

$ aws cognito-idp create-user-pool-client \
--user-pool-id your-userpool-id \
--client-name test \
--no-generate-secret \
--explicit-auth-flows "ALLOW_REFRESH_TOKEN_AUTH" "ALLOW_USER_SRP_AUTH" "ALLOW_USER_AUTH" "ALLOW_USER_PASSWORD_AUTH"

3. Lambda 関数の作成

以下の設定で作成しました。

  • ランタイム: Python 3.13
  • 実行ロール: AdministratorAccess 権限を付与
  • コード: 以下の通り
import json

def lambda_handler(event, context):
    print("Pre Sign-up trigger invoked")
    print(f"Event: {json.dumps(event)}")
    
    # clientMetadataからAccept-Languageヘッダーを取得
    client_metadata = event['request'].get('clientMetadata', {})
    accept_language = client_metadata.get('Accept-Language', '')
    
    print(f"Accept-Language: {accept_language}")
    
    # 許可する言語/地域設定
    allowed_languages = [
        'ja',     # 日本語
        'ja-JP',  # 日本語-日本
        'ja-jp'   # 小文字バリエーション
    ]
    
    # Accept-Languageに日本語が含まれているかチェック
    is_allowed = any(lang in accept_language.lower() for lang in allowed_languages)
    
    if not is_allowed:
        print(f"Access denied for language: {accept_language}")
        # サインアップを拒否
        raise Exception("お住まいの地域からのサインアップは現在サポートされていません")
    
    print(f"Access allowed for language: {accept_language}")
    # サインアップを許可
    return event

4. Lambda トリガーの追加

手順 1 で作成したユーザープールに手順 3 で作成した Lambda をトリガーとして追加します。
トリガーの種類は「サインアップ前 Lambda トリガー」です。

5. html ファイルの作成

サインアップのテストのためにローカル環境に以下の html ファイルを作成します。
以下の項目は環境に合わせて変更してください。

  • AWS.config.region: 今回は ap-northeast-1 を指定
  • UserPoolId: 手順 1 で作成したユーザープールの ID
  • ClientId: 手順 2 で作成したクライアント ID
index.html
<!DOCTYPE html>
<html>
<head>
    <title>地域制限テスト</title>
    <script src="https://sdk.amazonaws.com/js/aws-sdk-2.1.24.min.js"></script>
    <script src="https://sdk.amazonaws.com/js/aws-sdk-2.1.24.min.js"></script>
    <script src="https://unpkg.com/amazon-cognito-identity-js@6.3.12/dist/amazon-cognito-identity.min.js"></script>
</head>
<body>
    <h1>Cognito 地域制限テスト</h1>
    
    <div>
        <h3>サインアップ</h3>
        <input type="email" id="email" placeholder="メールアドレス">
        <input type="password" id="password" placeholder="パスワード">
        <button onclick="signUp()">サインアップ</button>
    </div>
    
    <div id="result"></div>

    <script>
        console.log("ページが読み込まれました");
        // Cognito設定
        AWS.config.region = 'ap-northeast-1';
        var poolData = {
            UserPoolId: 'your-user-pool-id',
            ClientId: 'your-client-id'
        };

        var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);

        function signUp() {
            var email = document.getElementById('email').value;
            var password = document.getElementById('password').value;
            
            if (!email || !password) {
                document.getElementById('result').innerHTML = '<p style="color: red;">メールアドレスとパスワードを入力してください</p>';
                return;
            }
            
            // Accept-Languageヘッダーを取得
            var acceptLanguage = navigator.language || navigator.userLanguage || 'en-US';
            
            var attributeList = [];
            var dataEmail = {
                Name: 'email',
                Value: email
            };
            var attributeEmail = new AmazonCognitoIdentity.CognitoUserAttribute(dataEmail);
            attributeList.push(attributeEmail);
            
            // clientMetadataにAccept-Languageを設定
            var clientMetadata = {
                'Accept-Language': acceptLanguage
            };
            
            userPool.signUp(email, password, attributeList, null, function(err, result) {
                if (err) {
                    document.getElementById('result').innerHTML = '<p style="color: red;">エラー: ' + err.message + '</p>';
                    return;
                }
                document.getElementById('result').innerHTML = '<p style="color: green;">サインアップ成功!確認メールをチェックしてください。</p>';
            }, clientMetadata);
        }

        console.log("現在の言語設定:", navigator.language);
    </script>
</body>
</html>

6. 動作確認

手順 5 で作成した html ファイルをブラウザで開き、メールアドレスとパスワードを入力してサインアップします。
「サインアップ成功!確認メールをチェックしてください。」と表示されればサインアップ成功です。

ユーザープールにもユーザーが追加されていることを確認できます。

続いて、ブラウザのコンソールを開いて以下のコードを入力し、ブラウザの言語を一時的に英語に設定します。

Object.defineProperty(navigator, 'language', {
  writable: true,
  value: 'en-US'
});
console.log("言語設定を変更:", navigator.language);

上記コード入力後、適当なメールアドレスで再度サインアップすると以下のメッセージが表示されます。

エラー: PreSignUp failed with error お住まいの地域からのサインアップは現在サポートされていません.

ブラウザの言語設定での判別ですが、簡単な地域制限をすることができました。

まとめ

今回は Cognito へのサインアップで地域制限してみました。
どなたかの参考になれば幸いです。

参考資料

Discussion