Accès côté serveur aux services de jeux Google Play

Nous vous recommandons d'utiliser PgsGamesSignInClient pour authentifier les joueurs et transmettre leur identité au serveur backend de manière sécurisée. Cela permet à votre jeu de récupérer de manière sécurisée l'identité du joueur et d'autres données sans être exposé à des tentatives de falsification lors de son passage sur l'appareil.

Une fois que le joueur s'est authentifié, vous pouvez demander un code unique à usage unique (appelé code d'autorisation du serveur) au SDK natif des services de jeux Play v2 (bêta), que le client transmet au serveur. Ensuite, sur le serveur, échangez le code d'autorisation du serveur contre un jeton OAuth 2.0 permettant au serveur d'appeler l'API des services de jeux Google Play.

Pour obtenir des conseils supplémentaires sur l'ajout de l'authentification dans vos jeux, consultez Authentification de la plate-forme.

Pour utiliser l'accès hors connexion, procédez comme suit :

  1. Dans la Google Play Console, créez des identifiants pour votre serveur de jeu. Le type de client OAuth pour ces identifiants est "web".
  2. Dans l'application Android : lors de l'authentification de la plate-forme, demandez un code d'autorisation pour les identifiants de votre serveur et transmettez-les lui. Le PgsGamesSignInClient peut demander trois habilitations OAuth 2.0 lorsqu'il demande un accès côté serveur aux API Web des services de jeux Play. Les niveaux d'accès facultatifs sont PGS_AUTH_SCOPE_EMAIL, PGS_AUTH_SCOPE_PROFILE et PGS_AUTH_SCOPE_OPENID. Les deux portées par défaut sont DRIVE_APPFOLDER et GAMES_LITE.
  3. Sur votre serveur de jeu : échangez le code d'autorisation du serveur contre un jeton d'accès OAuth à l'aide des services d'authentification Google, puis utilisez-le pour appeler les API REST des services de jeux Play.

Avant de commencer

Vous devez d'abord ajouter votre jeu dans la Google Play Console, comme décrit dans la section Configurer les services de jeux Google Play.

Créer une application Web côté serveur

Les services de jeux Google Play ne proposent pas de backend pour les jeux Web. Toutefois, un serveur backend est disponible pour le serveur de votre jeu Android.

Si vous souhaitez utiliser les API REST pour les services de jeux Google Play dans votre application côté serveur, procédez comme suit :

  1. Dans la Google Play Console, sélectionnez un jeu.
  2. Accédez à Services de jeux Play > Configuration et gestion > Configuration.
  3. Sélectionnez Add credential (ajouter des identifiants) pour accéder à la page correspondante. Sélectionnez Game server (Serveur de jeu) comme type d'identifiant, puis passez à la section Authorization (Autorisation).
    1. Si votre serveur de jeu dispose déjà d'un ID client OAuth, sélectionnez-le dans le menu déroulant. Après avoir enregistré vos modifications, passez à la section suivante.
    2. Si vous ne disposez d'aucun ID client OAuth pour votre serveur de jeu, vous pouvez en créer un.
      1. Cliquez sur Create OAuth client (Créer un client OAuth), puis sur le lien Create OAuth Client ID (Créer un ID client OAuth).
      2. Vous êtes redirigé vers la page Create OAuth client ID (créer un ID client OAuth) de Google Cloud Platform pour le projet associé à votre jeu.
      3. Remplissez le formulaire, puis cliquez sur "Create" (Créer). Veillez à définir le type d'application sur Web.
      4. Revenez à la section Autorisation de la page d'ajout des identifiants, sélectionnez le client OAuth que vous venez de créer, puis enregistrez vos modifications.

Obtenir le code d'autorisation du serveur

