#はじめに
こんにちは!この記事は「 [AWS Amplify Advent Calendar 2021] (https://qiita.com/advent-calendar/2021/amplify) 」7日目の記事です。
私は大学を1年間休学してtoB向けアプリ開発をしているスタートアップで長期エンジニアインターンをしております。
Amplifyを用いる中で、ユーザーの招待機能を実装したので、その方法について共有させていただきたいと思います!
一つの実装例として、どなたかのご参考になればと思います
[注意] 今回はフロントエンド部分の実装には触れず、バックエンドの実装のご紹介のみとさせていただきます。
#要件
実装に当たって下記要件を満たす必要がありました。
- 招待したいユーザーのメールアドレス宛に招待メールが送信できること
- 一度招待したユーザーのメールアドレス宛に招待メールが再送できること
- 招待時に送信するメールと通常のユーザーサインアップ時に送信するメールを動的に使い分ける
- 招待するユーザーのcognitoのユーザー名は一意であること
#実際に作ってみる
ユーザーの招待(作成)にはcognitoのsdkのAdminCreateUserCommandを用いていきます。
##1.cognitoのsdkを実行するLambdaを作成する
今回は、cognitoのsdkのAdminCreateUserCommandをLambdaで実行していきたいと思います。
amplify CLIでLambdaを作成します。
amplify add function
要件にも記述した通り、「1度招待(作成)したユーザーのメールアドレス宛にメールを再送できること」が条件だったため、そちらを考慮した作りにしました。
また、「招待するユーザーのcognitoのユーザー名は一意であること」という要件を達成するために、また、招待時に作成するユーザー名はuuidv4を用いてランダムな文字列を作成することで対応しました。
「ユーザー名をランダムな文字列に設定してサインインの際に困らないの?」と思われるかもしれませんが、cognitoのユーザープール作成時に属性にてエンドユーザーがEmailと任意のユーザー名のどちらのサインインにも対応できるようにしてあるので問題ありません。
/**
* 既にユーザーが存在している場合メールを再送
*/
const resendEmail = async (
client: CognitoIdentityProviderClient,
userPoolID: string,
username: string,
): Promise<void> => {
const resendEmailParams = {
UserPoolId: userPoolID,
DesiredDeliveryMediums: ["EMAIL"],
Username: username,
//メールの再送を設定
MessageAction: "RESEND",
};
await client.send(new AdminCreateUserCommand(resendEmailParams));
};
//中略
/**
* ユーザーを作成する
*
* 同じ username が存在する場合にはメールを再送する
*/
export const createUser = async (
client: CognitoIdentityProviderClient,
userPoolID: string,
params: HandlerArgument["arguments"]
): Promise<void> => {
try {
//一度ユーザーが作成されている前提でメールの再送を試みる
await resendEmail(
cognito,
userPoolID,
username,
firstName,
lastName
);
} catch (e) {
// 同一ユーザーが存在しないため、エラーを握りつぶしてユーザーを新規作成
}
const createUserParams = {
UserPoolId: userPoolID,
DesiredDeliveryMediums: ["EMAIL"],
Username: username,
UserAttributes: [
{
Name: "email",
Value: email,
},
{
Name: "email_verified",
Value: "true",
},
],
};
await client.send(new AdminCreateUserCommand(createUserParams));
##2.作成したLambdaをクライアントから呼び出す
GraphQL API経由で先ほど作成したLambda関数をクライアントから呼び出します。
schemaの type Mutation
にて下記のように記述します。
type Mutation
{
inviteUser(
username: String!
email: String!
group: String!
):inviteUserResponse
@function(name: "inviteUser-${env}")
@auth(rules: [
{allow: private, provider: userPools},
])
//省略
])
}
次に適切な権限設定を行ったAppSyncClientを用いて下記でLambdaを呼び出します。
const client = new AppsyncClient({
//適切な権限設定を行う
url: "",
region:""
//etc...
});
await client.mutate({
mutation: gql(inviteUser),
variables: variable,
})
3.Cognitoから送信するメールを動的にカスタマイズ
さて、残すところは「招待時に送信するメールと通常のユーザーサインアップ時に送信するメールを動的に使い分ける」という要件のみです。こちらは、カスタムメッセージのLambdaトリガーを使用して対応しました。
こちらのLambdaもAmplify CLIから追加することができます。
amplify update auth
Lambdaトリガーの中身はこちらになります。
eventとしてCognitoからLambdaへ受け取ったtriggerSource値に応じて動的に送信する内容を変えます。
triggerSourceがCustomMessage_AdminCreateUser
の際に招待ユーザー用のサインアップ画面のURL添付することで、招待を受けたユーザーがそのリンクからサインアップを完了させます。
switch (event.triggerSource) {
case "CustomMessage_SignUp":
event.response.emailMessage = //サインアップ時のメッセージ
break;
case "CustomMessage_AdminCreateUser":
event.response.emailMessage = //招待時のメッセージ&招待ユーザー用のサインアップ画面のURLを貼る
break;
case "CustomMessage_ForgotPassword":
event.response.emailMessage = //パスワード忘れに対応したメッセージ
break;
//省略
}
return event;
これですべての要件を満たした招待機能が実装できました。
#おわりに
今回はフロントエンドについては触れず、バックエンド部分の実装方法についてご紹介させていただきました!
このやり方以外にも、招待機能を実装する方法はいろいろあると思います。
Amplify含めたAWSのサービスについて、まだまだ勉強中の身なので「ここはこうした方が良い」といったアドバイスいただけるととてもありがたいです!