Windowsフォームアプリの認証にCognitoを使ってみた

# 概要
Cognitoで準備したアカウントを使ってWindows Formアプリにログインする。
ログインを通過したら、CognitoからAWSアカウント（S3 参照権限付き）をもらって
S3バケットの一覧を表示する。
![ざっくり](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185989/c26ac458-d105-8c64-9fc0-be50119eeecb.png)

# 前提
一連の認証ができる形をCognitoで作っておく↓
[Cognito 組み込みWebページ＋S3だけで動的サイトを作る](https://qiita.com/afukuma/items/51e57b44d21b5e02614a)

ここでは、以下のパラメータが必要になります

|パラメータ | 例 |
| --- | --- | 
| ユーザプールID|us-east-1_hhogehogeh | 
| アプリケーションクライアントID| 4ks0na9rghogehogehoge0l| 
| IDプールのID| us-east-1:7864a4bf-8045-4221-a280-hogehogehoge|

あと、S3のバケットも準備しておきます

# ソース
フォームデザインは↓こんな感じ
![Login.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185989/10b73cd5-f04f-0dbd-492e-cca0a81d04bb.jpeg)

IDとパスワードを入力して、Loginボタンを押すと何かが起こる感じにしておきます。

Loginボタンクリック時は非同期で実行します。

```csharp
/*
  ここで使う変数
　wwRegion :: Cognitoのリージョン
  wwUserPoolID  ::CognitoのユーザプールID
  wwAppClientID ::CognitoのアプリケーションクライアントID
  txtID.Text    ::フォーム上のIDテキストボックス
  txtPass.Text  ::フォーム上のPasswordテキストボックス
  wwIdPoolID    ::CognitoのIDプールのID
  wwS3BucketName::S3バケット名

*/

private async void btnLogin_ClickAsync(object sender, EventArgs e)
{
        AmazonCognitoIdentityProviderClient provider = new AmazonCognitoIdentityProviderClient(new Amazon.Runtime.AnonymousAWSCredentials(), wwRegion);
        CognitoUserPool userPool = new CognitoUserPool(wwUserPoolID, wwAppClientID, provider);
        CognitoUser user = new CognitoUser(txtID.Text, wwAppClientID, userPool, provider);
        InitiateSrpAuthRequest authRequest = new InitiateSrpAuthRequest()
        {
            Password = txtPass.Text
        };

        AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);
        string idToken = authResponse.AuthenticationResult.IdToken;

        CognitoAWSCredentials credentials = new CognitoAWSCredentials(
            wwIdPoolID, // ID プールの ID
            wwRegion    // リージョン
        );

        credentials.AddLogin("cognito-idp.us-east-1.amazonaws.com/" + wwUserPoolID, idToken); // the raw token
        //↓おまじない
        string hoge = await credentials.GetIdentityIdAsync();
        
        //ここから下は、通常のAPIの利用方法
        using (var client = new AmazonS3Client(credentials, wwRegion))
        {
            var S3Request = new ListObjectsRequest();
           S3Request.BucketName = wwS3BucketName;
            var S3Response = await client.ListObjectsAsync(S3Request);
            //ここでオブジェクトがとれている（略）
   
         }
}
```

# 解説
ちゃんと理解しているわけではないので、動物的感覚で説明

1. 入力したユーザ＋パスワードからトークンを取得
2. トークンからAWSアカウントを取得
3. AWSアカウントから、各種APIを利用する


## 1. 入力したID・パスワードから、トークンを取得する
[公式:Amazon CognitoAuthentication 拡張ライブラリの例](https://docs.aws.amazon.com/ja_jp/sdk-for-net/v3/developer-guide/cognito-authentication-extension.html)に書いているもの

```csharp
        AmazonCognitoIdentityProviderClient provider = new AmazonCognitoIdentityProviderClient(new Amazon.Runtime.AnonymousAWSCredentials(), wwRegion);
        CognitoUserPool userPool = new CognitoUserPool(wwUserPoolID, wwAppClientID, provider);
        CognitoUser user = new CognitoUser(txtID.Text, wwAppClientID, userPool, provider);
        InitiateSrpAuthRequest authRequest = new InitiateSrpAuthRequest()
        {
            Password = txtPass.Text
        };

        AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);
        string idToken = authResponse.AuthenticationResult.IdToken;
```
トークンは、アクセストークン・IDトークン・他がある様子（詳しくは[こちら](https://qiita.com/wadahiro/items/ad36c7932c6627149873))

ID・パスワードがCognitoで登録されているユーザに該当するとidTokenに、長い文字列が設定されます。

## 2. トークンを使ってAWS認可権限を取得する

フェデレーテッドアイデンティティ のサンプルコード→AWS認証情報の取得のソースコードを使います
![スクリーンショット 2019-08-18 10.53.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185989/bd66a359-0f4a-fd21-6f91-52068c2e6d15.png)

```csharp
        CognitoAWSCredentials credentials = new CognitoAWSCredentials(
            wwIdPoolID, // ID プールの ID
            wwRegion    // リージョン
        );
```

credentialオブジェクトに、上記で取得したIDトークンを渡します。

```csharp
        credentials.AddLogin("cognito-idp.us-east-1.amazonaws.com/" + wwUserPoolID, idToken);
        //↓おまじない
        string hoge = await credentials.GetIdentityIdAsync();
```

よくわからないが、おまじないをします。

ここで取得できるAWSアカウントは、👇これです
![スクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185989/e8eec00b-f0cc-1c45-4ff5-293e7a7a6b95.png)

## 3.あとは、通常の認証と同じように使える

```csharp
        using (var client = new AmazonS3Client(credentials, wwRegion))
        {
            var S3Request = new ListObjectsRequest();
           S3Request.BucketName = wwS3BucketName;
            var S3Response = await client.ListObjectsAsync(S3Request);
            //ここでオブジェクトがとれている（略）
   
         }
```


## まとめ
.Net系はなかなか情報が見つからない。。
随時修正します。。