背景
AWS LambdaでAmazon Cognitoのメールアドレスや電話番号を変更時にフロント側から送られてくるデータを使用して重複チェックをしたい時があって、少しつまづいたのでどうにかできないかということがありました。
変更のタイミングでAmazon Cognito側のLambdaトリガーを使って実装していたのですが、トリガー発火した時のeventの中身には登録されているAmazon Cognitoのユーザープールのデータが取れるので、フロント側から変更したデータは得られていないことが発覚。
API Gatewayをトリガーにしたらデータも取得できるので可能ですが、今回はAmazon Cognito + AWS Lambdaでの実装が必要だということだったので、別の方法が必要でした。
解決方法
今回はフロント側からAmplifyのAuthを使用した方法で変更のデータが送られるので、そのときにClientMetadataを送信することで対応しました。
ただ、状況によってはClientMetadataの使用が非推奨のこともあるので、実装する際は要件などに気をつける必要がありそうです。
実行環境
Python 3.9
実装コード(例)
フロント側(React)
今回はAmazon Cognitoのメールアドレスの属性を変更するので、変更のメールアドレスのデータをAuth.updateUserAttributes
の引数に渡します。
ここでClientMetadata
に該当する第3引数にdata
を渡すことでバックエンド(Lambda)側でデータを使うことができます。
import { Auth } from '@aws-amplify';
import { Authenticator } from '@aws-amplify/ui-react';
function App() {
const changeAttribute = async () => {
const user = await Auth.currentAuthenticatedUser(); // ログインしているユーザーデータ
const data = {'email': 'xxxxxx@example.com'}; // 変更するデータ(今回はメールアドレス)
return await Auth.updateUserAttributes(
user,
data,
data // ClientMetadataの引数
);
return (
<Authenticator>
{({ signOut, user }) => (
<div>
<button onClick={signOut}>Sign Out</button>
<button onClick={changeAttribute}>Change Attribute</button>
</div>
)}
</Authenticator>
);
}
バックエンド側(Python)
バックエンド(Lambda)側では、Amazon CognitoのLambdaトリガーから渡されるevent
内にフロント側から送信されたClientMetadata
をevent['request']['clientMetadata']
で取得できます。
import boto3
def lambda_handler(event, context):
if event['triggerSource'] == 'CustomMessage_UpdateUserAttribute':
try:
if event['request']['clientMetadata'].get('email') is not None:
duplicated_user = cognito_client.list_users(
UserPoolId = event['userPoolId'],
Filter = f"email =\"{ event['request']['clientMetadata']['email'] }\""
)
if len(duplicated_user['Users']) > 0:
raise Exception('このメールアドレスはすでに登録されています。べつのメールアドレスを登録してください。')
return event
except Exception as e:
print(e)
これで、変更したいメールアドレスのユーザーがすでに存在していた場合は、エラーを発生させます。
注意点
AWS SDK for Python(boto3)公式サイトにClientMetadataの使用上の注意が書かれています。
表記は英語なので簡単に翻訳して引用します。
ClientMetadataパラメーターを使う場合、Amazon Cognitoは以下のことをしないということに注意してください:
①ClientMetadataの値を保存しません。
また、このデータはCognitoのユーザープールに設定されたLambdaトリガーでのみ使用可能です。②ClientMetadataの値はバリデーションされません。
③ClientMetadataの値は暗号化されません。
そのため、暗号化が必要なデータなどの送信はしないようにしてください。
このような注意点がありますので、上述のように要件などに合わせて使う必要があります。
まとめ
AWSを触り始めてまだ1か月ほどで、ここまで来るのに苦労しました...
解決したかと思いきや、注意点もあったのでなんともいいがたいところです...
もしほかの方法やご指摘がありましたら、コメントにお願いいたします!