認証

【PlayFab】Sign in with Apple を「簡単に」統合する方法

sign-in-with-apple

Apple のアカウントでログインができる、「Sign in with Apple」。

実は最近、PlayFab などのサードパーティを使用してログインする場合、Sign in with Apple の実装も「必須」になりました。

すでにリリース済みのアプリも、2020/6末までに対応が必要とのことで、なかなか大変です。

ですが、実装しないといけない割に、「どうやって実装したらいいのか」がちゃんとまとまっていません。

Unity 公式ブログでも実装方法は紹介されているのですが、内容が少し古く、ソースコードや解説も十分とは言えません。

ということで、情報が少なく苦戦しましたが、私が自分で調べて実現しました。

この記事では、Unity において Sign in with Apple を実現し、PlayFab に統合する方法をわかりやすくまとめています。

純粋に Unity に組み込むだけの場合でも、参考になると思います。

読み終える頃には、Sign in with Apple に対する抵抗感もなくなり、スムーズに実装ができるようになっているはずです。

前置きはこれくらいにして、さっそく見ていきましょう。

Sign in with Apple を統合する方法

Apple Developer Account がないとこの先が進められないので、ご注意ください。

事前準備

事前準備については、公式ドキュメントも参考になるので合わせてご覧ください。

Apple の Developer サイトにログインして、「Sign In with Apple」の機能をつけた Identifier を作成しましょう。

sign-in-with-apple

私は以下の情報で登録しました。

sign-in-with-apple

「IDENTIFIER」の列はあとで使うので、コピーしておいてください。

次に、PlayFab の管理画面に戻って、アドオンの Apple を有効にします。

先ほどコピーした「IDENTIFIER」を、バンドルIDに設定してください。

sign-in-with-apple

トークンの有効期限を設定すると、一定時間(10分)経つと再ログインが必要になり、セキュリティが強化できます。

しかし、ゲームをするのに毎回ログインしていては大変なので、今回は有効期限を無視することにしました。

これで事前準備は完了です。

次からは、Unity 側の処理を見ていきましょう。

オープンソースのダウンロード

Unity 公式でも Sign in with Apple のサンプルが公開されているのですが、圧倒的に評価が低く、使うのをやめました。

調べたところ、評価の良いオープンソースを見つけたので、今回はこちらを使用することにします。

まずは、最新の unitypackage をダウンロードしてください。

ダウンロードできたら、プロジェクトにインポートします。

sign-in-with-apple

これができたら、次はPlayFab 側の処理を書いていきましょう。

Apple アカウントをリンクする種類

リンクする方法は、「すでに PlayFab のアカウントを作成しているかどうか」で異なります。

まだ PlayFab のアカウントを作成していない場合は、アカウントを作成すると同時に Apple とリンクします。

これはゲームに一度もログインしたことがない人のための処理ですね。

一方で、一度はログインしたことがあるけど、あとで Apple とリンクする場合は、リンクする専用の処理を呼び出します。

ということで、実際の処理を見てきましょう。

PlayFab 側の呼び出し処理

まずは、Login With Apple から見てみます。

public static void LoginWithApple(byte[] identityToken)
{
    PlayFabClientAPI.LoginWithApple(new LoginWithAppleRequest
    {
        CreateAccount = true,
        IdentityToken = Encoding.UTF8.GetString(identityToken),
        TitleId = PlayFabSettings.TitleId
    }
    , result =>
    {
        Debug.Log("Login With Apple Success!!");
    }
    , error => { Debug.Log(error.GenerateErrorReport()); });
}

すごくシンプルなのですが、1つだけ解決にかなり時間をかけたところがあります。

それが以下の部分。

IdentityToken = Encoding.UTF8.GetString(identityToken),

PlayFab 側の IdentityToken は JWT の文字列で渡す必要があるのですが、オープンソース内部で保持されているのは、Base64 byte配列でした。

この byte配列を JWT の形式に変換する処理が、上記というわけですね。

JWT の話
ペンギンくん
ペンギンくん
そもそも、JWT って何なのさ。

JWTは「Json Web Token」の略で、「ジョット」と読むそうです。(読めない)

