AWS SDK for .NET を使って、.NET 6 アプリケーションから Amazon Cognito ユーザープールのユーザー属性を更新する

2022.07.30

いわさです。

.NET 6 アプリケーションを使って、Cognito ユーザープールのユーザー属性を更新する機会がありました。
以下のような形でユーザーがいくつか存在しており、管理者向けのAPIを使って属性を更新します。

せっかくなので本日は、AWS SDK for .NET を使うときのリファレンスの確認方法や実装方法などを交えながら紹介したいと思います。

情報を整理する

いきなりエディターを開いても良いのですが、どのように実装すれば良いのかを先ず考えてみます。
大前提として、.NET アプリケーションから AWS に対して何かしらの操作を行いたい場合は、AWS SDK for .NET を使います。
SDK API で HTTP レイヤーで直接操作することも出来ると思いますが、面倒そうです。
うまいことやってくれる SDK が便利です。

というわけで、まずは AWS SDK for .NET v3 の API リファレンスを眺めてみます。
ちなみに GitHub リポジトリはこちらです。

全ての名前空間とクラスが列挙されているようなので、Cognitoでページ内検索してみます。
そうすると以下の関係ありそうな名前空間が見つかりました。

Amazon.CognitoSyncはデータ同期用に以前使われていた機能で、今は AWS AppSync の利用が推奨されているようです。
互換性のために残されているようですね。

リファレンスの説明を見てみると、Amazon.CognitoIdentityはフェデレーション機能を使う場合に利用するもので、ユーザープールを操作するのみにフォーカスする場合は以下のAmazon.CognitoIdentityProviderを使えば良さそうな感じです。

AWS SDK の使い方はだいたいどの言語でも同じで、

  • クライアントを生成する。生成時に認証情報渡す
  • クライアントに実装されているAPI実行する

これだけです。AWS SDK for .NET でも同じです。
そこで、上述のAmazonCognitoIdentityProviderClientを使えば良さそうなことがわかったので、認可情報の引き渡し方と実装されているメソッドを確認してみましょう。

AmazonCognitoIdentityProviderClientのコンストラクタでは多岐に渡って認証情報を渡すためのオーバーロードが用意されています。
そして、AWS SDK for .NET 共通の動作として以下のような仕様になっています。

本日は Cognito の操作を関係ないところなので、指定なしで実行環境のデフォルトプロファイルを使ってもらいましょう。

さて、次にメソッドです。
Updateみたいな用語で検索するといくつか更新用APIのようなものを見つけることが出来ます。
その中のAdminUpdateUserAttributesが怪しそうです。怪しそうというかそのまんまです。管理者がユーザー属性を更新する時に使いそうな名前です。

上記説明文を呼んでも、ユーザー属性を更新するメソッドであると説明されていますね。こいつを使いましょう。

使い方ですが、オーバーロードはなくてシンプルです。
AdminUpdateUserAttributesRequest型のリクエスト情報を引き渡すだけですね。
そして、AdminUpdateUserAttributesRequestを見てみると、コンストラクタは引数なしのやつがひとつ、メソッド無し。ユーザープールID、ユーザー名、ユーザー属性のリストをプロパティとして設定出来るようになっています。

ということで、以下を実施すれば実現出来そうということがわかりました。

  • AWS SDK for .NET をインストール
  • AmazonCognitoIdentityProviderClientを生成
  • AdminUpdateUserAttributesRequestを生成し、更新対象のユーザープールID, ユーザー名, 更新したい属性情報を設定
  • AdminUpdateUserAttributesを実行
  • おわり

やってみる

ここまでの情報整理で9割実装終わってるようなものですが念の為実際に動作させておきたいところなので、やってみます。

.NET アプリケーションはなんでも良いので、シンプルにコンソールアプリケーションで作成し、NuGet パッケージを追加します。
今回の範囲であれば、AWSSDK.CognitoIdentityProviderのみインストールすれば良いです。

