Google Play 게임즈 서비스에 대한 서버 측 액세스 사용 설정

플레이어를 인증하고 플레이어의 ID를 백엔드 서버에 안전하게 전달하는 것이 좋습니다. 이렇게 하면 기기를 거치는 동안 잠재적인 조작에 노출되지 않고 게임이 플레이어의 ID와 기타 데이터를 안전하게 가져올 수 있습니다.

이 시나리오에서는 로그인할 때 특수한 일회용 코드를 요청할 수 있습니다. (서버 인증 코드라고 함)를 Play 게임즈 서비스 v2 SDK에서 가져옵니다. 그런 다음 서버에서 OAuth 2.0 토큰의 서버 인증 코드이며, Google Play 게임즈 서비스 API

게임에 로그인을 추가하는 방법에 관한 추가 안내는 다음을 참고하세요. Android 게임에서 로그인

오프라인 액세스에는 다음 단계가 필요합니다.

  1. Google Play Console: 게임 서버의 사용자 인증 정보를 만듭니다. 이 사용자 인증 정보의 OAuth 클라이언트 유형은 '웹'입니다.
  2. Android 앱: 로그인의 일환으로 서버의 사용자 인증 정보 서버 인증 코드를 요청하여 서버에 전달합니다.
  3. 게임 서버에서: 서버 인증 코드를 OAuth 액세스로 교환 Google 인증 서비스를 사용하여 토큰을 설정한 다음 이를 사용하여 Play 게임즈 서비스 REST API

시작하기 전에

먼저 Search Console에서 Google Play Console(아래에 설명됨) Google Play 게임즈 서비스를 설정하고 Play 게임즈 서비스 로그인을 게임에 통합합니다.

게임에 연결된 서버 측 웹 애플리케이션 만들기

Google Play 게임즈 서비스는 웹 게임에 백엔드 지원을 제공하지 않습니다. 그러나 Android 게임 서버에는 백엔드 서버 지원을 제공합니다.

서버 측 앱에서 Google Play 게임즈 서비스용 REST API를 사용하려면 다음 단계를 따르세요.

  1. Google Play Console의 게임에서 Play 게임즈 서비스 > 설정 및 관리 > 구성으로 이동합니다.
  2. 사용자 인증 정보 추가를 선택하여 사용자 인증 정보 추가 페이지로 이동합니다. 게임 서버를 사용자 인증 정보 유형으로 선택하고 승인 섹션으로 이동합니다.
    1. 게임 서버에 이미 OAuth 클라이언트 ID가 있으면 드롭다운 메뉴에서 이 ID를 선택합니다. 변경사항을 저장한 후 다음 섹션으로 이동합니다.
    2. 게임 서버에 기존 OAuth 클라이언트 ID가 없으면 새로 만들 수 있습니다.
      1. OAuth 클라이언트 만들기를 클릭하고 OAuth 클라이언트 ID 만들기 링크를 이용합니다.
      2. 그러면 게임과 연결된 Cloud Platform 프로젝트를 위한 Google Cloud Platform의 OAuth 클라이언트 ID 만들기 페이지로 이동합니다.
      3. 페이지 양식을 작성하고 만들기를 클릭합니다. 애플리케이션 유형을 웹 애플리케이션으로 설정해야 합니다.
      4. 사용자 인증 정보 추가 페이지의 승인 섹션으로 돌아가 새로 생성된 OAuth 클라이언트를 선택하고 변경사항을 저장합니다.

서버 인증 코드 가져오기

게임이 백엔드 서버의 액세스 토큰에 사용할 수 있는 서버 인증 코드를 가져오려면 다음 단계를 따르세요.

  1. 클라이언트에서 requestServerSideAccess를 호출합니다.

    1. Android 애플리케이션의 OAuth 클라이언트 ID가 아니라 게임 서버에 등록된 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에 대해 확인한 다음 게임에 인증합니다.

서버 인증 코드를 서버에서 액세스 토큰으로 교환

서버 인증 코드를 백엔드 서버로 전송하여 액세스 및 갱신 토큰으로 교환합니다. 액세스 토큰을 사용하여 플레이어를 대신하여 Google 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 호출

자세한 내용은 Google Play 게임즈 서비스용 REST API를 참고하세요. 사용 가능한 API 호출에 대한 자세한 설명입니다.

유용할 수 있는 REST API 호출의 예는 다음과 같습니다.

플레이어

  • 로그인한 플레이어의 ID와 프로필 데이터를 가져오고 싶은가요? Players.get 호출 'me'를 ID로 사용합니다.

친구

친구에 대해 자세히 설명하는 친구 가이드를 검토하세요.

  • 플레이어의 친구 목록을 가져오시겠습니까? 다음으로 Players.list를 호출합니다. 'friends_all'collection로 사용합니다.
  • 친구 목록에 액세스할 수 있는지 확인하세요. me에 대해 Players.get을 호출합니다. 응답의 profileSettings.friendsListVisibility 필드를 확인합니다.

업적

업적을 설명하는 업적 가이드를 검토하시기 바랍니다. 더 자세히 살펴보겠습니다

  • 현재 업적 목록을 보고 싶으신가요? AchievementDefinitions.list를 호출할 수 있습니다.
  • 이를 Achievements.list 호출과 결합하여 플레이어가 달성한 업적을 찾습니다.
  • 플레이어가 업적을 달성했나요? Achievements.unlock을 사용하여 달성하세요.
  • 플레이어가 일부 업적을 달성하기 위해 진행했나요? Achievements.increment를 사용하여 다음 작업 수행 진행 상황을 보고하고 플레이어가 잠금 해제했는지 확인합니다.
  • 아직 프로덕션 단계에 없는 게임을 디버깅하고 있나요? 전화를 걸어보세요 Management API의 Achievements.reset 또는 Achievements.resetAll 업적을 원래 상태로 재설정하세요.

리더보드

리더보드에 대한 자세한 내용은 리더보드 가이드를 검토하세요.

  • 게임의 모든 스코어보드 목록을 원하나요? Leaderboards.list를 호출합니다.
  • 플레이어가 게임을 끝냈나요? Scores.submit에 점수를 제출하여 새로운 최고점수입니다.
  • 리더보드를 표시하시겠습니까? Scores.list에서 데이터를 가져와 사용자에게 표시합니다.
  • Scores.listWindow를 사용하여 사용자의 최고 점수에 근접한 다양한 점수를 찾습니다.
  • 특정 리더보드의 플레이어 점수에 대한 자세한 정보를 확인하려면 (예: 플레이어 중 상위 12% 에 속하는 경우) Scores.get을 호출합니다.
  • 게임을 디버깅 중인가요? Management(관리)에서 Scores.reset을 호출해 보세요. 특정 리더보드에서 해당 플레이어의 모든 점수를 재설정하는 API