私も深いところまでは理解できていませんが、簡単にいうと

  • クライアント側で生成できない、複雑な文字列
  • 文字列を解析して、内容を検証することができる

という感じです。

さらに詳しく知りたい人は、JWTの概要と使い所も参照してみてください。

リンクする専用の処理も同様で、特に解説は不要でしょう。

public static void LinkApple(byte[] identityToken)
{
    PlayFabClientAPI.LinkApple(new LinkAppleRequest
    {
        IdentityToken = Encoding.UTF8.GetString(identityToken)
    }
    , result =>
    {
        Debug.Log("Link Apple Success!!");
    }
    , error => { Debug.Log(error.GenerateErrorReport()); });
}

リンクする場合は、Startメソッドなどであらかじめログインしておく必要がありますが、ここでは割愛します。

PlayFab 側の実装はこれで完了です。

オープンソースへの組み込み

先ほど作成した処理を、ログイン成功後の処理に差し込んであげれば準備は完了です。

MainMenu.cs
private void AttemptQuickLogin()
{
    var quickLoginArgs = new AppleAuthQuickLoginArgs();
    
    // Quick login should succeed if the credential was authorized before and not revoked
    this._appleAuthManager.QuickLogin(
        quickLoginArgs,
        credential =>
        {
            // If it's an Apple credential, save the user ID, for later logins
            var appleIdCredential = credential as IAppleIDCredential;
            if (appleIdCredential != null)
            {
                PlayerPrefs.SetString(AppleUserIdKey, credential.User);

                // この1行を追加!!
                PlayFabController.LoginWithApple(appleIdCredential.IdentityToken);
                // この1行を追加!!
            }

            this.SetupGameMenu(credential.User, credential);
        },
        error =>
        {
            // If Quick Login fails, we should show the normal sign in with apple menu, to allow for a normal Sign In with apple
            Debug.LogWarning("Quick Login Failed " + error.ToString());
            this.SetupLoginMenuForSignInWithApple();
        });
}

IAppleIDCredential で持っている、IdentityToken を渡してあげるのがポイントです。

ビルドして実行

実行すると、以下のように画面が変わっていきます。

初期画面
sign-in-with-apple
認証
sign-in-with-apple
結果
sign-in-with-apple

ユーザー名やメールアドレスなどは隠していますが、最後の画面が出ればOKです。

また、PlayFab の管理画面では、先ほどの「Username」が紐付いていることが確認できます。(塗りつぶしたのでわかりにくい)

sign-in-with-apple

ひと通りの流れとしては以上です。

トークンの中身について

ここからは、アカウントに紐付けるトークンが正しいか検証する方法について解説していきます。

公式の開発ドキュメントによると、トークンでは以下のことを確認すべきと言っています。

トークンで確認すべきこと
  • サーバーの公開鍵を使用して JWS E256 署名を確認
  • nonce 認証を確認
  • iss フィールドが「https://appleid.apple.com」であることを確認
  • aud フィールドが開発者のものであることを確認
  • 時刻が exp トークンの値より前であることを確認

aud とか exp とかについては、公式の「Generate and validate tokens」で解説されています。

しかし、実際は少し違うかな?と感じたので以下にまとめてみました。

kid 「86D88Kf」固定
alg 「RS256」固定
iss 「https://appleid.apple.com」固定
aud バンドルID
exp トークンの有効期限(エポック秒)
iat トークンが発行された時刻(エポック秒)
sub ユーザー名
c_hash 認証コードのハッシュ値
email Emailアドレス(どこのアドレスかは謎)
email_verified Emailが認証されたか
is_private_email private なアドレスかどうか(謎)
auth_time 認証された時刻(iat と同じでは?)
nonce_supported nonceのサポートがされているか
上記の通り、公式ドキュメントには載っていなかった項目がたくさんありました。

ちなみに、kid は https://appleid.apple.com/auth/keys から取得されていると思われます。

デバッグで JWT の生データを取り、jwt.ioというサイトで見てみると、以下のように中身を確認することができます。

sign-in-with-apple

こう見ると、ちゃんと中身が入っていることが確認できますね。

