🎉

AWS Cognitoを使ったサインアップとログイン機能のまとめ

2020/10/24に公開

目次

  • はじめに
  • 環境
  • 前提
  • サインアップ編
  • アクティベーション編
  • サインイン編
  • まとめ
  • 参考

はじめに

今回はAmazon Cognitoを使ってユーザー認証処理を実装していきたいと思います。今まではFirebaseをよく使っていたのですがインフラをAWSで構築する事になったので、色々統一した方が良いのでは?という思いからCognitoを使う事にしました。

環境

  • Laravel7.2
  • CSS(Tailwind)
  • JS(jquery)

前提

※AWS Cognitoのアカウントの作成とLaravelの環境構築は行っている前提です。

サインアップ編

Amazon Cognitoを使用して自分のアプリケーションからサインアップする手順を紹介します。

①JavaScriptからAmazon Cognitoを使用するためのライブラリを用意する

必要なライブラリは以下になります。
wgetコマンドを使って、ダウンロードできます。AWSのSDKはzipでダウンロード出来ます。

Cognito SDK
https://raw.githubusercontent.com/aws/amazon-cognito-identity-js/master/dist/aws-cognito-sdk.min.js
https://raw.githubusercontent.com/aws/amazon-cognito-identity-js/master/dist/amazon-cognito-identity.min.js
http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js
http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn2.js
https://raw.githubusercontent.com/bitwiseshiftleft/sjcl/master/sjcl.js
http://momentjs.com/downloads/moment.js

AWS SDK
https://github.com/aws/aws-sdk-js/releases/download/v2.6.6/browser.zip

②サインアップをするための画面を作る

<!-- 新規登録フォーム -->
<div class="register-form border-solid border border-gray-200 w-8/12 mx-auto mt-16 bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4 flex flex-col">
	<a href="/" class="fit-content m-auto flex text-lg font-semibold tracking-widest text-gray-900 rounded-lg dark-mode:text-white focus:outline-none">
		<img class="h-12" src="/storage/stacklive-logo.png"><span class="text-3xl my-auto mx-0 font-black tracking-normal">StackLive</span>
	</a>
	<ul class="flex mx-auto my-12">
		<li class="list-none text-center mr-2" >
		<a class="border-solid border border-gray-400 text-gray-600 font-bold py-3 px-16 rounded hover:bg-gray-200" href="{{ route('login') }}">ログイン</a>
		</li>
		<li class="list-none text-center">
			<a class="bg-blue-600 hover:opacity-75 text-white font-bold py-3 px-16 rounded" href="{{ route('register') }}">新規登録</a>
        </li>
	</ul>
    <div class="mb-4">
      	<label class="block text-grey-darker text-sm font-bold mb-2" for="username">
      	  ユーザー名
      	</label>
     	<input class="shadow appearance-none border rounded w-full py-2 px-3 text-grey-darker" id="username" type="text" placeholder="ユーザー名">
    </div>
    <div class="mb-4">
      	<label class="block text-grey-darker text-sm font-bold mb-2" for="mailaddress">
      	  メールアドレス
      	</label>
     	<input class="shadow appearance-none border rounded w-full py-2 px-3 text-grey-darker" id="mailaddress" type="text" placeholder="メールアドレス">
    </div>
    <div class="mb-6">
      <label class="block text-grey-darker text-sm font-bold mb-2" for="password">
        パスワード
      </label>
      <input class="shadow appearance-none border border-red rounded w-full py-2 px-3 text-grey-darker mb-3" id="password" type="password" placeholder="******************">
    </div>
    <div class="text-center">
      <button id="user_add_btn" class="bg-blue-600 hover:bg-blue-dark text-white font-bold py-2 px-4 rounded" type="button">
        新規登録
      </button>
    </div>
</div>

上記のHTMLをブラウザで開くと以下の画像のようになります。

③サインアップ処理のJavaScriptを書く

ここで先ほどダウンロードしたライブラリが必要になります。先にヘッダーで読み込んでおいてください。

signup.js
// Amazon Cognito 認証情報プロバイダーを初期化します
AWS.config.region = ''; // リージョンの指定
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
  IdentityPoolId: '',//IDプールのID
});

// Amazon Cognito Userpoolとクライアントアプリの指定
let poolData = {
  UserPoolId: '', //ユーザープールのID
  ClientId: '' //クライアントアプリの設定上のID
};
//ユーザープール+クライアントアプリの情報を格納
let userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var cognitoUser = userPool.getCurrentUser();
console.log(cognitoUser);

