カスタム認証

デフォルトではアプリケーションには認証メカニズムがなく、匿名ユーザーの接続が許可されます。 Photonアプリケーションにはカスタム認証を実装するオプションがあります。

Photonでのカスタム認証は非常に柔軟性が高く、 サードパーティーの認証プロバイダや完全にカスタマイズされたソリューションに対応しています。

弊社はGitレポジトリで認証プロバイダの実装例を提供しています。 ぜひレポジトリをフォークし、プルリクエストを送信してください。 GitHubでソースを確認してください。

Contents

認証フロー

以下に、認証プロセスの一般的なフローを記載します。

Photon Cloud: Custom Authentication Flow Diagram
カスタム認証フロー図

  1. クライアントは、使用する認証プロバイダについての情報や必要な認証データを Connect()を使用してPhoton Serverに渡します。
  2. Photon Serverは、必要な認証プロバイダをアプリケーションに取得し、以下の手順のいずれかへと進みます。
    • 認証プロバイダ設定を検出された場合 -> 認証は手順3に進みます。
    • 認証プロバイダ設定が検出されない場合 -> アプリケーションの設定に応じて、クライアントは接続を許可されるか、または拒否されます
  3. Photon Serverは Connect()で渡された認証情報で、認証プロバイダを呼び出します。
    • 認証プロバイダがオンラインの場合 -> 認証は手順4に進みます。
    • 認証プロバイダがオフラインの場合 -> 該当するプロバイダの設定に応じて、クライアントは接続を許可されるか、または拒否されます。
  4. 認証プロバイダが認証情報を処理し、Photon Serverに結果を返します。
  5. 認証の結果に応じて、クライアントは正常に認証されるか、または拒否されます。

Back To Top

Photon Cloudにセットアップ

Photonアプリケーションのダッシュボードから、すべての認証プロバイダをセットアップできます。 アプリケーションの詳細ページに進み、カスタム認証セクションを開きます。

カスタム認証を設定する場合には、変更が反映されるまでにしばらく時間がかかる点に留意してください。

Back To Top

認証プロバイダを追加

認証プロバイダの設定は容易で、 Photonアプリケーションのダッシュボードから数秒間で実行できます。

Photon Cloud: Custom Authentication Creation
カスタム認証プロバイダの作成

スクリーンショットで表示されているとおり、認証サービスがオンラインでない場合や、その他の何らかの理由で作動していない場合にクライアントを拒否する必要があるか、認証URLを入力して決定することができます。 また、各リクエストの認証サービスにクエリ文字列パラメータとして、送信するキー/値のセットを任意で追加できます。

ベストプラクティスは、クライアントに「不可視」で「機密」かつ静的なキー/値のセットをダッシュボードから設定することです。 例:
  • リクエストが、実際にいずれかのPhoton Serverから来ていることを確認するAPIパブリックキー
  • 今後の変更をさらに適切に処理するための、カスタム認証のAPIバージョン。

また、設定された認証プロバイダに関係なく、アプリケーションに接続しようとする匿名のクライアントを許可または拒否することもできます。 デフォルトではこの機能は有効化されているため、認証されているかどうかに関わらず、内部的にはすべてのクライアントがアプリケーションに接続することができます。Photon アプリケーションのダッシュボード内のアプリケーションの詳細ページ、認証セクションで確認してください。 Photon Applications' Dashboardのアプリケーション詳細ページの認証セクションで確認できます。 このオプションは、少なくとも1つの認証プロバイダーを追加した場合にのみ表示されます。 認証プロバイダーが設定されていない場合、デフォルト値(非表示)で非表示になります。

Photon Cloud: Custom Authentication, Allow Anonymous Clients
カスタム認証を使用して、匿名のクライアントを許可

Back To Top

認証プロバイダをアップデートまたは削除

また、アプリケーションの詳細のページから、既存の認証プロバイダを選択して編集することができます。 編集フォームから、すべての設定を更新するか、または認証プロバイダを完全に削除することができます。

Photon Cloud: Custom Authentication Editing
既存のカスタム認証プロバイダをアップデートまたは削除

Back To Top

実装

Photon CloudにFacebook認証を使用している場合には、この部分を飛ばしてください。

