AWS Cognito の特徴とやってみる

#1.特徴#
アプリからできるだけログアウトさせたくない。
普段使い慣れているFacebook,Google,Amazonなどと連携させて利用したい。

などといっった課題が出てきます。

AWS Cognitoは、

- 複雑なインフラ基盤構築なしに認証、認可の機能を実装可能。
- 複数の認証方式やID情報を一元管理可能。
- 業界標準認証連携プロトコルに対応、Facebook,Google,Amazon,Microsoft ActiveDirectoryなどと容易に連携可能。
- 利用者の増加やサインアップ、サインイン回数の増加に対応してインフラを自動的にスケールさせる。

マネージドサービスです。


#2.認証と認可#
【認証】アクセスしてきたユーザが本人であることを確認する。
　↓
【認可】　アクセスしようとしているリソースに権限があるかを確認する。
　↓
【【データアクセス】】


#3.ユーザープールとIDプール#
![スクリーンショット 2019-10-13 18.10.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/f3e9cb23-9126-79e7-c575-78eccb10db76.png)

ユーザープールはアプリの開発者の方のためのサービス、
IDプールはAWSのサービスと連携するためのサービス。


#4.MFAのサポート#

- SMSテキストメッセージ
- ソフトウェアトークン


#5.Amazon Cognito Advanced Security機能#
簡単な設定で利用者のID詐称を検知、防御するコントロールを検知。

- アダプティブ認証
 - ユーザーおよび使用しているデバイス単位でリスクコアを計算し、ID詐称が行われているか検証する。
- 漏洩した認証情報（ID/passwordの組み合わせ）の利用の検知
 - Amazonで収集している漏洩した認証情報とのマッチングを行い検知する。

検知した場合は、ロギング、アクセスをブロック、追加の認証（MFA）の実行などを要求するように実装することもできます。


#6.他アプリケーションとの連携#

![スクリーンショット 2019-10-13 18.46.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/59edb745-3726-912a-3482-05ff119146bb.png)


#7.やってみた#
https://aws.amazon.com/jp/getting-started/projects/build-serverless-web-app-lambda-apigateway-s3-dynamodb-cognito/

##7-1 静的ウェブホスティング##

・S3バケットに必要なコンテンツを同期し、アップロードされたことだけ確認しておきます。

```
aws s3 sync s3://wildrydes-us-east-1/WebApplication/1_StaticWebHosting/website s3://<<YOUR_BUCKET_NAME>>

aws s3 ls s3://<<YOUR_BUCKET_NAME>>
                           PRE css/
                           PRE fonts/
                           PRE images/
                           PRE js/
2019-10-17 05:41:34       2992 apply.html
2019-10-17 05:41:34       6540 faq.html
2019-10-17 05:41:34       1406 favicon.ico
2019-10-17 05:41:41       6757 index.html
2019-10-17 05:41:41       6079 investors.html
2019-10-17 05:41:42       2735 register.html
2019-10-17 05:41:42       4329 ride.html
2019-10-17 05:41:42         43 robots.txt
2019-10-17 05:41:42       2590 signin.html
2019-10-17 05:41:43       5047 unicorns.html
2019-10-17 05:41:43       2595 verify.html
```

・ウェブホスティングを有効にする。

```
aws s3 website s3://my-bucket/ --index-document index.html
```

・パブリック読み込みを許可するバケットポリシーを作成します。

```
policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::naata-s3/*"
        }
    ]
}

aws s3api put-bucket-policy --bucket naata-s3 --policy file://policy.json
```

・S3 バケットのウェブサイトエンドポイント URL にアクセスし表示だけ確認しておく。


##7-2 ユーザー管理##

・Cognito ユーザープールを作成（設定はデフォルトのまま）し、[プール ID] を確認しておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/d9586343-4688-ea85-af12-5897e4a72aa8.png)

・ユーザープールにアクセスするための固有の ID とオプションのシークレットキーが付与するためにアプリクライアントを作成し、次の画面で[アプリクライアントID]を控えておく。「クライアントシークレットを生成する」のチェックは外しておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/6ce2d3d3-b5e6-0477-55bd-849ac3430347.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/d2311e16-f556-e5df-fff4-40b6c12ada2a.png)

・config.jsファイルの「userPoolId」「userPoolClientId」「region」を編集し更新する。