// 新規登録
$('#user_add_btn').click(function () {
	//画面上の入力値であるメールアドレス+パスワードを代入する
	username = $("#username").val();
	mailaddress = $("#mailaddress").val();
  	password = $("#password").val();
	//バリデーション
  	if (!username || !password || !mailaddress) {
  	  return false;
  	}
	var attributeList = [];
	// ユーザ属性リストの生成
	var dataName = {
		Name : "name",
		Value : username
	}
	var attributeName = new AmazonCognitoIdentity.CognitoUserAttribute(dataName);
	attributeList.push(attributeName);

  userPool.signUp(mailaddress, password, attributeList, null, function (err, result) {
    if (err) {
      console.log(err);
      message_text = err;
      message_class = "alert-danger";
    } else {
		// 成功した時の処理
        $('.register-form').fadeOut(200, function(){
           $('.activation-form').fadeIn(300);
        });
      cognitoUser = result.user;
    }
  });
});

これだけでサインアップが可能になりました。
新規登録のボタンを押すと実際にアカウントが作成されます。

ただしこの時点ではこのアカウントにサインインする事はできません。
入力されたメールアドレス宛てに送信された確認コードを認証する事によりサインインが可能になります。次はそのアクティベーション処理の実装をしていきたいと思います。

アクティベーション編

サインアップをしたアカウントを使用できるようにするアクティベーションの処理を実装していきます。

まずサインアップ処理でuserPool.signUpが成功したら確認フォームのページに飛ばすなり、表示させるなりしてください。

①アクティベーションフォームの作成

jsのライブラリはサインアップをした時と同じものを使用するので、読み込んでおいてください。

<!-- activationフォーム -->
<div class="activation-form hidden border-solid border border-gray-200 w-8/12 mx-auto mt-16 bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4 flex flex-col">
	<a href="/" class="fit-content m-auto flex text-lg font-semibold tracking-widest text-gray-900 rounded-lg dark-mode:text-white focus:outline-none">
		<img class="h-12" src="/storage/stacklive-logo.png"><span class="text-3xl my-auto mx-0 font-black tracking-normal">StackLive</span>
	</a>
    <div class="mb-4 mt-4">
		<p class="text-gray-600 text-center mb-5">検証コードを記載いただいたメールアドレスに送信しました。<br>確認の上、以下のフォームにご入力くださいませ。</p>
      	<label class="block text-grey-darker text-sm font-bold mb-2" for="mailaddress">
      	  メールアドレス
      	</label>
     	<input class="shadow appearance-none border rounded w-full py-2 px-3 text-grey-darker" id="activationMail" type="text" placeholder="メールアドレス">
    </div>
    <div class="mb-6">
      <label class="block text-grey-darker text-sm font-bold mb-2" for="password">
        検証コード
      </label>
      <input class="shadow appearance-none border border-red rounded w-full py-2 px-3 text-grey-darker mb-3" id="activationCode" type="text" inputmode="numeric" pattern="\d*" placeholder="123456">
    </div>
    <div class="text-center">
      <button id="activation-button" class="bg-blue-600 hover:bg-blue-dark text-white font-bold py-2 px-4 rounded" type="button">
        検証
      </button>
    </div>
</div>

上記のhtmlファイルを読み込むと以下の画像のようなフォームになります。

②アクティベーション処理のJavaScriptを書く

activation.js
// Amazon Cognito 認証情報プロバイダーを初期化します
AWS.config.region = ''; // リージョンの指定
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
  IdentityPoolId: '',//IDプールのID
});

// Amazon Cognito Userpoolとクライアントアプリの指定
let poolData = {
  UserPoolId: '', //ユーザープールのID
  ClientId: '' //クライアントアプリの設定上のID
};
//ユーザープール+クライアントアプリの情報を格納
let userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var cognitoUser = userPool.getCurrentUser();
console.log(cognitoUser);
// 「Activate」ボタン押下時確認
$("#activation-button").click(function(event) {
    activate();
});
var activate = function() {
	var email = $("#activationMail").val();
	var activationCode = $("#activationCode").val();
	// 何か1つでも未入力の項目がある場合、処理を中断
	if (!email | !activationCode) {
	    return false;
	}
	var userData = {
	    Username : email,
	    Pool : userPool
	};
	var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
	// アクティベーション処理
	cognitoUser.confirmRegistration(activationCode, true, function(err, result){
	    if (err) {
	        // アクティベーション失敗の場合、エラーメッセージを画面に表示
	        if (err.message != null) {
	            $("div#message span").empty();
	            $("div#message span").append(err.message);
	        }
	    } else {
			var url = "/login";
     		$('.activation-form').fadeOut(200, function(){
     		   $(location).attr("href", url);
     		});
	        // アクティベーション成功の場合、サインイン画面に遷移
			console.log('成功したよ!!!!!!!');
	    }
	});
}

