simplestarの技術ブログ

目的を書いて、思想と試行、結果と考察、そして具体的な手段を記録します。

AWS DynamoDB を Unity で操作する

AWS DynamoDB を Unity で操作できました。
詳細な手順をなんもわからん状態から出来るようになるまでを記録しました。

記事概要として、AWS Cognito の機能として

1.ユーザープールを作成(サインアップ、認証コードをメールアドレスへ送信、サインインできるようになる)
2.IDプールを作成(未認証ユーザー、サインインしたユーザーそれぞれにAWSアクセス権限を付与)
3.未認証のユーザーが AWS DynamoDB を利用してテーブルの作成と利用ができることを確認
おまけ:認証ユーザーになるには ID トークンなるものが必要らしい

それでは順に見ていきましょう。

# ユーザープールを作成

ユーザープールの作成方法としてこちらのステップ 1, 2, 3 を実行してみました。

ユーザープールの開始方法。 - Amazon Cognito

いいですか?
ステップ 1, 2, 3 のみですよ。

ソーシャルIDプロバイダーはいくつか選択できますが、Google のみ行いました。

Google での手順リンク先でまた迷いましたが、次のページにて「CONFIGURE A PROJECT」ボタンを発見できました。
https://developers.google.com/identity/sign-in/web/sign-in

Google 側も手順を省略する方向でサイトを整備したみたいですね。
リダイレクト URL など設定するため、作成したプロジェクトのGoogleコンソール画面へ移動すると、すでに認証情報が作られていました。
あとは設定項目にステップで指定された url を記入して完成~

作ったユーザープールの login のURLを開くと次の Google でログイン or 新しくメールアドレスとパスワードでアカウント登録の画面が出ました!

f:id:simplestar_tech:20190324113618j:plain
https://your_user_pool_domain/login?response_type=code&client_id=your_client_id&redirect_uri=https://www.example.com (作成したものによる置換がいるよ!)を開いたときの画面

それぞれでログインすると、AWS Cognito のユーザープールのユーザー一覧ページにて、それぞれのユーザーアカウント情報を確認することができました。

f:id:simplestar_tech:20190324114404j:plain
Google認証と新規email&パスワード認証をしたときのCognitoユーザー一覧画面

ユーザーそれぞれの情報を確認できます、ここでメールアドレスは確認できましたが、パスワードまでは閲覧できませんでした。(これ重要)
これでユーザープールが出来た…

# IDプールを作成

次の手順に従って ID プール名を記入して、上記ユーザープールの ID とアプリクライアントIDをプロバイダーの項目に入力しました。
サインイン後に ID プールを使用して AWS サービスへアクセスする - Amazon Cognito

これで ID プールが出来た。
その ID プールのダッシュボード開いてる状態…

# 未認証のユーザーが AWS DynamoDB を利用

ここからはいよいよ Unity のコードに触れってことらしいですね。
次の手順に従って .unitypackage 群をダウンロードします。
AWS Mobile SDK for Unity のセットアップ - AWS Mobile SDK

> 使用する .unitypackage ファイルに移動して選択します。
どれ?

f:id:simplestar_tech:20190324153201j:plain
AWS SDK for Unity packages

なるほど、今回は DynamoDB というオンラインデータベースを使おうと思っていますので
AWSSDK.DynamoDBv2.3.3.100.1.unitypackage
を展開して利用することにしました。

AWSSDK, Examples, Plugins フォルダが作られそれぞれに SDK, Sample, Plugin が配置されました。

サンプルちょっと眺めてますが、書式古いですねー(Unity ユーザー、上から目線w)
同梱の readme にシーンの構成と使い方が示されています。こちら一読して作業しました。

とにかくシーンビルド構成を

1. DynamoDbExample.unity
2. LowLevelDynamoDbExample.unity
3. TableQueryAndScanExample.unity
4. HighLevelExample.unity

にして実行しろとのこと
そして、それぞれのシーンのゲームオブジェクトのインスペクタにて ID プールの ID を記入し、適宜お使いのリージョン名に書き換えろとのことです。
対処しました。

ほか、オンラインドキュメントで説明のある awsconfig.xml ファイルがないことで混乱しましたが…
混乱したまま進めることにしました。

実装を見るに、認証しないユーザーで DynamoDB の Table を作ったり Table を列挙したり、Table の中身を更新したり、Table の中身を列挙したり、Table を破壊したりしています。
先に IAM の方で、そんな DynamoDB への操作を許可しているか確認してみましょう。

IAM コンソールにはいくつかディフォルトのロールと、今回作成した Cognito* というロールがあります。
未認証のロールの方を選択して、インラインポリシーの追加を選択すると、次の通り DynamoDB をサービスに選ぶと、一覧と設定UIが現れました。

f:id:simplestar_tech:20190324163932j:plain
IAM ポリシーの編集はビジュアルエディット可能

これらを設定して保存してあげれば、一時認証のときに DynamoDB を操作することができますね。
さらにリクエストする IP アドレスの範囲設定までできたので、自宅からのアクセスのみに絞ってみました。
これで、第三者から勝手に DB 編集されずに済みますね!安全である