% dotnet new console
テンプレート "コンソール アプリ" が正常に作成されました。

作成後の操作を処理しています...
/Users/iwasa.takahito/src/aws-dotnet-cognito-admin-userpool-update/aws-dotnet-cognito-admin-userpool-update.csproj で ' dotnet restore ' を実行しています...
  Determining projects to restore...
  Restored /Users/iwasa.takahito/src/aws-dotnet-cognito-admin-userpool-update/aws-dotnet-cognito-admin-userpool-update.csproj (in 93 ms).
正常に復元されました。

% dotnet add package AWSSDK.CognitoIdentityProvider --version 3.7.4.20
  Determining projects to restore...
  Writing /var/folders/4d/nhd1bp3d161crsn900wjrprm0000gp/T/tmpueKRRJ.tmp
info : Adding PackageReference for package 'AWSSDK.CognitoIdentityProvider' into project '/Users/iwasa.takahito/src/aws-dotnet-cognito-admin-userpool-update/aws-dotnet-cognito-admin-userpool-update.csproj'.
info : Restoring packages for /Users/iwasa.takahito/src/aws-dotnet-cognito-admin-userpool-update/aws-dotnet-cognito-admin-userpool-update.csproj...
info :   GET https://api.nuget.org/v3-flatcontainer/awssdk.cognitoidentityprovider/index.json
info :   OK https://api.nuget.org/v3-flatcontainer/awssdk.cognitoidentityprovider/index.json 665ms
info :   GET https://api.nuget.org/v3-flatcontainer/awssdk.cognitoidentityprovider/3.7.4.20/awssdk.cognitoidentityprovider.3.7.4.20.nupkg
info :   OK https://api.nuget.org/v3-flatcontainer/awssdk.cognitoidentityprovider/3.7.4.20/awssdk.cognitoidentityprovider.3.7.4.20.nupkg 690ms
info :   GET https://api.nuget.org/v3-flatcontainer/awssdk.core/index.json
info :   OK https://api.nuget.org/v3-flatcontainer/awssdk.core/index.json 673ms
info :   GET https://api.nuget.org/v3-flatcontainer/awssdk.core/3.7.12.16/awssdk.core.3.7.12.16.nupkg
info :   OK https://api.nuget.org/v3-flatcontainer/awssdk.core/3.7.12.16/awssdk.core.3.7.12.16.nupkg 738ms
info : Installed AWSSDK.CognitoIdentityProvider 3.7.4.20 from https://api.nuget.org/v3/index.json with content hash cc5G7+C/Nf8SZB9xzS9Er9W7QCBv91a/AdkfYHdeg/1Biit5meQMbSYXrCETrWejI/LQQ2uwEYHoecbQmn3btQ==.
info : Installed AWSSDK.Core 3.7.12.16 from https://api.nuget.org/v3/index.json with content hash 6o20L6vXNHtRZ0Ir0QN3v7H+jy8+WUQXMN9tdDdIDj/NCacWU1BHHDEbpCTAV6UopRIFd+IulXGbHCfoLLbgDw==.
info : Package 'AWSSDK.CognitoIdentityProvider' is compatible with all the specified frameworks in project '/Users/iwasa.takahito/src/aws-dotnet-cognito-admin-userpool-update/aws-dotnet-cognito-admin-userpool-update.csproj'.
info : PackageReference for package 'AWSSDK.CognitoIdentityProvider' version '3.7.4.20' added to file '/Users/iwasa.takahito/src/aws-dotnet-cognito-admin-userpool-update/aws-dotnet-cognito-admin-userpool-update.csproj'.
info : Committing restore...
info : Generating MSBuild file /Users/iwasa.takahito/src/aws-dotnet-cognito-admin-userpool-update/obj/aws-dotnet-cognito-admin-userpool-update.csproj.nuget.g.props.
info : Writing assets file to disk. Path: /Users/iwasa.takahito/src/aws-dotnet-cognito-admin-userpool-update/obj/project.assets.json
log  : Restored /Users/iwasa.takahito/src/aws-dotnet-cognito-admin-userpool-update/aws-dotnet-cognito-admin-userpool-update.csproj (in 6.23 sec).

