AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

AWS Cognitoでは認証画面は提供していません。(でも提供していたらどなたか教えてください)
認証画面を自作します。ちょっと凝ったことをしたいのでCloudFrontで配信し、S3にWebコンテンツを配置します。
使用するサービスは、ACM,CroudFront,Route53,Cognito,S3,APIGatewayです。

上記の記事で独自ドメイン + SSL化が完了したら、Cognitoでユーザープールを作成してください。

S3にWebコンテンツを置いてCloudFrontで配信する

Webコンテンツを配置するS3のバケットを作成します。
適当に「web」というバケットを作成してみます。すると「バケット名はすでに存在しています」と怒られます。
どうもバケット名はそのリージョン内ではなく全世界でユニークでないといけないようです。
バケット名なんて何でも良いので適当に命名して作成します。

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

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」として作成します。

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

認証は別記事で書いたCognitoの設定で作成した認可を指定してください。ここでは「cognito1」という名前の認可になります。LambdaはJSONを返しているだけです。

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

「アクション」ー「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

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

Default Cache Behavior Settings

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

Distribution Settings

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

CNAMEsはACMで取得したドメイン(例:www.yahoo.co.jp)を入力します。

ACMはドロップダウンリストから表示されるのでそれを選択します。

最後に「Create Distribution」をクリックして完了です。

Originを追加設定する

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

上記の赤枠のCloudFront Distributionが作成されているのが確認できます。

次はS3オリジンの設定をする必要があるので、IDのリンクをクリックします。

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

API GatewayのOriginは作成されているのが確認できるので、「Create Origin」をクリックします。

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

「Origin Domain Name」にカーソルをあてると、バケット一覧が表示されるので、今回作成したバケットを選択します。選択したら「Origin ID」が自動で入力されます。

「Restrict Bucket Access」は「Yes」にします。その他、画像の通りに選択して、「Create」をクリックします。これでS3のオリジン作成は完了です。

Behaviorsを追加設定する

S3のオリジンを作成したら、次はS3のBehaviorを作成します。

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

API GatewayのPath Patternが「*」となっていますが、こうしないと私が試した限りではうまく複数オリジンを一つのドメインで管理することができませんでした。

ではS3の設定をするために「Create Behavior」をクリックします。

 

次はS3オリジンの設定をする必要があるので、IDのリンクをクリックします。

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

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にアクセスしたら

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

こんな画面になります。

S3に直接アクセスさせないように設定する

S3のURLにアクセスされても403となるように設定し、「Origin Access Identity」を使ってCloudfront経由のみからアクセスさせることができます。

S3もURLが以下の形式で決まっているので、アクセスすると閲覧できてしまいます。

http://<バケット名>.s3.amazonaws.com

AWS Cognitoで認証画面を作成してサインイン後にAPI GatewayをCognitoで認可する

見えていますね。

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を実行しても認証トークンがないため実行ができません。この状態を認可されていない、と言う感じでしょうか。

認証されて初めて認可されます。

コメント

タイトルとURLをコピーしました