> ## 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.

# Inicios de sesión cifrados

> Habilite el cifrado personalizado para las llamadas a la API de inicio de sesión del cliente de PlayFab para proteger las cargas de autenticación y reforzar la seguridad de la aplicación contra manipulaciones.

PlayFab le permite reforzar la seguridad de la aplicación protegiendo determinadas llamadas a la API de cliente con cifrado personalizado. En este tutorial se muestra cómo habilitar el cifrado para el cliente.

El método que usaremos permite proteger *cualquier* llamada a la API de inicio de sesión. Como el proceso es *siempre* similar, solo mostramos cómo proteger *un* método concreto, `LoginWithCustomID`.

<Info>
  El cifrado de inicio de sesión está pensado para usarse con *todos* los jugadores desde la creación del título, o no usarse en absoluto. *No* es una característica que se pueda habilitar en una fecha posterior. Debe usarla desde el *principio* o no usarla en absoluto. En particular, los jugadores *cifrados* nunca podrán iniciar sesión *sin cifrar*, y los jugadores *no cifrados* nunca podrán convertirse en jugadores *cifrados*.
</Info>

En esta guía haremos lo siguiente:

1. Crear un secreto compartido de jugador.
2. Introducir una regla de directiva de API para habilitar la protección en un método determinado.
3. Cambiar el cliente para usar una clave compartida de jugador con el fin de recuperar la clave pública del título y cifrar la carga.

<Note>
  PlayFab hace la siguiente declaración de exención de responsabilidad: "Todas nuestras llamadas a la API ya están cifradas de forma segura conforme a los estándares modernos, y el cifrado estándar de las llamadas a la API es todo lo que la mayoría de los clientes necesitan. Esta característica representa una capa *adicional* de seguridad diseñada para dificultar que los jugadores usen un cliente no autorizado. *No* es infalible: simplemente aumenta el nivel de dificultad para los hackers. Para la mayoría de los desarrolladores, el ligero aumento de seguridad no compensará el esfuerzo adicional necesario".
</Note>

## Creación de un secreto compartido de jugador

La API de administración de PlayFab expone un método para administrar los secretos compartidos de jugador.

<Note>
  La creación de un nuevo secreto compartido con un nombre determinado invalidará la clave existente con el mismo nombre, si la hay. Además, puede tener *varios* secretos compartidos registrados con nombres diferentes.
</Note>

Ejecute el código siguiente para agregar un secreto compartido de jugador al título.

```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);
}
```

Para ejecutar este código, necesita una clave secreta de desarrollador. Para obtener más información sobre las claves secretas, consulte [Administración de claves secretas](/services/playfab/live-service-management/gamemanager/secret-key-management).

Esta aplicación debería imprimir un secreto compartido de jugador recién creado. *Asegúrese de guardarlo*. Si se pierde, tendrá que generar un nuevo secreto ejecutando la aplicación de nuevo.

El secreto tiene este aspecto:

`QC953WQ3TU6ZJTZMAT1FNJQIKR92FPUQTISW4Q6WD8SY841MQQ`

## Actualización de la directiva

Ya tenemos creado un nuevo secreto compartido. Ahora debemos indicar a PlayFab qué llamadas a la API se deben proteger.

Ejecute el código que se muestra a continuación para proteger la llamada a la API `LoginWithCustomId` y *desproteger* el resto de las llamadas a la 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");
}
```

## Configuración del cliente

Ahora que la directiva está actualizada, ya no puede llamar simplemente a la API `LoginWithCustomID`. Considere el código que se muestra a continuación.

```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);
}
```

Normalmente, esto iniciaría la sesión del usuario sin problemas. Sin embargo, *ahora* esta llamada a la API está *protegida*, y el código producirá un error `Not Authorized` (que no debe confundirse con `Not Authenticated`).

Debemos modificar el cliente para cifrar correctamente la carga de la llamada. Esto se realiza en 2 pasos:

1. Usar el secreto compartido de jugador para capturar la clave pública del título.
2. Usar la clave pública del título para cifrar la carga.

El código que se muestra a continuación ilustra este proceso.

```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);
}
```

Una vez que ejecute el código, debería poder iniciar sesión. Tenga en cuenta que, una vez creado un secreto compartido de jugador, debe codificarse de forma rígida en el código del cliente, ya que *no hay forma* de capturarlo ni solicitarlo mediante ninguna llamada a la API.


## Related topics

- [Inicio de sesión único](/es/services/xbox-services/fundamentals/s2s-auth-calls/custom-service-config/single-sign-on/index.md)
- [Configuración del inicio de sesión único en Partner Center](/es/services/xbox-services/fundamentals/s2s-auth-calls/custom-service-config/single-sign-on/live-single-sign-on.md)
- [Inicio de sesión de usuario](/es/services/xbox-services/fundamentals/identity/auth/live-authentication-nav.md)
- [Inicio de sesión del jugador](/es/services/playfab/identity/player-identity/login/index.md)
- [Inicios de sesión del jugador](/es/services/playfab/player-progression/player-data/player-logins.md)