ユーザープールIDと更新対象のユーザー名は、この記事では簡易的にハードコードしておきます。利用にあたってはご注意ください。

先程整理した情報を元に、クライアントインスタンスを生成し、リクエストオブジェクトのインスタンス生成、更新APIの実行を行います。
result.HttpStatusCodeをコンソール出力しているのは特に意味はなく、アプリケーションにあわせてresultをどう扱うかは適宜検討しましょう。

Program.cs

using Amazon.CognitoIdentityProvider;
using Amazon.CognitoIdentityProvider.Model;

var client = new AmazonCognitoIdentityProviderClient();
var result = await client.AdminUpdateUserAttributesAsync(new AdminUpdateUserAttributesRequest
{
    UserPoolId = "ap-northeast-1_zVyUOeuZo",
    Username = "hoge-user1",
    UserAttributes = new List<AttributeType>
    {
        new AttributeType { Name = "name", Value = "user111"},
        new AttributeType { Name = "nickname", Value = "hogehogehoge"}
    }
});

Console.WriteLine(result.HttpStatusCode);

一点今回学んだのですが、Top Level ステートメントに慣れていなくて、await使うときにどこでasyncにするんだと最初戸惑いました。
どうやら勝手にやってくれるらしいですね。便利だなぁ。

では、変更前後を比較しながら実行してみましょう。

aws cognito-idp admin-get-user --user-pool-id ap-northeast-1_zVyUOeuZo --username hoge-user1 --profile hoge
{
    "Username": "hoge-user1",
    "UserAttributes": [
        {
            "Name": "sub",
            "Value": "2c202fa2-f5d2-42be-a0af-a2c6e17111f6"
        },
        {
            "Name": "email_verified",
            "Value": "true"
        },
        {
            "Name": "name",
            "Value": "user1"
        },
        {
            "Name": "nickname",
            "Value": "hoge"
        },
        {
            "Name": "email",
            "Value": "hoge-user1@example.com"
        }
    ],
    "UserCreateDate": "2022-07-30T06:37:02.689000+09:00",
    "UserLastModifiedDate": "2022-07-30T06:38:48.731000+09:00",
    "Enabled": true,
    "UserStatus": "FORCE_CHANGE_PASSWORD"
}

% dotnet run                
OK

% aws cognito-idp admin-get-user --user-pool-id ap-northeast-1_zVyUOeuZo --username hoge-user1 --profile hoge
{
    "Username": "hoge-user1",
    "UserAttributes": [
        {
            "Name": "sub",
            "Value": "2c202fa2-f5d2-42be-a0af-a2c6e17111f6"
        },
        {
            "Name": "email_verified",
            "Value": "true"
        },
        {
            "Name": "name",
            "Value": "user111"
        },
        {
            "Name": "nickname",
            "Value": "hogehogehoge"
        },
        {
            "Name": "email",
            "Value": "hoge-user1@example.com"
        }
    ],
    "UserCreateDate": "2022-07-30T06:37:02.689000+09:00",
    "UserLastModifiedDate": "2022-07-30T07:41:37.628000+09:00",
    "Enabled": true,
    "UserStatus": "FORCE_CHANGE_PASSWORD"
}

無事、更新することが出来ました。

さいごに

本日は、AWS SDK for .NET を使って、.NET 6 アプリケーションから Amazon Cognito ユーザープールのユーザー属性を更新する方法を、実際にリファレンスを眺めながら実装方法を考えるところから行ってみました。

.NET での AWS ワークロード実装は他のランタイムと比較するとサンプルなども少なめかなと思うので、リファレンスなどみながらササッと実装出来るようにしておきたいところです。