はじめに
今回はAWSドキュメントを見ながらAmazon Cognitoを触ってみました。
SAP勉強中で、GWで時間もできたことなので実際に手を動かしてディープに理解していきます。
Amazon Cognitoとは
- アプリにユーザ認証機能を提供するサービス。
- モバイルアプリやWebアプリに、ユーザーのサインイン・認証機能・ユーザー管理機能を簡単に実装できる。
コンポーネント
Amazon Cognitoには2つのコンポーネントが存在する。
2つの違いが初見だと理解に苦しみましたが、誰にどんな認証/認可機能を提供するかを整理して考えるとスッキリしました。
1.ユーザープール(認証処理)
- ユーザープールは、Amazon Cognito のユーザーディレクトリ
- ユーザーはモバイルアプリ・Webアプリに、Cognito経由でサインインしたり、サードパーティ(Twitter,Google,Facebookなど)経由でユーザ認証が可能
- MFA(多要素認証)、Eメールや電話番号による検証が可能
- 正常に認証されるとCognitがユーザーに対してJWTトークンを発行する
2.IDプール(認可処理)
- ユーザーに一意のIDを発行して、IDプロバイダーでフェデレートすることが可能。
- IDプールを使用すると、一時的なAWS認証情報を取得して、様々なAWSサービスにアクセスすることができる。
- 以下のIDプロバイダーをサポートしている
- パブリックプロバイダー(Amazon,Facebook,Google,Apple)
- Cognitoユーザープール
- Open ID Connect
- SAML ID
- 開発者が認証したアイデンティティ
ハンズオン
今回は簡易的なログインページを作成してみました。
今回はCognitoの動作確認が目的なので、デザインのこだわりは無いのと、フレームワークなしのHTML、JavaScriptを使って実装しました。
実装はこちらを参考にしました。(とてもわかりやすかったです。。)
ハンズオンのフローとしては、
メールアドレスとパスワードを使ってログイン->Eメールに認証情報が届く->認証情報を入力->ログイン成功することを確認したいと思います。
Cognitoのユーザープールの作成
-
AWSコンソールにログイン>サービス>Cognitoを選択
-
右側の「ビジネスケースから始める」でアプリケーションにユーザーディレクトリを作成する。を選択する。(2023年5月現在の画面)
「ユーザープールを作成」を選択する。
-
パスワードポリシーは特にこだわりがないので、デフォルトのままにします。
アプリによってパスワードポリシーが異なればカスタム設定ができるということですね。
-
MFA(多要素認証)は「なし」で設定します。
サインインで、二段階認証としてSMS認証や認証アプリなど設定することができそうです。
-
セルフサービスのサインアップはデフォルトで自己登録を有効化してます。
無効化すると、sign-upリクエストが拒否されるとか、、
-
できるだけCognitoにお任せしたいので、Cognitoアシスト型は許可してます。
検証属性はEメールの検証なので、Eメールを設定してます。
-
Eメールの送信方法を指定します。
今回はCognitoを選びました。1日最大50通のメール送信ができるとの記載があるので、検証には十分です。
-
ユーザープール名を設定します。(プール名いつ設定するのかな?と思ったらここで出てきて安心しました。)
OAuth2.0を使用しないので、ホストされた認証ページは無効化としてます。
ここまででユーザープールの作成は完了ですが、
最後に「ユーザープールID」の値が必要になるのでメモしておきます。
アプリケーションクライアントの「クライアントID」も後ほど必要になりますのでこれもメモします。
CognitoのIDプールの作成
-IDプール名を設定します。(入力後、緑のチェックマークが表示されればOK)
認証プロバイダーを「Cognito」を選択し、先ほどメモしたIDを入力して「プールの作成」を選択します。
これでIDプールの作成は完了ですが、
AWS認証情報の取得を後ほど使用するので、こちらもメモを取っておきます。
サインイン画面の実装
3つの画面を用意します。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</meta>
<title>CognitoSignUp</title>
<script src="js/aws-cognito-sdk.min.js"></script>
<script src="js/amazon-cognito-identity.min.js"></script>
<script src="js/main.js"></script>
</head>
<body>
<h1>KitonSite サインイン画面</h1>
<span style="display: inline-block; width: 100px;">Email</span>
<input type="text" id="email" placeholder=" メールアドレス">
<br />
<span style="display: inline-block; width: 100px;">Password</span>
<input type="password" id="password" placeholder="パスワード">
<br />
<input type="button" value="サインアップ" onclick="SignUp();">
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</meta>
<title>CognitoConfirmRegistration</title>
<script src="js/aws-cognito-sdk.min.js"></script>
<script src="js/amazon-cognito-identity.min.js"></script>
<script src="js/main.js"></script>
</head>
<body>
<h1>KitonSite 認証画面</h1>
<p>入力したメールアドレスに認証コードを送付しました。</p>
<p>メールアドレスと認証コードを入力してください。</p>
<span style="display: inline-block; width: 100px;">Email</span>
<input type="text" id="email" placeholder="メールアドレス">
<br />
<span style="display: inline-block; width: 100px;">ConfirmCode</span>
<input type="text" id="ConfirmCode" placeholder="認証コード">
<br /><br />
<input type="button" value="認証" onclick="ConfirmRegistration();">
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</meta>
<title>CognitoAuthenticateUser</title>
<script src="js/aws-sdk.min.js"></script>
<script src="js/aws-cognito-sdk.min.js"></script>
<script src="js/amazon-cognito-identity.min.js"></script>
<script src="js/main.js"></script>
</head>
<body>
<h1>KitonSite ログイン画面</h1>
<span style="display: inline-block; width: 100px;">Email</span>
<input type="text" id="email" placeholder="メールアドレス">
<br />
<span style="display: inline-block; width: 100px;">Password</span>
<input type="password" id="password" placeholder="パスワード">
<br /><br />
<input type="button" value="ログイン" onclick="LoginUser();">
</body>
</html>
- Javascriptは1つのファイルにまとめて書きました。(リファクタリングできてません。。)
const poolData = {
UserPoolId: 'us-east-1_xxxxxx', // ユーザープール固有のID(メモした値)
ClientId: 'xxxxyyyyzzzz', // クライアント固有のID(メモした値)
};
// signup.html
function SignUp() {
var username = document.getElementById("email").value;
var password = document.getElementById("password").value;
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
userPool.signUp(username, password, null, null, function(
err,
result
) {
if (err) {
alert(err.message || JSON.stringify(err));
return;
}
var cognitoUser = result.user;
console.log('user name is ' + cognitoUser.getUsername());
window.location.href = 'confirm.html';
});
}
// confirm.html
function ConfirmRegistration() {
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var username = document.getElementById("email").value;
var code = document.getElementById("ConfirmCode").value;
var userData = {
Username: username,
Pool: userPool,
};
var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
cognitoUser.confirmRegistration(code, true, function(err, result) {
if (err) {
alert(err.message || JSON.stringify(err));
return;
}
console.log('call result: ' + result);
window.location.href = 'login.html';
});
}
// login.html
function LoginUser() {
var username = document.getElementById("email").value;
var password = document.getElementById("password").value;
var authenticationData = {
Username: username,
Password: password,
};
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(
authenticationData
);
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var userData = {
Username: username,
Pool: userPool,
};
var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function(result) {
var idToken = result.getIdToken().getJwtToken(); // IDトークン
var accessToken = result.getAccessToken().getJwtToken(); // アクセストークン
var refreshToken = result.getRefreshToken().getToken(); // 更新トークン
console.log("idToken : " + idToken);
console.log("accessToken : " + accessToken);
console.log("refreshToken : " + refreshToken);
AWS.config.region = 'us-east-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:xxxx-yyyy-zzzz', // IDプールの値(メモした値)
Logins: {
// Change the key below according to the specific region your user pool is in.
'cognito-idp.us-east-1.amazonaws.com/us-east-1_xxxxxx': result
.getIdToken()
.getJwtToken(),
},
});
AWS.config.credentials.refresh(error => {
if (error) {
console.error(error);
} else {
console.log('Successfully logged!');
}
});
},
onFailure: function(err) {
alert(err.message || JSON.stringify(err));
},
});
}
動作確認
最後に
とっても長くなりましたが、今回はCognitoのハンズオンを実践してみました。
実際に手を動かしてみた感想としては、ユーザプールの設定に少し時間がかかりましたが、細かな設定ができるので様々な要件にも対応できそうだなと感じました。
ただ、気になることも多々あるので、SAP勉強が落ち着いたらもっと検証してみたいですね!!
例えば、
- ユーザー認証を自前で実装しているアプリケーションをCognitoに移行可能かどうか
- signupしたユーザが事前に設定したグループに自動的に振り分けられるかどうか
- サードパーティ経由でユーザー認証
- 他のAWSサービスとの連携(API Gateway,Amplify,Lambdaなど、、、)
参考サイト