【AWS】Cognito(IDプール)で認証を行い、S3バケットへアップロードを行う

# はじめに
Cognito(ユーザープール)のIDトークンをもとにCognito(IDプール)にて認証を行い、
S3バケットへオブジェクトのアップロードを行う機会があり、
その際に実装を行った方法について、備忘録として記載します。

前提
　・Cognito(ユーザープール)の作成・設定済みとする。
　・本記事では、下記の赤矢印③〜⑤の実装方法について記載する。
![cognito_s3_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1255237/4fd4f71a-8be6-3129-a730-d041909d7468.png)

# 目次
[1. S3バケットの作成](https://qiita.com/drafts/3aca986885a7554e9ba3/edit#1-s3%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90)
[2. Cognito(IDプール)の作成](https://qiita.com/drafts/3aca986885a7554e9ba3/edit#2-cognitoid%E3%83%97%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90)
[3. IAMロールの設定](https://qiita.com/drafts/3aca986885a7554e9ba3/edit#3-iam%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E8%A8%AD%E5%AE%9A)
[4. オブジェクトアップロード処理の実装](https://qiita.com/drafts/3aca986885a7554e9ba3/edit#4-%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%A2%E3%83%83%E3%83%97%E3%83%AD%E3%83%BC%E3%83%89%E5%87%A6%E7%90%86%E3%81%AE%E5%AE%9F%E8%A3%85)
# 1. S3バケットの作成
### 1-1.バケットの作成
S3のコンソール画面から任意のバケット名で、S3バケットを作成する。
バケット作成時、ブロックパブリックアクセス設定は「パブリックアクセスをすべてブロック」（デフォルト）を選択する。
![cognito_s3_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1255237/226f96b3-f3a0-2156-35e0-e4a97ab8ec52.png)

### 1-2.アクセス許可の設定
1-1で作成したバケットを選択し、「アクセス許可」タブを開く。
アクセス許可内の「Cross-Origin Resource Sharing (CORS)」に下記のJSONをコピー&ペーストで設定する。

```
[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "HEAD",
            "GET",
            "PUT",
            "POST",
            "DELETE"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "ETag"
        ]
    }
]
```

# 2. Cognito(IDプール)の作成
Cognitoのコンソール画面から下記の設定値でIDプールを作成する。
作成時、IAMロール自動作成の確認をされるので、許可する。

|設定項目|設定値|
|:---|:---|
|ID プール名|任意の値|
|認証されていない ID に対してアクセスを有効にする|チェックなし|
|基本 (クラシック) フローを許可する|チェックあり|
|認証プロバイダー（Cognito）>ユーザープールID|ユーザー認証に使用するユーザープールID|
|認証プロバイダー（Cognito）>アプリクライアントID|ユーザー認証に使用するアプリクライアントID|

# 3. IAMロールの設定
IAM（ロール）のコンソール画面にて、ロール名「**Cognito_[2で作成したIDプール名]Auth_Role**」のロールを選択する。
※同時に作成される「Cognito_[2で作成したIDプール名]**Unauth**_Role」とロール名が似ているため、間違えないこと。

「インラインポリシーの追加」から下記のJSONを設定する。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": "*"
        }
    ]
}
```
※上記、Actionの「s3」を任意のサービスに変更することで、任意のサービスへのアクセス許可を設定することができる。
※上記、Resourceの「*」を任意の値に変更することで、特定のバケットやフォルダへのアクセス許可を設定することができる。

# 4. オブジェクトアップロード処理の実装
```javascript:S3upload.js
import AWS from 'aws-sdk'

// アップロード処理
function upload (uploadedFile, filename, idtoken) {
    // PROVEDER_KEY作成
    const PROVIDER_KEY = 'cognito-idp.' + [AWSのリージョン] + '.amazonaws.com/' + [ユーザー認証を行うユーザープールID];

    AWS.config.region = [AWSのリージョン]
    // IDプールにてIDトークンの認証を行う
    AWS.config.credentials = new AWS.CognitoIdentityCredentials({
      IdentityPoolId: [2で作成したIDプールID],
      Logins: {
        [PROVIDER_KEY]: idtoken //ユーザー認証時に返却されるIDトークン
      }
    });

    //資格情報のリフレッシュ処理
    AWS.config.credentials.refresh((err) => {
      if(err) {
          alert(err);
          return;
      }
    });
    
    // S3オブジェクト作成
    var s3 = new AWS.S3({
      apiVersion: '2006-03-01',
      region: [AWSのリージョン]
    });

    // パラメータ作成
    const params = {
      Bucket: [1で作成したバケット名],
      Key: filename,
    }
    params.Body=uploadedFile;

    return new Promise((resolve, reject) => {
      // S3へオブジェクトをアップロード
      s3.putObject(params, (err, data) => {
        if (err) {
          reject(err)
        } else {
          resolve(data)
        }
      })
    })
}
```

# 参考
[Class List - Class: AWS.S3](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html)
[LamdbaからS3内のファイルを操作したい](https://qiita.com/OsakaKaiyukan/items/507f566a1ea2d544f2f9)
[JavaScript AWS SDKでS3にある画像をブラウザに表示](https://suzuki-navi.hatenablog.com/entry/2020/10/15/165228)
[AWSマネジメントコンソールからのAmazon S3のCORS設定方法がJSON記法になっていました](https://dev.classmethod.jp/articles/amazon-s3-edit-cors-configuration-using-json-in-aws-management-console/)
[Amazon Cognito (2) サインイン後に AWS リソースへのアクセス権限を与える (Cognito Identity Pool)](https://maku.blog/p/3mx8hr2/)