Back To Top

クライアント側

クライアント側ではLoadBalancing APIでカスタム認証を処理します。 関連するパラメータと対象のカスタム認証サービスの設定は、1回のみ必要です。 セットアップが完了すると、接続してその後のエラーが処理されます。

:

プレイヤーからPhoton Boltループに認証資格情報を渡すには、 PhotonPlatformを初期化して、Photon.Realtime.AuthenticationValuesのインスタンスを渡します。 Boltはこの情報をPhoton Cloudに送信し、認証サーバーからのデータを処理します。 以下は、新しい「PhotonPlatform」を作成して「AuthenticationValues」を渡す方法を示すサンプルコードです。 ピアをサーバーまたはクライアントとして開始する前に、UdpPlatformを設定する 必要があります

using Photon.Realtime;
using UdpKit.Platform;

public class Menu : Bolt.GlobalEventListener
{
    public void StartServer(string user, string password)
    {
        SetupPlatform(user, password);
        BoltLauncher.StartServer();
    }

    public void StartClient(string user, string password)
    {
        SetupPlatform(user, password);
        BoltLauncher.StartClient();
    }

    private void SetupPlatform(string user, string password)
    {
        var auth = new AuthenticationValues();

        auth.AuthType = CustomAuthenticationType.Custom;
        auth.AddAuthParameter("user", user);
        auth.AddAuthParameter("pass", password);
        auth.UserId = "my local user ID";

        var platform = new PhotonPlatform(new PhotonPlatformConfig()
        {
            AuthenticationValues = auth
        });

        BoltLauncher.SetUdpPlatform(platform);
    }
}

単純化するため、このスニペットでは非常に基本的なパスワードベースの認証証明書を選択しました。 結果的に、クエリ文字列は以下のとおりとなります:?user={user}&pass={pass}。 一般的に、これらの証明書は値のセットです。最初の値は固有の識別子(ユーザーID、ユーザー名、メールなど)で、もう1つの値は「信頼性の証明」(ハッシュされたパスワード、キー、秘密、トークンなど)です。 セキュリティ上の理由から、プレーンテキストのパスワードは送信しないでください。

Back To Top

認証オペレーション

認証オペレーションによって、認証値が実際にサーバーに送信されます。 これは通常、クライアントコードで直接使用されるのではなく、APIによって使用されます。

留意すべき点は:サーバーへの接続には、常に認証ステップが含まれる点です。 まず、オペレーションは暗号化されたオペレーションとして実際の認証値を送信します。 後に発生するサーバー切替では、Photonは暗号化され、かつ自動的に使用される独自のトークンを提供します。

Back To Top

サーバー側

Webサーバーが認証リクエストを受信した場合、クエリパラメータを確認し有効化する必要があります。 たとえば、現在の証明書とデータベース内に保存された既存の証明書を比較できます。

受信したパラメータが見つからない場合や無効の場合、返される結果は{ "ResultCode": 3}となります。

有効化が完了すると、以下が返されます:

  • 成功: { "ResultCode": 1, "UserId": <userId>}
  • 失敗: { "ResultCode": 2}

Back To Top

高度な機能

ユーザー認証以外にも、認証プロバイダーから補足情報を返すことができます。 この設定をおこなうには、ユーザーは「認証者」の役割を担うWebサービスとクライアント間にプロトコルのようなものを設定する必要があります。

Back To Top

サーバーにデータを送信

もっとも簡単かつ簡潔なのは、「全か無か」という方式です: クライアントに変数の静的な数を返すかどうか、選択してください。 一部のユースケースでは、クライアントのリクエストへの「オンデマンド」ベースでWebサービスがデータを返す、さらに複雑なアプローチが必要になります。 このサブセクションでは、クライアントからWebサービスにデータを送信する方法を説明します。 このデータは、認証に必要な証明書や補足のパラメータです。 補足のパラメータは、認証レスポンスで返されるサーバー側から利用可能になるデータをリクエストするのに使用されます。 これは非常に有用で、余分なAPIコールが不要となりログインワークフローが単純化されます。