アクティベーションするには、CognitoUser.confirmRegistration関数を呼び出します。アクティベーションに失敗した場合は変数errとしてエラー情報オブジェクトが渡されてくるので、それをもとに成功/失敗を判断します。

これでアクティベーション処理が終了しました。

検証ボタンを押すとE メール確認済みがfalseからtrueに変わっていることがわかります。
これでこのアカウントにサインインする事が可能になりました。

サインイン編

アクティベーションが終わったアカウントに実際にサインインしてみたいと思います。

①サインインフォームの作成

<div class="login-form border-solid border border-gray-200 w-8/12 mx-auto mt-16 bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4 flex flex-col">
	<a href="/" class="fit-content m-auto flex text-lg font-semibold tracking-widest text-gray-900 rounded-lg dark-mode:text-white focus:outline-none">
		<img class="h-12" src="/storage/stacklive-logo.png"><span class="text-3xl my-auto mx-0 font-black tracking-normal">StackLive</span>
	</a>
	<ul class="flex mx-auto my-12">
		<li class="list-none text-center mr-2" >
			<a class="bg-blue-600 hover:opacity-75 text-white font-bold py-3 px-16 rounded" href="{{ route('login') }}">ログイン</a>
		</li>
		<li class="list-none text-center">
			<a class="border-solid border border-gray-400 text-gray-600 font-bold py-3 px-16 rounded hover:bg-gray-200" href="{{ route('register') }}">新規登録</a>
        </li>
	</ul>
	<form method="POST" action="{{ route('login') }}">
    @csrf
    <div class="mb-4">
      	<label class="block text-grey-darker text-sm font-bold mb-2" for="mailaddress">
      	  メールアドレス
      	</label>
     	<input class="shadow appearance-none border rounded w-full py-2 px-3 text-grey-darker" id="mailaddress" type="text" placeholder="メールアドレス">
    </div>
    <div class="mb-6">
      <label class="block text-grey-darker text-sm font-bold mb-2" for="password">
        パスワード
      </label>
      <input class="shadow appearance-none border border-red rounded w-full py-2 px-3 text-grey-darker mb-3" id="password" type="password" placeholder="******************">
    </div>
    <div class="text-center">
      <button id="login-button" class="bg-blue-600 hover:bg-blue-dark text-white font-bold py-2 px-4 rounded" type="button">
        ログイン
      </button>
      <a class="fit-content m-auto block align-baseline font-bold text-sm text-blue hover:text-blue-darker" href="{{ route('password.request') }}">
		パスワードを忘れたかた
      </a>
    </div>
	</form>
</div>

上記のhtmlファイルを読み込むと以下の画像のようなフォームになります。

②サインイン処理のJavaScriptを書く

signin.js
// Amazon Cognito 認証情報プロバイダーを初期化します
AWS.config.region = ''; // リージョンの指定
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
  IdentityPoolId: '',//IDプールのID
});

// Amazon Cognito Userpoolとクライアントアプリの指定
let poolData = {
  UserPoolId: '', //ユーザープールのID
  ClientId: '' //クライアントアプリの設定上のID
};
//ユーザープール+クライアントアプリの情報を格納
let userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var cognitoUser = userPool.getCurrentUser();
console.log(cognitoUser);
// ログイン処理
$("#login-button").click(function(event){
    //画面上の入力値であるメールアドレス+パスワードを代入する
    event.preventDefault();
    let authenticationData = {
        Username : $('#mailaddress').val(),
        Password : $('#password').val(),
    };
    let authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);

    //2Amazon Cognito Userpoolの指定+クライアントアプリの指定
    let poolData = {
        UserPoolId: 'us-east-1_nWj5TFbJj',//ユーザープール用のID
        ClientId: '1qauif4hgkptkejetvs0gn0u75'//サインイン用アプリID フェデレーションIDのCognito認証に利用したクライアントアプリのID
    };

    let userPool = new  AmazonCognitoIdentity.CognitoUserPool(poolData);
    let userData = {
        Username : $("#mailaddress").val(),
        Pool : userPool
    };

    let cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);
    cognitoUser.authenticateUser(authenticationDetails, {
        onSuccess: function (authresult) {
			var url = "/";
     		$('.login-form').fadeOut(700, function(){
     		   $(location).attr("href", url);
     		});
        },
        onFailure: function(err) {
            alert(err.message);
        },
    });
});

これでサインイン処理が完成しました。
画面で入力されたデータをもとに認証データを作成し、CognitoUser.authenticateUser関数を呼び出してユーザー認証します。

まとめ

いかがだったしょうか。
初めてCognitoを触ったのですが、特につまづく事なく簡単にユーザー認証を実装する事ができました。

次回は入力されたユーザー情報を取得してアプリで使用するのも作りたいと思います。

参考

Discussion