Dostęp po stronie serwera do usług gier Google Play

Zalecamy używanie interfejsu PgsGamesSignInClient do uwierzytelniania graczy i bezpiecznego przekazywania tożsamości gracza na serwer backendu. Dzięki temu gra może bezpiecznie pobierać tożsamość gracza i inne dane bez narażania się na potencjalne manipulacje podczas przesyłania przez urządzenie.

Gdy gracz pomyślnie się uwierzytelni, możesz poprosić o specjalny kod jednorazowy (zwany kodem autoryzacji serwera) z natywnego pakietu SDK usług Gier Play w wersji 2 (beta), który klient przekazuje serwerowi. Następnie na serwerze wymień kod autoryzacji serwera na token OAuth 2.0, którego serwer może używać do wywoływania interfejsu API Usług gier Play Google.

Dodatkowe wskazówki dotyczące dodawania uwierzytelniania w grach znajdziesz w artykule Uwierzytelnianie na platformie.

Aby uzyskać dostęp offline:

  1. W Konsoli Google Play: utwórz dane logowania dla serwera gry. Typ klienta OAuth danych logowania to „web”.
  2. W aplikacji na Androida: w ramach uwierzytelniania platformy poproś o kod uwierzytelniania serwera dla danych logowania serwera i przekaż go do serwera. Aplikacja PgsGamesSignInClient może prosić o 3 zakresy OAuth 2.0, gdy żąda dostępu po stronie serwera do interfejsów API usług internetowych Gry Play. Opcjonalne zakresy to PGS_AUTH_SCOPE_EMAIL, PGS_AUTH_SCOPE_PROFILE i PGS_AUTH_SCOPE_OPENID. Dwa domyślne zakresy to DRIVE_APPFOLDERGAMES_LITE.
  3. Na serwerze gry: wymień kod autoryzacji serwera na token dostępu OAuth za pomocą usług uwierzytelniania Google, a następnie użyj go do wywoływania interfejsów REST API usług gier Play.

Zanim zaczniesz

Najpierw musisz dodać grę w Konsoli Google Play, zgodnie z opisem w artykule Konfigurowanie usług gier Google Play.

Tworzenie aplikacji internetowej po stronie serwera

Usługi gier Google Play nie zapewniają obsługi backendu w przypadku gier internetowych. Zapewnia jednak obsługę serwera backendu serwera gry na Androida.

Jeśli chcesz używać interfejsów API REST usług Gier Google Play w aplikacji po stronie serwera, wykonaj te czynności:

  1. Konsoli Google Play wybierz grę.
  2. Kliknij Usługi gier Play > Konfiguracja i zarządzanie > Konfiguracja.
  3. Kliknij Dodaj dane logowania, aby przejść na stronę Dodaj dane logowania. Jako typ danych logowania wybierz Serwer gier i przejdź do sekcji Autoryzacja.
    1. Jeśli serwer gier ma już identyfikator klienta OAuth, wybierz go z menu. Po zapisaniu zmian przejdź do następnej sekcji.
    2. Jeśli nie masz identyfikatora klienta OAuth na potrzeby serwera gry, możesz go utworzyć.
      1. Kliknij Utwórz klienta OAuth i skorzystaj z linku Utwórz identyfikator klienta OAuth.
      2. Spowoduje to przejście do strony Tworzenie identyfikatora klienta OAuth w Google Cloud Platform dla projektu powiązanego z Twoją grą.
      3. Wypełnij formularz na stronie i kliknij Utwórz. Ustaw typ aplikacji na Aplikacja internetowa.
      4. Wróć do sekcji Autoryzacja na stronie Dodaj dane logowania, wybierz nowo utworzonego klienta OAuth i zapisz zmiany.

Pobieranie kodu autoryzacji serwera

Aby pobrać kod autoryzacji serwera, którego gra może używać do uzyskiwania tokenów dostępu na serwerze backendu:

  1. Zadzwoń pod numer PgsGamesSignInClient_requestServerSideAccess z telefonu klienta.
    1. Upewnij się, że używasz identyfikatora klienta OAuth zarejestrowanego na serwerze gry, a nie identyfikatora klienta OAuth aplikacji na Androida.
    2. (Opcjonalnie) Jeśli serwer gry wymaga dostępu offline (długotrwałego dostępu za pomocą tokena odświeżania) do usług Gier Play, możesz ustawić parametr force_refresh_token na wartość true.
  2. (Opcjonalnie) W ramach uwierzytelniania nowi użytkownicy powinni zobaczyć jeden ekran zgody na dodatkowe zakresy. Po zaakceptowaniu zgody ustawiasz parametr PgsAuthScope scopes z zakresami OAuth PGS_AUTH_SCOPE_EMAIL, PGS_AUTH_SCOPE_PROFILEPGS_AUTH_SCOPE_OPENID. Jeśli użytkownicy odrzucą prośbę o zgodę, do backendu zostaną wysłane tylko 2 domyślne zakresy: DRIVE_APPFOLDERGAMES_LITE.

    Ekran zgody na dodatkowe zakresy OAuth.
    Ekran zgody na dodatkowe zakresy OAuth. (kliknij, aby powiększyć).

     // #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. Wyślij token kodu autoryzacji OAuth na serwer backendu, aby można go było wymienić, zweryfikować identyfikator gracza za pomocą interfejsów REST API usług Gier Play, a następnie uwierzytelnić w grze.

Przesyłanie kodu autoryzacji serwera

Wyślij kod autoryzacji serwera na serwer backendu, aby wymienić go na tokeny dostępu i odświeżania. Użyj tokena dostępu, aby wywołać interfejs API usług gier Play w imieniu gracza, i opcjonalnie zapisz token odświeżania, aby uzyskać nowy token dostępu, gdy ten wygaśnie.

Więcej informacji o tym, jak działają identyfikatory graczy, znajdziesz w artykule Identyfikatory graczy nowej generacji.

Poniższy fragment kodu pokazuje, jak możesz wdrożyć kod po stronie serwera w języku programowania C++, aby wymienić kod autoryzacji serwera na tokeny dostępu.

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

Zakresy OAuth możesz pobrać za pomocą Google API Client Libraries w językach Java lub Python, aby uzyskać obiekt GoogleIdTokenVerifier. Poniższy fragment kodu pokazuje implementację w języku programowania 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.");
    }
}

Wywoływanie interfejsów API REST z serwera

Pełny opis dostępnych wywołań interfejsu API znajdziesz w artykule Interfejsy REST API usług Gier Google Play.

Oto przykłady wywołań interfejsu API REST, które mogą Ci się przydać:

Odtwarzanie

Chcesz uzyskać uwierzytelniony identyfikator gracza i dane profilu? Wywołaj funkcję Call Players.get z parametrem 'me' jako identyfikatorem.

Osiągnięcia

Szczegółowe informacje znajdziesz w przewodniku po osiągnięciach.

  • Aby uzyskać listę bieżących osiągnięć, wywołaj funkcję AchievementDefinitions.list.

  • Połącz to z wywołaniem funkcji Achievements.list, aby sprawdzić, które osiągnięcia zostały odblokowane przez gracza.

  • Wywołaj funkcję Achievements.unlock, aby odblokować osiągnięcie gracza.

  • Wywołaj funkcję Achievements.increment , aby zgłosić postępy w zdobywaniu osiągnięcia i sprawdzić, czy gracz je odblokował.

  • Jeśli debugujesz grę, która nie została jeszcze udostępniona w wersji produkcyjnej, możesz wywołać funkcje Achievements.reset lub Achievements.resetAll z interfejsów Management API, aby zresetować osiągnięcia do stanu pierwotnego.