AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する
AWS Cognitoでは認証画面は提供していません。(でも提供していたらどなたか教えてください)
認証画面を自作します。ちょっと凝ったことをしたいのでCloudFrontで配信し、S3にWebコンテンツを配置します。
使用するサービスは、ACM,CroudFront,Route53,Cognito,S3,APIGatewayです。
上記の記事で独自ドメイン + SSL化が完了したら、Cognitoでユーザープールを作成してください。
S3にWebコンテンツを置いてCloudFrontで配信する
Webコンテンツを配置するS3のバケットを作成します。
適当に「web」というバケットを作成してみます。すると「バケット名はすでに存在しています」と怒られます。
どうもバケット名はそのリージョン内ではなく全世界でユニークでないといけないようです。
バケット名なんて何でも良いので適当に命名して作成します。
CloudFrontで配信するので、S3のウェブサイトのホスティングは無効にしておいてください。
今回の大事な要件として、「複数オリジンを一つのドメインで管理する」という要件があります。その一つであるS3のフォルダ構成を以下のようにします。
login │ ├index.html ├index.js ├mypage.html ├mypage.js ├style.css ├─js ├─amazon-cognito-identity.js ├─aws-cognito-sdk.js
このバケットにindex.htmlなどのWebコンテンツを配置します。
API Gatewayを作成してデプロイする
まず認可の為にオーソライザーを作成します。
名前は任意です。タイプは「Cognito」、Cognitoユーザープールは先に作成しておいたユーザープールを選択します。
トークンのソースは「Authorization」固定です。トークンの検証は空白で「作成」を押します。
これで、オーソライザーの作成は完了です。
次に、サインインした後にjQueryで実行したいAPI Gatewayを作成します。ここでは「test」として作成します。
認証は別記事で書いたCognitoの設定で作成した認可を指定してください。ここでは「cognito1」という名前の認可になります。LambdaはJSONを返しているだけです。
「アクション」ー「APIのデプロイ」を実行します。この際のhttpsから始まるURLをメモしておいてください。ステージは「test」にしました。
一応Lambdaのソースです。JSONを返します。
exports.handler = (event, context, callback) => { // TODO implement callback(null, {"name": 'takahashi'}); };
CloudFrontを設定する
CloudFrontはグローバルなのでリージョンは関係ありません。「Create Distribution」をクリックします。
Webの「Get Started」をクリックします。
「Origin Domain Name」にカーソルを当てると先ほど作成したバケットが表示されますが、先ほどのAPI GatewayのURLを貼り付けてください。貼り付けてカーソルを外すと以下のように自動で入力されます。
Create Distribution
Origin Settings
Default Cache Behavior Settings
Distribution Settings
CNAMEsはACMで取得したドメイン(例:www.yahoo.co.jp)を入力します。
ACMはドロップダウンリストから表示されるのでそれを選択します。
最後に「Create Distribution」をクリックして完了です。
Originを追加設定する
上記の赤枠のCloudFront Distributionが作成されているのが確認できます。
次はS3オリジンの設定をする必要があるので、IDのリンクをクリックします。
API GatewayのOriginは作成されているのが確認できるので、「Create Origin」をクリックします。
「Origin Domain Name」にカーソルをあてると、バケット一覧が表示されるので、今回作成したバケットを選択します。選択したら「Origin ID」が自動で入力されます。
「Restrict Bucket Access」は「Yes」にします。その他、画像の通りに選択して、「Create」をクリックします。これでS3のオリジン作成は完了です。
Behaviorsを追加設定する
S3のオリジンを作成したら、次はS3のBehaviorを作成します。
API GatewayのPath Patternが「*」となっていますが、こうしないと私が試した限りではうまく複数オリジンを一つのドメインで管理することができませんでした。
ではS3の設定をするために「Create Behavior」をクリックします。
Path Patternは、*
とすると上手くいかないので、login/*
といったようにAPI Gatewayと分けるためにPath Patternを変更してください。この時、login/
とせずに最後に必ず*
をつけてください。
あとは画像のとおり選択してください。最後に「Create」をクリックします。
完成
これでS3に配置したコンテンツをCloudFrontを経由して高速に配信し、かつ独自ドメインでSSL化されていてCognitoでサインアップ、サインインの認証、API Gatewayの認可までの設定が完了です。
具体的なサインイン画面や、サインイン後のAPI Gatewayの実行については、以下に記述します。
ログイン画面
問答無用で以下を読み込みます。バージョンは適当です。
<script src="js/aws-cognito-sdk.js"></script> <script src="js/amazon-cognito-identity.js"></script> <script src="https://sdk.amazonaws.com/js/aws-sdk-2.5.2.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
JSの先頭に以下をおまじないとしてコーディングします。
// AWS 認証情報の取得 AWS.config.region = '{{リージョン}}'; AWS.config.credentials = new AWS.CognitoIdentityCredentials({ IdentityPoolId: '{{アイデンティティプールID}}', // フェデレーティッドアイデンティティに記載されている情報 }); AWSCognito.config.region = '{{リージョン}}'; AWSCognito.config.credentials = new AWS.CognitoIdentityCredentials({ IdentityPoolId: '{{アイデンティティプールID}}', // フェデレーティッドアイデンティティに記載されている情報 });
次に、AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool
に渡すデータをJSON形式で作成します。
var data = { UserPoolId: 'us-east-2_qUKebzZoT', ClientId: 'r7pg62m9s99ub7i2q3aphemc1', Paranoia : 7 // 7である必要性はないが、0だと古いIEなどでセキュアでないらしい };
次にCognitoUser管理しているクラスを作成します。
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(userPoolData); // ユーザープールを作成 var userData = { Username : $('#name').val(), // ログイン画面のユーザーIDを指定します Pool : userPool }; var cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);
これでCognitoUser管理しているクラスを作成することができました。
やっと認証ができます。ユーザIDとパスワードを以下の形式で変数に格納します。
var authenticationData = { Username : $('#name').val(), // ユーザIDとします Password : $('#password').val() // パスワードとします };
authenticationDataを、cognitoUser.authenticateUserメソッドの第一引数に渡します。
cognitoUser.authenticateUser(authenticationDetails, { onSuccess: function (authresult) { // 成功時の処理(画面遷移とか) }, onFailure: function(err) { alert(err.message); // 失敗時の処理(今回はアラート) }, });
これで完了です。
認可されていないAPIにアクセスしたら
こんな画面になります。
S3に直接アクセスさせないように設定する
S3のURLにアクセスされても403となるように設定し、「Origin Access Identity」を使ってCloudfront経由のみからアクセスさせることができます。
S3もURLが以下の形式で決まっているので、アクセスすると閲覧できてしまいます。
見えていますね。
CloudFrontに「Origin Access Identity」というのがあるのでクリックします。
IDをメモしておきます。
S3のバケットを選択し、「アクセス権限」-「バケットポリシー」を選択して以下のように編集します。
{ "Version": "2008-10-17", "Id": "PolicyForCloudFrontPrivateContent", "Statement": [ { "Sid": "1", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <OAIのID>" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::<バケット名>/*" } ] }
これで完了です。
認証と認可の意味について
ざっくり言うと認証がサインイン(誰であるかの確認)で、認可は認証時に発行された認証トークンを持ってAPI Gatewayを実行する事ができたりできなかったりすることを認可と言う感じです。
なので、サインインしていない状態でAPIを実行しても認証トークンがないため実行ができません。この状態を認可されていない、と言う感じでしょうか。
認証されて初めて認可されます。
KHI入社して退社。今はCONFRAGEで正社員です。関西で140-170/80~120万から受け付けております^^
得意技はJS(ES6),Java,AWSの大体のリソースです
コメントはやさしくお願いいたします^^
座右の銘は、「狭き門より入れ」「願わくは、我に七難八苦を与えたまえ」です^^
コメント