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

我们建议您对玩家进行身份验证,并安全地将玩家的身份传递到后端服务器。这样一来,您的游戏就可以安全地检索玩家的身份和其他数据,而不会在通过设备时面临可能被篡改的风险。

在这种情况下,当玩家成功登录后,您可以从 Play 游戏服务 v2 SDK 请求一个特殊的一次性代码(称为服务器授权代码),并由客户端传递到服务器。随后,在服务器上,用服务器授权代码换取 OAuth 2.0 令牌,以供服务器用于调用 Google Play 游戏服务 API。

如需获得有关在游戏中添加登录功能的其他指导,请参阅 Android 游戏登录

如需离线访问,必须执行以下步骤:

  1. 在 Google Play 管理中心内:为您的游戏服务器创建凭据。凭据的 OAuth 客户端类型为“Web”(网络)。
  2. 在 Android 应用中:在登录过程中,请求获取服务器凭据的服务器授权代码,并将其传递给您的服务器。
  3. 在您的游戏服务器上:通过 Google 授权服务用服务器授权代码换取 OAuth 访问令牌,然后使用该访问令牌来调用 Play 游戏服务 REST API

准备工作

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

创建服务器端 Web 应用

Google Play 游戏服务未针对网络游戏提供后端支持。但该服务为 Android 游戏的服务器提供了后端服务器支持。

如果您希望在服务器端应用中使用适用于 Google Play 游戏服务的 REST API,请按以下步骤操作:

  1. Google Play 管理中心内,从您的游戏中,依次进入 Play 游戏服务 > 设置和管理 > 配置
  2. 选择“添加凭据”,以转到“添加凭据”页面。选择“游戏服务器”作为凭据类型,然后继续转到“授权”部分。
    1. 如果您的游戏服务器已有一个 OAuth 客户端 ID,请从下拉菜单中选择该 ID。保存您所做的更改后,继续转到下一部分
    2. 如果您的游戏服务器当前没有 OAuth 客户端 ID,您可以创建一个。
      1. 点击“创建 OAuth 客户端”,然后点击“创建 OAuth 客户端 ID”链接。
      2. 系统会将您转到 Google Cloud Platform 中与您的游戏关联的 Cloud Platform 项目的“创建 OAuth 客户端 ID”页面。
      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 授权代码令牌发送到您的后端服务器,以便交换该令牌,针对 Play 游戏服务 REST API 验证玩家 ID,然后使用您的游戏进行身份验证。

发送服务器授权代码

将服务器授权代码发送到后端服务器以换取访问令牌和刷新令牌。访问令牌可用于代表玩家调用 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

  • 如果您想要调试游戏,可以从 Management API 调用 Scores.reset 以重置该玩家在特定排行榜中的所有得分。