UnityでCognito UserPoolsを使ってサインアップ・サインインを実現する

開発環境のセットアップ

検証に先立ち、以下の開発環境を構築しました。

  • macOS 10.13.4
  • Unity 2017.2.2f1
  • Mono 5.4.1.6

Unityプロジェクトの作成とAWS SDK導入

UnityではC#とUnity Scriptを使えますが、今回はC#を使います。
AWS Mobile SDK for Unityは執筆時点でCognito UserPoolsに対応していないため、今回はAWS SKD for .NETを使用します。これはNuGetで配布されているので、UnityでのNuGetパッケージ管理ツールとして、Nuget for Unityを使用します。
アセットストアからダウンロードして、プロジェクトにインポートします。

また、AWS SDK for .NETはMicrosoft .NET Framework 3.5 以降を必須要件としていますが、Unity 2017はデフォルトが2系を使うランタイム設定なので、Experimentalに変更して4系に変更する必要があります。
※ 次期バージョンのUnity 2018からデフォルトのランタイムが.NET 4.6になるそうです。 https://blogs.unity3d.com/jp/2018/01/05/discontinuing-support-for-monodevelop-unity-starting-in-unity-2018-1/

ここまで設定したら、NuGet for Unityを使ってAWS SDK for .NETを導入します。NuGet > Manage NuGet Packagesで検索フォームに "Cognito" と検索して、以下のパッケージをプロジェクトに追加します。

  • Amazon Cognito Identity Provider
  • CognitoAuthentication

インストールが終了すると、以下のようにAWS SDK Coreもインストールされているはずですが、されていない場合は手動でインストールしてください。

CognitoAuthenticationは、Extension Libraryと呼ばれているもので、現在はDeveloper Previewとなっている公式ライブラリです。詳細は以下のリンク先を参照してください。
https://aws.amazon.com/jp/blogs/developer/cognitoauthentication-extension-library-developer-preview/

Cognito UserPools設定

Unity側で指定する項目として、Cognito UserPools作成時に発行されるIDが必要です。今回はus-west-2に作成しました。emailをusernameとして使う設定にします。
その後、Client Idを作成します。詳細は割愛します。

Unityアプリ

Unityを操作して、以下のような画面を作成します。

そして、各ボタンに以下のようなスクリプトを設定します。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Amazon;
using Amazon.CognitoIdentityProvider;
using Amazon.CognitoIdentityProvider.Model;

public class Signup : MonoBehaviour {

    public InputField emailField;
    public InputField passwordField;
    static string clientId = "0123456789abcdef";

    void Start () {
    }

    void Update () {
    }

    public void OnClick() {
        var client = new AmazonCognitoIdentityProviderClient (null, RegionEndpoint.USWest2);
        var sr = new SignUpRequest ();
        string email = emailField.text;
        string password = passwordField.text;

        sr.ClientId = clientId;
        sr.Username = email;
        sr.Password = password;
        sr.UserAttributes = new List<AttributeType> {
            new AttributeType {
                Name = "email",
                Value = email
            }
        };

        try {
            SignUpResponse result = client.SignUp(sr);
            Debug.Log(result);
        } catch (Exception ex) {
            Debug.Log (ex);
        }
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Amazon;
using Amazon.CognitoIdentityProvider;
using Amazon.CognitoIdentityProvider.Model;

public class Confirmation : MonoBehaviour {

    public InputField emailField;
    public InputField confirmationCodeField;
    static string clientId = "0123456789abcdef";

    void Start () {
    }

    void Update () {
    }

    public void OnClick(){
        var client = new AmazonCognitoIdentityProviderClient (null, RegionEndpoint.USWest2);
        ConfirmSignUpRequest confirmSignUpRequest = new ConfirmSignUpRequest();

        confirmSignUpRequest.Username = emailField.text;
        confirmSignUpRequest.ConfirmationCode = confirmationCodeField.text;
        confirmSignUpRequest.ClientId = clientId;

        try {
            ConfirmSignUpResponse confirmSignUpResult = client.ConfirmSignUp(confirmSignUpRequest);
            Debug.Log(confirmSignUpResult.ToString());
        } catch (Exception ex) {
            Debug.Log(ex);
        }
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Amazon;
using Amazon.Runtime;
using Amazon.CognitoIdentityProvider;
using Amazon.Extensions.CognitoAuthentication;

public class Signin : MonoBehaviour {

    public InputField emailField;
    public InputField passwordField;
    static string clientId = "0123456789abcdef";
    static string userPoolId = "us-west-2_0123ABCD";

    void Start () {
    }

    void Update () {
    }

    public void OnClick() {
        Debug.Log("Start Signup");
        try {
            AuthenticateWithSrpAsync();
        } catch(Exception ex) {
            Debug.Log(ex);
        }
    }

    public async void AuthenticateWithSrpAsync() {
        var provider = new AmazonCognitoIdentityProviderClient (null, RegionEndpoint.USWest2);
        CognitoUserPool userPool = new CognitoUserPool(
            userPoolId,
            clientId,
            provider
        );
        CognitoUser user = new CognitoUser(
            emailField.text,
            clientId,
            userPool,
            provider
        );

        AuthFlowResponse context = await user.StartWithSrpAuthAsync(new InitiateSrpAuthRequest(){
            Password = passwordField.text
        }).ConfigureAwait(false);

        Debug.Log(user.SessionTokens.IdToken);
    }
}

動作確認

メールアドレスとパスワードを入力してサインアップすると、メールアドレスにconfirmation codeが届きます。
それを入力すると、IdTokenとしてJWTを得られます。デコードすると以下のようになります。

{
  "sub": "aaaa1111-abcd-aa11-bb22-0123abcd",
  "aud": "0123456789abcdef",
  "email_verified": true,
  "event_id": "fbb432a5-3b90-11e8-bc39-4f741e568ae0",
  "token_use": "id",
  "auth_time": 1523235452,
  "iss": "https://cognito-idp.us-west-2.amazonaws.com/us-west-2_0123ABCD",
  "cognito:username": "0c08e593-f9f8-4b51-XXXX-XXXXXXXX",
  "exp": 1523239052,
  "iat": 1523235452,
  "email": "example@example.com"
}

まとめ

このエントリでは、Cognito UserPoolsを使ったUnityアプリのサインインとサインアップを実装しました。
次回は、今回入手した認証情報を使ったリクエストを実装します。

4/12追記 第二回はこちらです