Google Play 游戏服务的服务器端访问

我们建议您对玩家进行身份验证,并将玩家的身份安全地传递到后端服务器。这使您的游戏能够安全地检索玩家的身份和其他数据,而不会在通过设备时暴露于潜在的篡改。

在这种情况下,玩家成功登录后,您可以从 Play 游戏服务 v2 SDK 请求一个特殊的单次使用代码(称为 *服务器身份验证代码*),客户端将该代码传递到服务器。然后,在服务器上,将服务器身份验证代码交换为服务器可以使用以对 Google Play 游戏服务 API 进行调用的 OAuth 2.0 令牌。

有关在游戏中添加登录的更多指导,请参阅 Android 游戏的登录.

以下步骤是离线访问所必需的

  1. 在 Google Play 管理中心:为您的游戏服务器创建凭据。凭据的 OAuth 客户端类型将为“网络”。
  2. 在 Android 应用程序中:作为登录的一部分,为您的服务器的凭据请求服务器身份验证代码,并将该代码传递到您的服务器。
  3. 在您的游戏服务器上:使用 Google 身份验证服务将服务器身份验证代码交换为 OAuth 访问令牌,然后使用它调用 Play 游戏服务的 REST API.

开始之前

您首先需要在 Google Play 管理中心 中添加您的游戏,如 设置 Google Play 游戏服务 中所述,并将 Play 游戏服务登录 与您的游戏集成。

创建服务器端 Web 应用程序

Google Play 游戏服务不提供对 Web 游戏的后端支持。但是,它确实为您的 Android 游戏的服务器提供后端服务器支持。

如果您想在服务器端应用程序中使用 Google Play 游戏服务的 REST API,请按照以下步骤操作

  1. Google Play 管理中心 中的您的游戏中,转到 **Play 游戏服务 > 设置和管理 > 配置**。
  2. 选择 *添加凭据* 以进入 *添加凭据页面*。选择 *游戏服务器* 作为凭据类型,然后继续进入 *授权* 部分。
    1. 如果您的游戏服务器已经拥有 OAuth 客户端 ID,请从下拉菜单中选择它。保存更改后,继续 下一部分.
    2. 如果您没有为游戏服务器创建现有的 OAuth 客户端 ID,则可以创建一个。
      1. 单击 *创建 OAuth 客户端*,然后按照 *创建 OAuth 客户端 ID* 链接进行操作。
      2. 这将带您进入 Google Cloud Platform 的 *创建 OAuth 客户端 ID* 页面,该页面适用于您游戏的关联 Cloud Platform 项目。
      3. 填写页面的表单,然后单击创建。确保将应用程序类型设置为 Web 应用程序。
      4. 返回 *添加凭据页面* 的 *授权* 部分,选择新创建的 OAuth 客户端,然后保存更改。

获取服务器身份验证代码

要检索游戏可用于后端服务器上的访问令牌的服务器身份验证代码

  1. 从客户端调用 requestServerSideAccess

    1. 确保您使用的是 **为游戏服务器注册的 OAuth 客户端 ID**,而不是 Android 应用程序的 OAuth 客户端 ID。
    2. (可选)如果您的游戏服务器需要对 Play 游戏服务的离线访问(使用刷新令牌的长期访问),则可以将 forceRefreshToken 参数设置为 true。
    GamesSignInClient gamesSignInClient = PlayGames.getGamesSignInClient(this);
    gamesSignInClient
      .requestServerSideAccess(OAUTH_2_WEB_CLIENT_ID, /* forceRefreshToken= */ false)
      .addOnCompleteListener( task -> {
        if (task.isSuccessful()) {
          String serverAuthToken = task.getResult();
          // Send authentication code to the backend game server to be
          // exchanged for an access token and used to verify the player
          // via the Play Games Services REST APIs.
        } else {
          // Failed to retrieve authentication code.
        }
    });
    
  2. 将 OAuth 身份验证代码令牌发送到后端服务器,以便可以将其交换,玩家 ID 与 Play 游戏服务 REST API 进行验证,然后与您的游戏进行身份验证。

发送服务器身份验证代码

将服务器身份验证代码发送到后端服务器以交换为访问和刷新令牌。使用访问令牌代表玩家调用 Play 游戏服务 API,并可选地存储刷新令牌以在访问令牌过期时获取新的访问令牌。

以下代码片段显示了如何在 Java 编程语言中实现服务器端代码以将服务器身份验证代码交换为访问令牌。它使用 clientserverskeleton 示例应用程序.

/**
 * Exchanges the authcode for an access token credential.  The credential
 * is the 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 API
    // console.  This is used to identify your web application.  The
    // contents of this file should not 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();

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

从服务器调用 REST API

有关可用的 API 调用的完整描述,请参阅 Google Play 游戏服务的 REST API.

您可能会发现以下 REST API 调用的示例很有用

玩家

想要获取已登录玩家的 ID 和个人资料数据?使用 'me' 作为 ID 调用 [Players.get][]。

好友

有关详细信息,请参阅 好友 指南。

成就

有关详细信息,请参阅 成就 指南。

排行榜

有关详细信息,请参阅 排行榜 指南。

  • 想要获取游戏中所有排行榜的列表?调用 Leaderboards.list.

  • 如果玩家完成了游戏,您可以将其分数提交到 Scores.submit,并找出它是否为新的最高分。

  • 要显示排行榜,请从 Scores.list 获取数据,并将其显示给用户。

  • 使用 Scores.listWindow 查找靠近用户最高分的各种分数。

  • 要获取有关玩家在特定排行榜上的分数的更多信息(例如,如果玩家在所有玩家中的前 12%),请调用 Scores.get.

  • 如果您正在调试游戏,您可以从管理 API 调用 Scores.reset 以重置特定排行榜上该玩家的所有分数。