まれに、認証が多くのデータを必要とする場合があります。 一方、ほとんどのWebサーバーにはクエリ文字列で使用される文字数の上限や、URLの長さの閾値があります。 このため、Photonではクライアントから明示的に AuthenticationValues.AuthPostDataフィールドに値を設定してHTTPメソッドをPOSTに変更できるようにしました。 後者には、string型またはbyte[]型を設定することが可能です。 AuthenticationValues クラスは、型ごとにそれぞれ2つのセッターを提供します。

これが要件や制約となる場合があるため、WebサービスからPOSTメソッドとして認証リクエストを受信したいユーザー向けにPOSTメソッドオプションも提供されています。

つまり、認証パラメータを送信する際にはクエリ文字またはPOSTデータ、もしくはその両方を自由に使用できます。 下表に、設定可能な組み合わせを示します。

AuthPostData AuthGetParameters HTTPメソッド
null * GET
空の文字列 * GET
文字列 (nullではなく、空ではない) * POST
バイト[] ( nullではない、空も可能) * POST

Back To Top

クライアントにデータを返送

Photon ServerはクライアントとWebサービス間のプロキシなので、Photon Serverが処理できる変数に留意してください。

Photon Serverが受信するすべてのHTTP受信レスポンスと同様に、WebサーバはResultCodeと任意のMessageを含むJSONオブジェクトを返す必要があります。 また、Photon Serverが認証時にWebサービスから受信可能なものを以下に記載します:

  • UserId: これは、認証自体のパラメータとして使用することができますが、クライアント側からリクエストすることも可能です。  Photon Serverが受信すると必ずクライアントに転送されます。AuthenticationValues.UserIdが最初に設定されていない場合は、  ランダムに生成されたUserIdがクライアントに返送されます。 これによってクライアントのUserIdの値が上書きされ、その後変更できなくなります。
  • Data:クライアントに返すべきその他の値が含まれているJSONオブジェクト。 ネストされた配列やオブジェクトはサポートされません。

ResultCodeは唯一必須となっている戻り変数で、他の変数は任意です。 以下の表に、Webサーバーが返すことが可能なものを示します。

ResultCode 説明 UserId Nickname AuthCookie Data
0 認証が不完全、データのみが返されました*
1 認証が成功。 (任意) (任意) (任意) (任意)
2 認証が失敗。証明書が誤っています。
3 無効なパラメータ。

*: インスタンスまたは2段階の検証にOAuth 2.0を実装するのに有用です。

Back To Top

クライアントからデータを読み込み

Photon Boltを起動すると、Photon Cloudに自動的に接続し、前述の認証プロセスを実行します。 このプロセスが完了すると、 BoltStartDoneが呼び出されます。この時点で、BoltMatchmaking.CurrentMetadataプロパティを確認することにより、サーバーから送信されたすべてのカスタム情報を読み取ることができます。 これはPhotonインテグレーションによって生成され、使用できるようになります。

以下は、レスポンスから返された値を取得する方法を示すコードスニペットです:

using System.Collections.Generic;
using Bolt.Matchmaking;
using Bolt.Utils;
using Photon.Realtime;
using UdpKit.Platform;

public class Menu : Bolt.GlobalEventListener
{
    // ...

    public override void BoltStartDone()
    {
        var meta = BoltMatchmaking.CurrentMetadata;

        // Read all custom data sent from your auth server
        Dictionary<string, object> customData;
        if (meta.TryGetValue("Data", out customData))
        {
            var text = "";

            foreach (var item in customData)
            {
                text += string.Format("{0} : {1}\n", item.Key, item.Value);
            }

            BoltLog.Info(text);
        }

        // Read the UserId of the local player
        string userID;
        if (meta.TryGetValue("UserId", out userID))
        {
            BoltLog.Info("UserID: {0}", userID);
        }

        // Read the Nickname of the local player
        string nickName;
        if (meta.TryGetValue("Nickname", out nickName))
        {
            BoltLog.Info("Nickname: {0}", nickName);
        }

        // Your usual BoltStartDone behaviour: setup game server or join a session
    }
}

Back To Top

データ型の変換

このセクションでは、Photonクラウドとウェブサービスの間で交換されるデータ型のみが説明されています。クライアントとPhotonサーバ間のデータ型の詳細はPhotonページのシリアル化を参照してください。

Photon Cloud -> ウェブサービス

