> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 暗号化されたログイン

> PlayFab クライアント ログイン API 呼び出しでカスタム暗号化を有効にして、認証ペイロードを保護し、改ざんに対するアプリケーションのセキュリティを強化します。

PlayFab では、特定のクライアント API 呼び出しをカスタム暗号化で保護することで、アプリケーションのセキュリティを強化できます。このチュートリアルでは、クライアントの暗号化を有効にする方法を説明します。

ここで使用する方法では、*任意の* ログイン API 呼び出しを保護できます。プロセスは *常に* 類似しているため、ここでは *1 つの* 特定のメソッド `LoginWithCustomID` を保護する方法のみを示します。

<Info>
  ログイン暗号化は、タイトル作成後の *すべての* プレイヤーに対して使用するか、まったく使用しないかのどちらかを意図しています。これは、後から有効にできる機能では *ありません*。*最初から* 使用するか、まったく使用しないかを選択する必要があります。特に、*暗号化された* プレイヤーは *暗号化されていない* 方法でログインできず、*暗号化されていない* プレイヤーは *暗号化された* プレイヤーになることはできません。
</Info>

このガイドでは、次のことを行います。

1. Player Shared Secret を作成します。
2. 特定のメソッドで保護を有効にするための API ポリシー ルールを導入します。
3. クライアントを変更して、Player Shared Key を使用してタイトル公開キーを取得し、ペイロードを暗号化するようにします。

<Note>
  PlayFab は次のような免責事項を示しています: 「すべての API 呼び出しは既に最新の標準で安全に暗号化されており、標準の API 呼び出しの暗号化はほとんどのお客様にとって必要なすべてです。この機能は、プレイヤーが不正なクライアントを使用することをより困難にするために構築された、*追加の* セキュリティ レイヤーを表します。これは万全ではありません - ハッカーにとっての難易度のバーを上げるだけです。ほとんどの開発者にとって、わずかなセキュリティ向上は、追加で必要な労力に見合いません。」
</Note>

## Player Shared Secret の作成

PlayFab Admin API では、Player Shared Secret を管理するメソッドが公開されています。

<Note>
  特定の名前で新しい共有シークレットを作成すると、同じ名前の既存のキーがあればそれを上書きします。また、異なる名前で登録された *複数の* 共有シークレットを持つこともできます。
</Note>

次のコードを実行して、タイトルに Player Shared Secret を追加します。

```csharp theme={null}
PlayFabSettings.staticSettings.DeveloperSecretKey = "__DEVELOPER_KEY__";
PlayFabSettings.staticSettings.TitleId = "__TITLE_ID__";
var response = await PlayFabAdminAPI.CreatePlayerSharedSecretAsync(new CreatePlayerSharedSecretRequest()
{
    FriendlyName = "__KEY_NAME__"
});

if (response.Error != null)
{
    Console.WriteLine(response.Error.GenerateErrorReport());
}
else
{
    Console.WriteLine(response.Result.SecretKey);
}
```

このコードを実行するには、開発者シークレット キーが必要です。シークレット キーの詳細については、[シークレット キーの管理](/services/playfab/live-service-management/gamemanager/secret-key-management) を参照してください。

このアプリケーションは、新しく作成された Player Shared Secret を出力するはずです。*これを必ず保存してください*。失くした場合は、アプリケーションを再度実行して新しいシークレットを生成する必要があります。

シークレットは次のようになります。

`QC953WQ3TU6ZJTZMAT1FNJQIKR92FPUQTISW4Q6WD8SY841MQQ`

## ポリシーの更新

新しい共有シークレットが作成されました。次に、保護する API 呼び出しを PlayFab に指示する必要があります。

以下のコードを実行して、`LoginWithCustomId` API 呼び出しを保護し、他の API 呼び出しの保護を *解除* します。

```csharp theme={null}
// Set development key and title id
PlayFabSettings.DeveloperSecretKey = "__DEVELOPER_KEY__";
PlayFabSettings.TitleId = "__TITLE_ID__";

public static async Task SetApiPermission(bool restrictCustomId)
{
    // The first statement denies every call to LoginWithCustomID that is not properly encrypted
    var filterCustom = new PermissionStatement
    {
        // Statement effects any action
        Action = "*",
        // Filter the case where there is no signature and payload is not encrypted
        ApiConditions = new ApiCondition()
        {
            HasSignatureOrEncryption = Conditionals.False
        },
        Comment = "Deny every request to LoginWithCustomID that is not properly encrypted",
        // Specify the resource name
        Resource = "pfrn:api--/Client/LoginWithCustomID", // Resource name
        // Deny any of such requests
        Effect = EffectType.Deny,
        // For any user
        Principal = "*"
    };
    // The second statement allows every other API call
    var filterNothing = new PermissionStatement()
    {
        // Statement effects any action
        Action = "*",
        Comment = "Allow the rest API calls",
        // For any resource name
        Resource = "pfrn:api--*",
        // Allow any request
        Effect = EffectType.Allow,
        // For any user
        Principal = "*"
    };

    // Update the policy
    var request = new UpdatePolicyRequest()
    {
        // ApiPolicy controls access to API methods
        PolicyName = "ApiPolicy",
        // In this example we overwrite the policy. Consider appending to the existing policy instead.
        OverwritePolicy = true,
        // Introduce policy statements
        Statements = new List<PermissionStatement> { filterNothing }
    };
    if (restrictCustomId)
        request.Statements.Add(filterCustom);
    var result = await PlayFabAdminAPI.UpdatePolicyAsync(request);

    // Handle possible errors
    if (result.Error != null)
        Console.WriteLine(result.Error.GenerateErrorReport());
    else
        Console.WriteLine("Policy updated");
}
```