具体的な値を確認すると、exp(有効期限)は、ちゃんと iat(発行時刻)の10分後に設定されていました。

サイト上でマウスカーソルを合わせるとツールチップで値がわかるので、実際に確認してみてください。

トークンを検証する方法

ここからは、実際にトークンを検証する方法について解説していきます。

試しに、「aud フィールドが開発者のものであることを確認する」というケースを見てみましょう。

PlayFab の管理画面で、うっかり違うバンドルIDを入力してしまったとします。

sign-in-with-apple

すると、PlayFab と連携する際に以下のエラーが出るようになっています。

Audience validation failed. Audiences: 'com.nekojoker.signinwithapple'.
Did not match: validationParameters.ValidAudience: 'com.nekojoker.signinwithapple1234’.

つまり、ある程度は PlayFab 側でトークンを検証してくれている、ということがわかりますね。

全部を確認したわけではありませんが、そこまで厳密にチェックをしなくてもよさそうです。

とはいえ、念のため自前でチェックしたい!

という人もいるかと思いますので、どうやったらチェックができそうかも検証してみました。

ここからは、具体的にチェックするにはどうしたらいいのかについて解説していきます。

NuGet の導入

JWT はそのままでは中身の解析ができないので、解析できる形式に変換して上げる必要があります。

Microsoft からライブラリが提供されているので、今回はそれを使用していきます。

まずは、NuGet を Unity で使いたいので、専用のパッケージをインポートします。

以下からダウンロードしてください。

ダウンロードができたら、インポートしましょう。

sign-in-with-apple

そのあと、「Nuget > Manage NuGet Packages」と進んでいきます。

sign-in-with-apple

続いて、System.IdentityModel.Tokens.Jwt をインストールしていきます。

  1. 「jwt」と入力する
  2. 右の Search ボタンを押す
  3. Install ボタンを押す
sign-in-with-apple

これでモジュールを使用する準備が整いました。

JWT を解析する

インストールした System.IdentityModel.Tokens.Jwt の使い方についてです。

上の方でまとめた alg や kid を値として取り出すことができれば、そこから解析ができます。

以下の例は、それぞれの値を取り出す処理の例です。

public void OutputJwt()
{
    // IdentityToken をもってくる処理は割愛
    var utf8Str = Encoding.UTF8.GetString(appleIdCredential.IdentityToken);
    var handler = new JwtSecurityTokenHandler();
    var tokenS = handler.ReadToken(utf8Str) as JwtSecurityToken;

    tokenS.Claims.ToList().ForEach(x => Debug.Log(x.Type.ToString() + ":" + x.Value));
}

この JsonSecurityTokenHandler というのが、JWT をうまいこと読み込んでくれるクラスです。

実際に実行した結果が以下になりました。

sign-in-with-apple

一つずつ値を取り出すことができたので、いろいろと検証はできそうですね。

もし検証するなら、サーバー処理としたほうが確実かと思います。

最後に

Sign in with Apple を PlayFab と統合する方法について解説しました。

実装が必須になっているわりに、情報が少なく難易度も高い気がします。

私もまだまだ理解が足りない部分があるので、記事内容で変なところがあれば教えていただけると嬉しいです。

また、この記事で紹介しきれなかった点や、さらに詳しい情報は以下のサイトで学習できるので、合わせてご覧ください。

かなり調べて厳選したサイトなので、必ず役に立つはずです。

この記事で少しでも Sign in with Apple がスムーズに実装できる助けになれば幸いです。

PlayFab の書籍も好評発売中!
playfab-book

PlayFab のことをもっと皆さんに知ってもらいたくて、合計500ページ以上にもなる書籍を5冊に分けて執筆しました。

私の知識をすべて詰め込んでいるので、ゲーム開発をさらに加速させたい方はぜひご覧ください。

POSTED COMMENT

  1. ジョナサン より:

    このチュートリアルに従ってAppleでログインを実装することはできません。理解を深めるために、ソースコードを共有していただけますか?

ねこじょーかー へ返信する コメントをキャンセル

メールアドレスが公開されることはありません。