前書き
ユーザ認証のCognitoを使って、ユーザ認証を実装してみました。
今回はそのまとめです。
実装したフローは、いろんなサービスでよくある以下のフローです。
- サインアップ
- 認証コードとURLが届く
- URL先の認証コード入力画面でコードを入力する
上記のフローを実装して見たので、まとめます。
実装
Cognitoの設定
まずはじめに、Cognito側でメッセージがコードであることを確認します。
あらかじめ、ユーザープールIDとクライアントIDは控えておきましょう。
コード認証実装
AWS-SDK、およびCognitoを利用するに当たって、以下のライブラリが必要なのでnpmかyarnでインストールします。
# npm
npm install aws-sdk
npm install amazon-cognito-identity-js
# yarn
yarn add aws-sdk
yarn add amazon-cognito-identity-js
2個目は、JavaScript上でCognitoを使いやすくしてくれるライブラリです。
では早速、最初の設定部分と実コード部分を実装していきます。
新規に、util的な扱いとしてcognito.jsを作成します。
長くなるので分けて解説し、最後にまとめて記載します。
初期設定
// src/utils/cognito.js
import AWS from 'aws-sdk';
import {
CognitoUserPool,
CognitoUser
} from 'amazon-cognito-identity-js';
import * as aws from './../config/aws';
AWS.config.region = aws.AWS_REGION;
AWS.config.update({
accessKeyId: aws.AWS_ACCESS_KEY,
secretAccessKey: aws.AWS_SECRET_ACCESS_KEY
});
const poolData = {
UserPoolId: aws.AWS_COGNITO_USER_POOL_ID,
ClientId: aws.AWS_COGNITO_APP_CLIENT_ID
};
const userPool = new CognitoUserPool(poolData);
AWSのクレデンシャルをAWS.config.updateで設定し
poolDataという形で、プールIDとクライアントIDを設定し、CognitoUserPool関数に渡して
ユーザプールを作成します。
初期設定はこれだけです。
1. サインアップ
// Signup
export const signup = (formValue) => {
return new Promise((resolve, reject) => {
const attributeList = [
{
Name: 'email',
Value: formValue.email
}
];
userPool.signUp(formValue.email, formValue.password, attributeList, null, (err) => {
if (err) {
reject(err);
}
resolve();
});
});
};
初期設定で作成したuserPoolのsignUpを利用します。
第1引数にemail、第2引数にパスワードを渡して第3引数にはユーザ属性(基本的にemailだけですかね)の配列を渡します。
第4引数は公式をみても、nullを渡していたのでnullを渡します。
第5引数がコールバックになります。
ちなみに、カスタム属性を利用する場合は、Name部が以下になります。
// firstNameがカスタム属性の場合
{
Name: 'custom:firstName',
Value: formValue.firstName
}
これで、指定したemailにCognitoから認証コードを乗せたメールが届きます。
2. 認証コードとURLが届く
デフォルトでは、認証コードのみが届きます。
コードさえあれば、認証は可能ですが
やはりメールに認証コード入力画面へのURLが欲しいと思います。
ここは、別の記事で細かく解説したいですが、Lambdaの作成が必要になります。
作成するLambdaの中身は以下です。
// LambdaHandler
module.exports.sendVerifyMessage = (event, context, callback) => {
// 指定のUserPoolIdとリクエストのUserPoolIdが同じ
if (event.userPoolId === process.env.USER_POOL_ID) {
// トリガーがカスタムメッセージ
if (event.triggerSource === 'CustomMessage_SignUp') {
// 実処理
// 件名
event.response.emailSubject = "件名";
// 本文
event.response.emailMessage = "本文";
}
}
// Return result to Cognito
context.done(null, event);
};
Cognitoが呼び出した際に、eventの中にサインアップ情報が含まれています。
event.response.emailSubjectに件名をemailMessageに本文を入れて返すことでメールが送信されます。
HTMLメールの利用ができるので、簡単にテンプレートを作成して入れるといいです。
eventから取得できる関連するパラメータは以下の通りです。
// メールアドレス
event.userName
// 認証コード
event.request.codeParameter
// そのほかカスタム属性
event.request.userAttributes['custom:hogehoge']
入力画面で利用するため、URLの最後にemailをパラメータとして渡す必要があります。
作成したLambdaはトリガー設定のカスタムメッセージへ設定します。
URL先の認証コード入力画面でコードを入力する
認証コード入力画面では、基本的に2回の処理が必要です。
- パラメータで飛んで来たemailが正しいメールかどうか
- 認証コードで認証する
それぞれを実装すると以下の形になります。
1. パラメータで飛んで来たemailが正しいメールかどうか
export const checkUser = ((email) => {
return new Promise((resolve, reject) => {
if (!email) {
reject('Reject');
}
const userData = {
Username: email,
Pool: userPool
};
const cognitoUser = new CognitoUser(userData);
if (!cognitoUser) {
reject('Reject');
}
resolve(cognitoUser);
});
});
パラメータで取得したemailとuserPoolを利用してcognitoUserを利用します。
存在しないユーザの場合はrejectされます。
2. 認証コードで認証する
export const activateUser = ((email, code) => {
return new Promise((resolve, reject) => {
const userData = {
Username: email,
Pool: userPool
};
const cognitoUser = new CognitoUser(userData);
cognitoUser.confirmRegistration(code, true, (err) => {
if (err) {
console.log(err);
reject(err);
} else {
// 成功
resolve();
}
});
});
});
cognitoUserのconfirmRegistrationを利用します。
ここでまたuserDataを利用するので、最初のcheckUserで作成したcognitoUserを再利用してもいいかもしれません。
まとめ
ここまでで作成したソースを記載してまとめとします。
import AWS from 'aws-sdk';
import {
CognitoUserPool,
CognitoUser
} from 'amazon-cognito-identity-js';
AWS.config.region = aws.AWS_REGION;
AWS.config.update({
accessKeyId: aws.AWS_ACCESS_KEY,
secretAccessKey: aws.AWS_SECRET_ACCESS_KEY
});
const poolData = {
UserPoolId: aws.AWS_COGNITO_USER_POOL_ID,
ClientId: aws.AWS_COGNITO_APP_CLIENT_ID
};
const userPool = new CognitoUserPool(poolData);
// Signup
export const signup = (formValue) => {
return new Promise((resolve, reject) => {
const attributeList = [
{
Name: 'email',
Value: formValue.email
}
];
userPool.signUp(formValue.email, formValue.password, attributeList, null, (err) => {
if (err) {
reject(err);
}
resolve();
});
});
};
// User Check
export const checkUser = ((email) => {
return new Promise((resolve, reject) => {
if (!email) {
reject('Reject');
}
const userData = {
Username: email,
Pool: userPool
};
const cognitoUser = new CognitoUser(userData);
if (!cognitoUser) {
reject('Reject');
}
resolve(cognitoUser);
});
});
// Code Activate
export const activateUser = ((cognitoUser, code) => {
return new Promise((resolve, reject) => {
cognitoUser.confirmRegistration(code, true, (err) => {
if (err) {
console.log(err);
reject(err);
} else {
// 成功
resolve();
}
});
});
});
後書き
早口な説明になりましたが、
AWSのSDKがなかなか充実しているので、思ったフローが簡単に実装できました。
サービスのユーザの認証は、
ユーザがサービスの印象を感じる部分でもあるので、しっかり実装していきたいですね。