Pour récupérer un code d'autorisation de serveur que votre jeu peut utiliser pour les jetons d'accès sur votre serveur backend :

  1. Appelez PgsGamesSignInClient_requestServerSideAccess à partir du client.
    1. Veillez à utiliser l'ID client OAuth enregistré pour votre serveur de jeu et non l'ID client OAuth de votre application Android.
    2. (Facultatif) Si votre serveur de jeu nécessite un accès hors connexion (accès de longue durée avec un jeton d'actualisation) aux services de jeux Play, vous pouvez définir le paramètre force_refresh_token sur "true".
  2. (Facultatif) Lors de l'authentification, les nouveaux utilisateurs doivent rencontrer un seul écran de consentement pour les habilitations supplémentaires. Une fois l'autorisation acceptée, vous définissez le paramètre PgsAuthScope scopes avec les champs d'application OAuth PGS_AUTH_SCOPE_EMAIL, PGS_AUTH_SCOPE_PROFILE et PGS_AUTH_SCOPE_OPENID. Si les utilisateurs refusent le consentement, seuls les deux niveaux d'accès par défaut DRIVE_APPFOLDER et GAMES_LITE sont envoyés au backend.

    Écran de consentement pour les habilitations OAuth supplémentaires.
    Écran de consentement pour les habilitations OAuth supplémentaires. (cliquez pour agrandir).

     // #include "google/games/pgs_games_sign_in_client.h"
     // 1. Define the Callback
     // This function is called when the server-side access request completes.
     // It provides the authorization code (on success) or an error (on failure).
     void OnServerSideAccessCallback(void* context, PgsError error, const char* serverAuthCode) {
         if (error == PgsError_Success) {
             if (serverAuthCode != nullptr) {
                 __android_log_print(ANDROID_LOG_INFO, "Games",
                     "Received Server Auth Code: %s", serverAuthCode);
                 // Send 'serverAuthCode' to your backend server immediately.
                 // Your server will exchange this code for an OAuth access token.
             }
         } else {
             __android_log_print(ANDROID_LOG_ERROR, "Games",
              "Failed to get server auth code. Error: %d", error);
         }
     }
     // 2. Define the Wrapper Function
     void RequestServerAccess(PgsGamesSignInClient* signInClient) {
         if (signInClient == nullptr) {
             return;
         }
         // This must match the "Web client ID" from your Google Cloud Console
         // (linked to your Play Console Game Server Credential).
         const char* SERVER_CLIENT_ID = "xxxx";
         // Set to 'true' if your server needs a Refresh Token (long-lived access).
         // Set to 'false' if you only need an Access Token (short-lived).
         bool forceRefreshToken = false;
         // Call the API
         PgsGamesSignInClient_requestServerSideAccess(
            signInClient,
            SERVER_CLIENT_ID,
            forceRefreshToken,
            OnServerSideAccessCallback, // The callback defined
            nullptr                     // User context (optional, passed to callback)
         );
     }
     // 3. Example Usage
     void TriggerSignInProcess(PgsGamesClient* gamesClient) {
          // Obtain the Sign-In Client from the main Games Client
          PgsGamesSignInClient* signInClient = PgsGamesClient_getSignInClient(gamesClient);
          RequestServerAccess(signInClient);
     }
     

  3. Envoyez le jeton de code d'autorisation OAuth à votre serveur backend pour qu'il puisse être échangé. L'ID de joueur est validé par les API REST des services de jeux Play, puis authentifié auprès de votre jeu.

Envoyer le code d'autorisation du serveur

Envoyez le code d'autorisation à votre serveur backend pour l'échanger contre des jetons d'accès et d'actualisation. Utilisez le jeton d'accès pour appeler l'API des services de jeux Play au nom du joueur et, éventuellement, stocker le jeton d'actualisation pour acquérir un nouveau jeton d'accès lorsque le jeton existant expirera.

Pour en savoir plus sur le fonctionnement des ID de joueur, consultez ID de joueur de nouvelle génération.

L'extrait de code suivant montre comment implémenter le code côté serveur dans le langage de programmation C++ afin d'échanger le code d'autorisation du serveur contre des jetons d'accès.

Java

/**
 * Exchanges the authcode for an access token credential. The credential
 * is associated with the given player.
 *
 * @param authCode - the non-null authcode passed from the client.
 * @param player   - the player object which the given authcode is
 *                 associated with.
 * @return the HTTP response code indicating the outcome of the exchange.
 */
private int exchangeAuthCode(String authCode, Player player) {
try {

    // The client_secret.json file is downloaded from the Google Cloud
    // console. This is used to identify your web application. The
    // contents of this file shouldn't be shared.

    File secretFile = new File("client_secret.json");

    // If we don't have the file, we can't access any APIs, so return
    // an error.
    if (!secretFile.exists()) {
        log("Secret file : " + secretFile
                .getAbsolutePath() + "  does not exist!");
        return HttpServletResponse.SC_FORBIDDEN;
    }

    GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(
            JacksonFactory.getDefaultInstance(), new
            FileReader(secretFile));

    // Extract the application ID of the game from the client ID.
    String applicationId = extractApplicationId(clientSecrets
            .getDetails().getClientId());

    GoogleTokenResponse tokenResponse =
            new GoogleAuthorizationCodeTokenRequest(
            HTTPTransport,
            JacksonFactory.getDefaultInstance(),
            "https://oauth2.googleapis.com/token",
            clientSecrets.getDetails().getClientId(),
            clientSecrets.getDetails().getClientSecret(),
            authCode,
            "")
            .execute();

    TokenVerifier(tokenResponse);

    log("hasRefresh == " + (tokenResponse.getRefreshToken() != null));
    log("Exchanging authCode: " + authCode + " for token");
    Credential credential = new Credential
            .Builder(BearerToken.authorizationHeaderAccessMethod())
            .setJsonFactory(JacksonFactory.getDefaultInstance())
            .setTransport(HTTPTransport)
            .setTokenServerEncodedUrl("https://www.googleapis.com/oauth2/v4/token")
            .setClientAuthentication(new HttpExecuteInterceptor() {
                @Override
                public void intercept(HttpRequest request)
                        throws IOException {
                        }
            })
            .build()
            .setFromTokenResponse(tokenResponse);

    player.setCredential(credential);

    // Now that we have a credential, we can access the Games API.
    PlayGamesAPI api = new PlayGamesAPI(player, applicationId,
            HTTPTransport, JacksonFactory.getDefaultInstance());

    // Call the verify method, which checks that the access token has
    // access to the Games API, and that the Player ID used by the
    // client matches the playerId associated with the accessToken.
    boolean ok = api.verifyPlayer();

    // Call a Games API on the server.
    if (ok) {
        ok = api.updatePlayerInfo();
        if (ok) {
            // persist the player.
            savePlayer(api.getPlayer());
        }
    }

    return ok ? HttpServletResponse.SC_OK :
            HttpServletResponse.SC_INTERNAL_SERVER_ERROR;

  } catch (IOException e) {
    e.printStackTrace();
  }
  return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
}

Vous pouvez récupérer les niveaux d'accès OAuth à l'aide des bibliothèques clientes des API Google en Java ou en Python pour obtenir l'objet GoogleIdTokenVerifier. L'extrait de code suivant montre l'implémentation dans le langage de programmation Java.

Java

import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;

/**
 * Gets the GoogleIdTokenVerifier object and additional OAuth scopes.
 * If additional OAuth scopes are not requested, the idToken will be null.
 *
 * @param tokenResponse - the tokenResponse passed from the exchangeAuthCode
 *                        function.
 *
 **/

void TokenVerifier(GoogleTokenResponse tokenResponse) {

    string idTokenString = tokenResponse.getIdToken();

    GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
        // Specify the WEB_CLIENT_ID of the app that accesses the backend:
        .setAudience(Collections.singletonList(WEB_CLIENT_ID))
        // Or, if multiple clients access the backend:
        //.setAudience(Arrays.asList(WEB_CLIENT_ID_1, WEB_CLIENT_ID_2, WEB_CLIENT_ID_3))
        .build();

    GoogleIdToken idToken = verifier.verify(idTokenString);

    // The idToken can be null if additional OAuth scopes are not requested.
    if (idToken != null) {
        Payload payload = idToken.getPayload();

    // Print user identifier
    String userId = payload.getSubject();
    System.out.println("User ID: " + userId);

    // Get profile information from payload
    String email = payload.getEmail();
    boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
    String name = (String) payload.get("name");
    String pictureUrl = (String) payload.get("picture");
    String locale = (String) payload.get("locale");
    String familyName = (String) payload.get("family_name");
    String givenName = (String) payload.get("given_name");

    // This ID is unique to each Google Account, making it suitable for use as
    // a primary key during account lookup. Email is not a good choice because
    // it can be changed by the user.
    String sub = payload.getSubject();

    // Use or store profile information
    // ...

    } else {
      System.out.println("Invalid ID token.");
    }
}

Appeler des API REST à partir du serveur

Pour obtenir une description complète des appels d'API disponibles, consultez la page API REST pour les services Google Play Jeux.

Voici des exemples d'appels d'API REST qui peuvent vous être utiles :

Joueur

Si vous souhaitez obtenir l'ID du joueur authentifié et les données de son profil, Appelez Players.get avec 'me' comme ID.

Exploits

Pour en savoir plus, consultez ce guide.