Cognito認証を経てS3バケットにアップロード

## はじめに

Cognitoでユーザープールでの認証完了後、IDプールと連携してS3バケットにアップロードするために必要なAWS設定を調べてみました。Cognitoユーザープールの設定やSwiftでのCognitoによるサインインやS3バケットへのアップロードを行うコードについては大幅に割愛していますのでご了承ください。

## AWS設定手順


### S3：バケットの作成

デフォルトの設定でバケットを作成します。

### Cognito：IDプールの設定

CognitoのIDプールの管理画面から`新しい ID プールの作成`を押してIDプールを作成します。IDプール名を入力後、認証プロバイダーに作成済みのユーザープールIDとアプリクライアントIDを指定し`プールの作成`を押します。
![名称未設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1777258/b9b4a2e5-0fa3-db69-8384-e4b07b51e24f.png)

次に表示される画面ではロールを作成します。上の段（`Your authenticated identities...`）のポリシードキュメントを表示し、編集ボタンを押して編集します。今回はアップロードすることが目的なので、`"s3:PutObject*"`を追加します。編集が終わったら画面下方の`許可`ボタンを押して次に進みます。
![名称未設定2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1777258/15ff96fa-cea5-1173-4196-229232a855e7.png)

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject*",
                "mobileanalytics:PutEvents",
                "cognito-sync:*",
                "cognito-identity:*"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
```

サンプルコードが表示されひとまず設定終了です。identityPoolIdが後々必要になりますが、この画面は後からでも確認することができます。
![名称未設定3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1777258/4b930174-fc5c-e0b5-4180-ccaffce0a0e0.png)

## Swiftによる実装

### パッケージの追加

podで以下のパッケージを追加します。

```rb
  # For Amazon Cognito.
  pod 'AWSCognitoIdentityProvider', '~> 2.12.0'
  pod 'AWSS3'
```

### AppDelegate

リージョンやIDなどを指定します。

```Swift
import AWSCognitoIdentityProvider
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    private let REGION: AWSRegionType = リージョン
    private let USER_POOL_ID: String = ユーザープールID
    private let ID_POOL_ID: String = IDプールのサンプルコードのidentityPoolId
    private let APP_CLIENT_ID: String = アプリクライアントID
    private let APP_CLIENT_SECRET: String? = nil
    private let KEY: String = "UserPool"

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        let serviceConfiguration = AWSServiceConfiguration(
            region: REGION,
            credentialsProvider: nil
        )
        
        let userPoolConfigration = AWSCognitoIdentityUserPoolConfiguration(
            clientId: APP_CLIENT_ID,
            clientSecret: APP_CLIENT_SECRET,
            poolId: USER_POOL_ID
        )

        AWSCognitoIdentityUserPool.register(
            with: serviceConfiguration,
            userPoolConfiguration: userPoolConfigration,
            forKey: KEY
        )

        // Amazon Cognito 認証情報プロバイダーを初期化します
        let pool = AWSCognitoIdentityUserPool(forKey: KEY)
        // IDプールで表示されるサンプルはidentityProviderManagerは指定されていませんが、指定した方が良いようです
        let credentialsProvider = AWSCognitoCredentialsProvider(
            regionType: REGION,
            identityPoolId: ID_POOL_ID,
            identityProviderManager:pool
        )
        let configuration = AWSServiceConfiguration(
            region: REGION,
            credentialsProvider:credentialsProvider
        )
        AWSServiceManager.default().defaultServiceConfiguration = configuration

        return true
    }
```

CognitoユーザーによるサインインやS3アップロードのコードは割愛させていただきます。


## その他

認証しないでアップロードを試みるとtransferUtility.uploadDataの実行時に以下のようなエラーが発生するのでおそらくうまく行っているのではないかと思っています。

```
Authentication delegate not set
```

ツッコミどころ満載と思いますが、不備等あればご指摘いただければ幸いです。



## 参考文献

[Amazon Cognito デベロッパーガイド](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/cognito-dg.pdf)