LoginSignup
57
44

More than 5 years have passed since last update.

JavaScriptで、Cognitoコード認証フローを実装したまとめ

Last updated at Posted at 2017-10-18

前書き

ユーザ認証のCognitoを使って、ユーザ認証を実装してみました。
今回はそのまとめです。
実装したフローは、いろんなサービスでよくある以下のフローです。

  1. サインアップ
  2. 認証コードとURLが届く
  3. URL先の認証コード入力画面でコードを入力する

上記のフローを実装して見たので、まとめます。

実装

Cognitoの設定

まずはじめに、Cognito側でメッセージがコードであることを確認します。
スクリーンショット 2017-10-18 23.37.09.png

あらかじめ、ユーザープール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を使いやすくしてくれるライブラリです。

Github

では早速、最初の設定部分と実コード部分を実装していきます。
新規に、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はトリガー設定のカスタムメッセージへ設定します。

スクリーンショット 2017-10-19 0.32.41.png

URL先の認証コード入力画面でコードを入力する

認証コード入力画面では、基本的に2回の処理が必要です。

  1. パラメータで飛んで来たemailが正しいメールかどうか
  2. 認証コードで認証する

それぞれを実装すると以下の形になります。

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がなかなか充実しているので、思ったフローが簡単に実装できました。
サービスのユーザの認証は、
ユーザがサービスの印象を感じる部分でもあるので、しっかり実装していきたいですね。

57
44
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57
44