```
aws s3 cp s3://<<YOUR_BUCKET_NAME>>/js/config.js config.js

config.js
window._config = {
    cognito: {
        userPoolId: '', // e.g. us-east-2_uXboG5pAb
        userPoolClientId: '', // e.g. 25ddkmj4v6hfsfvruhpfi7n4hv
        region: '' // e.g. us-east-2
    },
    api: {
        invokeUrl: '' // e.g. https://rc7nyt4tql.execute-api.us-west-2.amazonaws.com/prod',
    }
}

aws s3 cp config.js s3://<<YOUR_BUCKET_NAME>>/js/config.js/

aws s3 ls s3://naata-s3/js/
                           PRE vendor/
2019-10-17 05:41:41       5198 cognito-auth.js
2019-10-17 07:21:28        370 config.js
2019-10-17 05:41:41       3845 esri-map.js
2019-10-17 05:41:41        168 main.js
2019-10-17 05:41:41       3642 ride.js
2019-10-17 05:41:41      86826 vendor.js
```

・register.htmlにアクセスし2 つの方法で検証していきます。

1.自分のメールアドレス
電子メールで受け取った認証コードを入力して、アカウントの検証プロセスを完了できます。

2.ダミーのメールアドレス
ダミーの E メールアドレスを使用した場合は、Cognito コンソールから手動でユーザーを確認する必要があります。​

1で登録した場合は、[E メール確認済み]が「true」2で確認した場合は「false」。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/18ec387b-e0b5-7894-71c3-18196393fab4.png)

2は[ユーザーの確認]でプロセスを終了させることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/504862f4-9623-4367-00df-6a8590e05841.png)

・signin.htmlにアクセス、ログインできるか確認しておきます。


##7-3 サーバーレスサービスバックエンド##

・DynamoDBテーブルを以下のとおり作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/c391955b-7579-33c5-39a3-41ed29789b3f.png)

・Lambda関数のIAMロールを作成する。アタッチするのは管理ポリシーとインラインポリシー。


```json:AWSLambdaBasicExecutionRole
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}
```

```json:naata-dynamodb
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "dynamodb:PutItem",
            "Resource": "<Amazon リソースネーム（ARN）>"
        }
    ]
}
```

・リクエストを処理するためのLambda関数を作成する。node.jsで作成し、先程作成したIAMロールを指定する。関数は以下のとおり。
https://github.com/aws-samples/aws-serverless-workshops/blob/master/WebApplication/3_ServerlessBackend/requestUnicorn.js

以下のテストイベントを実行する。

```json
{
    "path": "/ride",
    "httpMethod": "POST",
    "headers": {
        "Accept": "*/*",
        "Authorization": "eyJraWQiOiJLTzRVMWZs",
        "content-type": "application/json; charset=UTF-8"
    },
    "queryStringParameters": null,
    "pathParameters": null,
    "requestContext": {
        "authorizer": {
            "claims": {
                "cognito:username": "the_username"
            }
        }
    },
    "body": "{\"PickupLocation\":{\"Latitude\":47.6174755835663,\"Longitude\":-122.28837066650185}}"
}
```

結果は以下のとおり。

```
{
  "statusCode": 201,
  "body": "{\"RideId\":\"YlhfLuMeqw57vU-yF8UaXQ\",\"Unicorn\":{\"Name\":\"Shadowfax\",\"Color\":\"White\",\"Gender\":\"Male\"},\"UnicornName\":\"Shadowfax\",\"Eta\":\"30 seconds\",\"Rider\":\"the_username\"}",
  "headers": {
    "Access-Control-Allow-Origin": "*"
  }
```

・DynamoDBにも以下のとおり作成されていることがわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/0b90e5e9-1311-3b6e-6bd6-bccb03fceb43.png)


##7-4 RESTful API##
・APIを作成する。[エンドポイント]は「エッジ最適化」とする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/57eb0f0f-592e-586d-5663-2481ad7c4649.png)

・オーソライザーで、Cognito ユーザープールを使用して API へのアクセスを制御できるようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/e14e6443-7142-a7fc-1e11-e5b9adccb74f.png)

・ride.htmlにアクセスし、認証トークンを張り付けてテストします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/e4044d81-3238-3bf6-c0da-ca7c6b8e7372.png)

・レスポンスが返ってきたことがわかります。
Response Code（応答コード）: 200

・APIに[リソース]を「ride」と[メゾット]を「POST」で作成、作成したLambda関数を指定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/7984e491-9048-3bc0-9780-b03635adb0f1.png)

・[メソッドリクエスト]でCognito ユーザープールオーソライザーを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/8b172aed-1b29-d514-8c93-b5c91ee1263d.png)

・デプロイし、 [URL の呼び出し]をconfig.jsのinvokeUrlに記載する。


```js:config.js
window._config = {
    cognito: {
        userPoolId: '', // e.g. us-east-2_uXboG5pAb
        userPoolClientId: '', // e.g. 25ddkmj4v6hfsfvruhpfi7n4hv
        region: '' // e.g. us-east-2
    },
    api: {
        invokeUrl: '' // e.g. https://rc7nyt4tql.execute-api.us-west-2.amazonaws.com/prod',
    }
}
```

・動作確認をし以上で完了。