C# / .NET (Photonが対応するタイプ) JavaScript / JSON
byte number
short
int
long
double
bool bool
string string
byte[] (byte array length < short.MaxValue) string (Base64 encoded)
T[] (array of supported type T, length < short.MaxValue) array
Hashtable (対応されているタイプの, カウント < short.MaxValue, Photon実装が望ましい) object
Dictionary (対応されているタイプのキーや値, カウント < short.MaxValue) object
null null

Back To Top

サンプルリクエストデータ(タイプは連結されます)

Photonクラウドから送信:

ウェブサーバによって読み込み:

Back To Top

ウェブサービス - >Photon Cloud

各JavaScript/JSONタイプをC#/.Netの同等のものに照らし合わせる表:

JavaScript / JSON C# / .Net
object Dictionary
array object[] (array of objects)
number (integral) long
number (floating) double
string string
boolean bool
null (タイプではない) null
undefined(送信時) null

Back To Top

サンプルのレスポンスデータ(タイプは連結されています)

Webサーバーから送信:

Photon Cloudから読み込み:

Back To Top

トラブルシューティング

カスタム認証が失敗すると、 BodStartFailedコールバックが引数値としてUdpConnectionDisconnectReason.Authenticationでトリガーされます。 前述したように、Boltを起動しようとすると認証プロセスが発生します。 サーバーがプレイヤーの認証資格情報を無効にすると、Boltは起動に失敗し、次の方法でこれを報告します。

public override void BoltStartFailed(UdpConnectionDisconnectReason disconnectReason)
{
    Debug.LogErrorFormat("BoltStartFailed. Reason: {0}", disconnectReason);
}

ダッシュボードで設定した認証URLがHTTPエラーを返す場合、Photonサーバーは負荷を避けるため短い時間、認証コールを一時停止します。 URLを設定またはテストする際には、この「バックオフ」時間を考慮するようにしてください。

Back To Top

ベストプラクティス

  • クライアント側からではなくダッシュボードで、静的なキー/値のセットを設定してください。 これにより、結果のクエリ文字列でキーが重複するのを防ぎます。
  • セキュリティ上の理由から、プレーンテキストのパスワードを認証パラメータとして送信しないでください。
  • Photonダッシュボードでクエリ文字列パラメータを設定することを推奨します。 これによって、リクエストの起源を確認できます。
  • パラメータの設定にはAuthenticationValuesメソッドを使用し、AuthGetParametersの値を直接変更しないでください。 こうすることで、クエリ文字列の変形を防ぐことができます。
  • 認証プロバイダから返される結果には、特にエラーの場合に備えて読解可能なメッセージを含める必要があります、 これにより、デバッグの手間が大幅に軽減されます。

Back To Top

ユースケース例:古いクライアントバージョンをブロック

カスタム認証を使用して、古いバージョン(または予期せぬバージョン)を使用しているクライアントから受信した接続を拒否することができます。この場合、特定のエラーを返してユーザーにアップデートを依頼することが可能です。 これを実現するには、カスタム認証リクエスト内で該当のバージョンを送信する必要があります。クエリ文字列パラメータでおこなうか、またはPOSTデータ引数としておこなうかはユーザー自身が決めることができます。 以下の例では、クエリ文字列パラメータを使用しています:

private void SetupPlatform(string user, string password)
{
    var version = BoltNetwork.CurrentVersion;
    var auth = new AuthenticationValues();

    auth.AuthType = CustomAuthenticationType.Custom;
    auth.AddAuthParameter("version", version);

    var platform = new PhotonPlatform(new PhotonPlatformConfig()
    {
        AuthenticationValues = auth
    });

    BoltLauncher.SetUdpPlatform(platform);
}

カスタム認証のURLがhttps://example.comの場合、リクエストはhttps://example.com?version={version}として送信されます。 認証プロバイダ実装から受信するバージョンを取得し、比較してください。 バージョンが許可された場合、{ "ResultCode": 1}を返してください。 もし許可されない場合には、任意のカスタム値(1以外)でResultCodeを返し、できる限りメッセージも送信してください。 例: { "ResultCode": 5, "Message": "Version not allowed."}。

ドキュメントのトップへ戻る