さて、Unity サンプルを実行するとなにやらエラーが発生したので、解決に取り掛かります。(わけわからん時に触るサンプルはだいたい修正しないと動かないものです。めんどくさい)

エラー内容から調べると、次の解決方法に出会いました。
Unity2017.3.0p4 で AWS SDK が例外を吐くようになったので原因を調べてみた

具体的には DynamoDBExample.cs にて、次の行を追加します。

        void Start()
        {
            UnityInitializer.AttachToGameObject(this.gameObject);
            AWSConfigs.HttpClient = AWSConfigs.HttpClientOption.UnityWebRequest; // ←この行で UnityWebRequest 使うように指定

うごきました!
Create Table ボタンを押すと Forum, ProductCatalog, Reply, Thread の四つの DynamoDB Table が作られました。
Table の Describe も行えましたし、Table のDelete もできました。

IAM に権限がないとアイテムの追加に失敗し、IAMポリシーを編集すれば、ゲーム起動中に権限が切り替わって Table 内のアイテム操作が行えることも確認しました。

オンラインデータベースにブロック情報を書き込んだり、読み出したりする時に参考になるサンプル実装はこんな感じでした。

        int bookID = 1001;
        DynamoDBContext Context;

        void Start()
        {
                var _CognitoPoolRegion = RegionEndpoint.GetBySystemName("ap-northeast-1");
                var Credentials = new CognitoAWSCredentials(IdentityPoolId, _CognitoPoolRegion); // ID プールの ID を文字列で指定
                var Client = new AmazonDynamoDBClient(Credentials, _DynamoRegion); // ユーザープール使っていない、つまり未認証の権限ロールを使用することになります。
                Context = new DynamoDBContext(Client); // アイテム操作は Context というものを介して操作する模様
        }

        private void PerformUpdateOperation()
        {
            // Retrieve the book. 
            Book bookRetrieved = null;
            Context.LoadAsync<Book>(bookID,(result)=> // Update なので、値が取れることは期待
            {
                if(result.Exception == null )
                {
                    bookRetrieved = result.Result as Book; // ここは期待通りなら強制キャスト
                    // Update few properties.
                    bookRetrieved.ISBN = "222-2222221001";
                    bookRetrieved.BookAuthors = new List<string> { " Author 1", "Author x" }; // Replace existing authors list with this.
                    Context.SaveAsync<Book>(bookRetrieved,(res)=> // 更新したデータ構造をそのままコピーします
                    {
                        if(res.Exception == null)
                            resultText.text += ("\nBook updated");
                    });
                }
            });
        }

    [DynamoDBTable("ProductCatalog")] // データ構造はこれらの属性が必要
    public class Book
    {
        [DynamoDBHashKey]   // Hash key.
        public int Id { get; set; }
        [DynamoDBProperty]
        public string Title { get; set; }
        [DynamoDBProperty]
        public string ISBN { get; set; }
        [DynamoDBProperty("Authors")]    // Multi-valued (set type) attribute. 
        public List<string> BookAuthors { get; set; }
    }

上記コードで更新した ProductCatalog テーブルのアイテム id = 1001 を AWS DynamoDB コンソールで選択すると、以下のような値が確認できました。

f:id:simplestar_tech:20190324181528j:plain
上記コードで作った Table の一つのアイテム

最初は、愚かしいデータ構造にしてみて、どんなレスポンスでゲームが遊べるのか試してみましょうか
やりたいことができるようになってきたのでいったん記事は完成ということで

# おまけ:認証ユーザーになるには ID トークンなるものが必要らしい

追記:
未認証による操作はできたのですが、認証を通した後の操作は?
気になりますよね。

Google の場合はここに示されている手順で 3つのクライアントIDを作成して、もろもろ登録して Unity に Googleプラグインを入れて操作することになるそうです。
Google (ID プール) - Amazon Cognito

AWS Cognito の User プールは?

ユーザープールを ID プールと統合するに示される通り

                       CognitoIdentityProviderName = "cognito-idp.<region>.amazonaws.com/<YOUR_USER_POOL_ID>";
                        Credentials.AddLogin(CognitoIdentityProviderName, initiateAuthResponse.Response.AuthenticationResult.IdToken);
                        Credentials.GetIdentityIdAsync(responce =>
                        {
                            Debug.Log("Logged In with refreshed IdToken : " + responce.Response);
                        });

で、認証情報にユーザープールを統合できるそうです。
おや initiateAuthResponse.Response.AuthenticationResult.IdToken はどうやって手に入れるのか
参考ページはこちら
https://qiita.com/t5ujiri/items/07575a7596e18340eefb#unity%E3%81%A7%E8%AA%8D%E8%A8%BC%E3%83%95%E3%83%AD%E3%83%BC%E3%82%92%E5%AE%9F%E8%A3%85%E3%81%99%E3%82%8B

どうしても認証を通して作業したいので、次はこちらの記事を参考に認証を通した後の IAM ロールで操作できることを確認してみます。

認証を通してから IAM による権限制御で AWS を Unity から直接操作できました!
手順をQiitaの方に書いておきました。
qiita.com