## クライアントのセットアップ

ポリシーが更新されると、`LoginWithCustomID` API を単に呼び出すことはできなくなります。以下のコードを検討してください。

```csharp theme={null}
var result = await PlayFabClientAPI.LoginWithCustomIDAsync(new LoginWithCustomIDRequest()
{
    CreateAccount = true,
    CustomId = "Some_Custom_Id"
});

if (result.Error != null)
{
    Console.WriteLine(result.Error.GenerateErrorReport());
}
else
{
    Console.WriteLine(result.Result.PlayFabId);
}
```

通常、これは問題なくユーザーをログインさせます。しかし、*現在では* この API 呼び出しは *保護されており*、コードは `Not Authorized` エラー (`Not Authenticated` と混同しないでください) を返します。

呼び出しペイロードを適切に暗号化するために、クライアントを変更する必要があります。これは 2 段階で行います。

1. Player Shared Secret を使ってタイトル公開キーを取得します。
2. タイトル公開キーを使ってペイロードを暗号化します。

以下のコードは、これを示しています。

```csharp theme={null}
public static async Task DoEncryptedLogin()
{
    Console.WriteLine("Begin DoEncryptedLogin");

    // Use Player Shared Secret to get Title Public Key
    var titleKeyResult = await PlayFabClientAPI.GetTitlePublicKeyAsync(new GetTitlePublicKeyRequest
    {
        TitleId = TITLE_ID,
        TitleSharedSecret = CLIENT_SECRET_KEY
    });

    Console.WriteLine("Encrypt request");
    // Convert public key to bytes
    var cspBlob = Convert.FromBase64String(titleKeyResult.Result.RSAPublicKey);

    // Serialize certain part of the model into string (this will be encrypted).
    var encryptionModel = JsonWrapper.SerializeObject(new LoginWithCustomIDRequest { CustomId = "SOME_PLAYER_ID_ENCRYPTED" });
    string encryptedPayload;

    // RSA encryption
    using (var rsa = new RSACryptoServiceProvider())
    {
        rsa.ImportCspBlob(cspBlob);
        var bytesToEncrypt = Encoding.UTF8.GetBytes(encryptionModel);
        var encryptedBytes = rsa.Encrypt(bytesToEncrypt, false);
        encryptedPayload = Convert.ToBase64String(encryptedBytes);
    }

    // Use encrypted payload to construct a model
    var model = new LoginWithCustomIDRequest
    {
        EncryptedRequest = encryptedPayload,
        PlayerSecret = CLIENT_SECRET_KEY,
        CreateAccount = true
    };

    Console.WriteLine("Call LoginWithCustomIDAsync");
    // Finally execute the call
    var result = await PlayFabClientAPI.LoginWithCustomIDAsync(model);
    Console.WriteLine("LoginWithCustomIDAsync done");
    bool successful = result.Error == null && result.Result != null;
    if (!successful)
        Console.WriteLine(result.Error.GenerateErrorReport());
    else
        Console.WriteLine("Login Successful" + result.Result.PlayFabId);
}
```

コードを実行すると、ログインできるはずです。Player Shared Secret を作成したら、API 呼び出しで取得または要求する *方法がない* ため、クライアント コードにハードコーディングする必要があることに注意してください。


## Related topics

- [MSIXVC2 暗号化モデル](/ja-jp/build/core-features/common/packaging/packaging-encryption-msixvc2.md)
- [Player Encryption サービス](/ja-jp/services/playfab/identity/player-identity/encryption/player-encryption-services.md)
- [ログインの基本とベスト プラクティス](/ja-jp/services/playfab/identity/player-identity/login/login-basics-best-practices.md)
- [MSIXVC2 パッケージング概要](/ja-jp/build/core-features/common/packaging/overviews/packaging-msixvc2-overview.md)
- [複数の PlayFab ログインの処理](/ja-jp/services/playfab/identity/player-identity/login/multiple-logins.md)
