Amazon Cognito による認証2020年4月11日 | |
はじめにAmazon Cognito を用いると、ユーザー認証画面を作ることができる。 ユーザープールと ID プールCognito ではユーザープールと ID プールというものを管理する。ユーザープールはユーザーを管理したり認証を行ったりするものである。ID プールは、Cognito のユーザープールだけでなく Google など一般的な認証サービスを提供するもの (認証プロバイダー) の認証情報に基づいて権限を与える。ID プールでは認証が通った時のロールを指定できるので、認証が通った時にだけ AWS SDK に必要なサービスへの権限を与えるということができる。 ユーザープールを作成するここではユーザーは管理側で作成するものとし、ユーザーには e-mail アドレスなどを要求しないものとする。
※ちなみに、属性で email を有効にして自己サインアップを許可すると、e-mail アドレスを用いてユーザー自身でユーザー登録を行うことができる。
ここではローカルの http サーバーでテストすることにする。"コールバック URL" と "サインアウト URL" を "http://localhost:8000" と設定する。Python でサーバーを立てる (コマンドプロンプトで実行)。 >python -m http.server ブラウザで "http://localhost:8000" にアクセスしてディレクトリの内容が表示されれば OK。 ログイン画面へのアクセスログイン画面にアクセスできるか確認する。ログイン画面の URL は次のようになる。 https://(プレフィックス).auth.(リージョン).amazoncognito.com/login?response_type=token&client_id=(アプリクライアント ID)&redirect_uri=(コールバック URL) 東京リージョンの場合はリージョンのところを "ap-northeast-1" とする。 コールバック URL は [アプリクライアントの設定] で設定したものと同じものである。とりあえずログイン画面が出てくれば OK。
ログアウトは次の URL にアクセスする (リージョンが東京の場合)。 https://(プレフィックス).auth.(リージョン).amazoncognito.com/logout?client_id=(アプリクライアント ID)&logout_uri=(コールバック URL) ID プールの作成
// Amazon Cognito 認証情報プロバイダーを初期化します
AWS.config.region = '(リージョン)';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: '(ID プール ID)',
});
ロールの設定IAM を開き、ID プールの作成時に作成された "認証されたロール" に必要な権限を設定する。たとえば、認証されたら S3 のデータが見えるようにするなど。 認証情報による権限の取得Web ページにおいて、AWS SDK for JavaScript について認証が通った場合の権限を取得するには、以下ようにする。 Cognit のログイン画面で認証を通過し、"コールバック URL" に設定したページに移動すると、URL の後ろに "#..." の形でパラメータ (ID トークン) がくっついている。それを URLSearchParams で取り出して AWS SDK に渡す。
const idToken = (() => {
const params = new URLSearchParams(location.hash.slice(1));
return params.get("id_token");
})();
// Initialize the Amazon Cognito credentials provider
AWS.config.region = "(リージョン)";
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: "(ID プール ID)",
Logins: {
["cognito-idp.(リージョン).amazonaws.com/(ユーザープール ID)']: idToken,
}
});
これにより "認証されたロール" が適用されるので、たとえば S3 へのアクセス権を与えているなら、S3 の API が使えるようになる。 ログイン画面の URL は長くて使いにくいが、直接 Web ページにアクセスしたときに、認証トークンがなかったらログイン画面にリダイレクトするなどすればよい。
if (idToken === "") {
location.href = "(ログイン画面の URL)";
}
認証の成否認証の成否は、アクセスキー ID などが取得できているかどうかで確認できる。
AWS.config.credentials.get(function() {
const secretAccessKey = AWS.config.credentials.secretAccessKey;
if (secretAccessKey === undefined) {
location.href = "(ログイン画面の URL)";
}
});
ユーザー名の取得ID トークンは JWT (JSON Web Token) であり、Base64 の文字列が '.' で区切られている。これをデコードすればユーザー名を取り出せる。
const username = (() => {
const tokens = idToken.split('.');
const obj = JSON.parse(atob(tokens[1]));
return obj['cognito:username'];
})();
ログインスクリプト以上の情報を以下のようなスクリプトにまとめておくとよい。 login.js
const awsRegion = 'ap-northeast-1';
const bucketName = '(バケット名)';
const domainPrefix = bucketName;
const cognitoUserPoolId = '(ユーザープール ID)';
const cognitoAppClientId = '(アプリクライアント ID)';
const cognitoIdentityPoolId = '(ID プール ID)';
//const thisUrl = "http://localhost:8000/index.html"; // for test
const thisUrl = `https://${bucketName}.s3-${awsRegion}.amazonaws.com/index.html`;
const cognitoDomainUrl = `https://${domainPrefix}.auth.${awsRegion}.amazoncognito.com`;
const cognitoLoginUrl = `${cognitoDomainUrl}/login?response_type=token&client_id=${cognitoAppClientId}&redirect_uri=${thisUrl}`;
const cognitoLogoutUrl = `https://${domainPrefix}.auth.${awsRegion}.amazoncognito.com/logout?client_id=${cognitoAppClientId}&logout_uri=${thisUrl}`;
const logout = () => {
location.href = cognitoLogoutUrl;
}
const idToken = (() => {
const params = new URLSearchParams(location.hash.slice(1));
return params.get("id_token");
})();
let username = '';
if (idToken === null) {
location.href = cognitoLoginUrl;
}
// Initialize the Amazon Cognito credentials provider
AWS.config.region = awsRegion;
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: cognitoIdentityPoolId,
Logins: {
[`cognito-idp.${awsRegion}.amazonaws.com/${cognitoUserPoolId}`]: idToken,
}
});
AWS.config.credentials.get(function() {
const secretAccessKey = AWS.config.credentials.secretAccessKey;
if (secretAccessKey === undefined) {
location.href = cognitoLoginUrl;
}
});
if (idToken !== null) {
username = (() => {
const tokens = idToken.split('.');
const obj = JSON.parse(atob(tokens[1]));
return obj['cognito:username'];
})();
}
最初の定数を環境に合わせて設定する。本番の Web ページは S3 のバケットに置き、バケット名とドメインプレフィックスは同じとしている。テスト環境では thisUrl を入れ替える (テストではローカル Web サーバーの index.html としている。Cognito ユーザープールのコールバック URL、サインアウト URL をこれに合わせる)。Web ページにおいてこのスクリプトを AWS SDK の読み込みのあとに読み込む。 <script src="https://sdk.amazonaws.com/js/aws-sdk-2.651.0.min.js"></script> <script src="login.js"></script> グループの利用ユーザープールではグループを作成でき、個別にロールを設定できる。グループにユーザーを追加しておけば、認証時にグループ名を得られる。
groups = (() => {
const tokens = idToken.split('.');
const obj = JSON.parse(atob(tokens[1]));
return obj['cognito:groups'];
})();
グループ名は配列で得られる。 グループによるロールの割り振り(2021.10.21 追記) グループによりロールを割り振ったりするには、ID プールで設定を行う。
まず、ロールを作っておく。IAM のロールにおいて、[ロールの作成] で [ウェブ ID] を選んで Cognito 用のロールを作る。 ID プールの編集画面で、"認証されたロールの選択" で "ルールを使用してロールを選択" を選ぶ。グループでロールを振り分ける場合は、"cognito:groups" に対して "含有" でグループ名を指定し、割り当てたいロール (上で作成したもの) を設定すればよい。 ※テスト上の注意: ちゃんと権限が切り替わっているか確認する際、ブラウザのキャッシュのせいで権限が変わっていないように見えることがあるため、注意が必要。 | |
| PENGUINITIS | |