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

게임에서 백엔드 서버를 사용하는 경우 Google 로그인으로 플레이어를 인증하고 플레이어의 ID를 백엔드 서버로 안전하게 전달합니다. 또한 사용자의 신원과 기타 데이터를 수집하지 않고도 안전하게 기기를 통과하는 동안 잠재적인 조작에 노출될 수 있습니다.

이 시나리오에서는 게임이 플레이어에게 평소와 같이 Google Play 게임즈 서비스에 로그인하라는 메시지를 표시합니다. 이 로그인이 완료되면 GoogleSignInAccount 객체에 특별한 일회용 코드가 포함됩니다. (서버 인증 코드라고 함). 그런 다음 서버에서 OAuth 2.0 토큰의 서버 인증 코드이며, Google Play 게임즈 서비스 API

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

Google 로그인을 사용하여 플레이어를 인증하는 방법을 보여주는 자세한 코드 샘플은 GitHub의 clientserverskeleton 샘플

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

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

시작하기 전에

Google 로그인을 게임에 통합하려면 먼저 Google Play Console(아래에 설명됨) Google Play 게임즈 서비스 설정

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

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

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

  1. 게임의 연결된 앱 섹션에서 게임에 연결된 웹 앱을 만듭니다. Google Play Console로 이동합니다. 참고: launch_url는 이 흐름에 사용되지 않으며 비워 둘 수 있습니다.
  2. 앱의 사용자 인증 정보 정보를 가져오려면 다음 단계를 따르세요. <ph type="x-smartling-placeholder">
      </ph>
    1. Google Play Console의 게임에서 게임 세부정보를 클릭합니다.
    2. API 콘솔 프로젝트 섹션까지 아래로 스크롤한 다음 링크를 클릭합니다. API 콘솔 프로젝트로 이동합니다
    3. API 및 서비스 > Google API의 사용자 인증 정보 화면 콘솔에서 웹 앱의 client_secret.json 파일을 다운로드합니다. 서버가 액세스할 수 있는 위치에 저장합니다. 클라이언트 기록 나중에 참조할 수 있는 사용자 인증 정보의 ID입니다.
  3. 서버 측 앱을 다시 시작하여 클라이언트 앱을 설치해야 합니다.

클라이언트에서 로그인 수행

GoogleSignInClient 클래스는 현재 로그인한 적이 없는 경우 로그인해야 합니다. 있습니다.

로그인 클라이언트를 만들려면 다음 단계를 따르세요.

  1. GoogleSignInOptions 객체를 통해 로그인 클라이언트를 만듭니다. GoogleSignInOptions.Builder에서 로그인을 구성하려면 다음을 지정해야 합니다. GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN
  2. 또한 게임에 인증이 필요하다고 지정해야 합니다. 백엔드 서버를 위한 코드를 생성할 수 있습니다. 서버의 클라이언트 ID를GoogleSignInOptions.Builder.requestServerAuthCode() 매개변수 값으로 사용됩니다. 나중에 설명된 대로 백엔드 서버에서 액세스 토큰에 대한 인증 코드를 가져옵니다. 서버 인증 코드 가져오기에서 확인할 수 있습니다.
  3. GoogleSignIn.getClient() 메서드를 호출하고 이전에 구성한 옵션을 전달합니다. 통화 성공하면 Google Sign-In API가 GoogleSignInClient 인스턴스를 반환합니다.
  4. GoogleSignInClient 인스턴스를 가져온 후에는 플레이어를 로그인해야 합니다. 활동의 onResume()에서 자동으로 자동 로그인을 수행합니다.

예를 들면 다음과 같습니다.

private static final int RC_SIGN_IN = 9001;
private GoogleSignInClient mGoogleSignInClient;

private void startSignInForAuthCode() {

  // Client ID for your backend server.
  String webClientId = getString(R.string.webclient_id);

  GoogleSignInOptions signInOption = new
      GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
      .requestServerAuthCode(webClientId)
      .build();

  GoogleSignInClient signInClient = GoogleSignIn.getClient(this, signInOption);
  Intent intent = signInClient.getSignInIntent();
  startActivityForResult(intent, RC_SIGN_IN);
}

서버 인증 코드 가져오기

게임이 백엔드 서버의 액세스 토큰에 사용할 수 있는 서버 인증 코드를 검색하려면 다음 안내를 따르세요. getServerAuthCode() 호출 GoogleSignInAccount의 메서드 플레이어 로그인에 성공하면 Google 로그인에서 반환하는 객체를 반환합니다.

예를 들면 다음과 같습니다.


// Auth code to send to backend server.
private String mServerAuthCode;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (requestCode == RC_SIGN_IN) {
    GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
    if (result.isSuccess()) {
      mServerAuthCode = result.getSignInAccount().getServerAuthCode();
    } else {
      String message = result.getStatus().getStatusMessage();
      if (message == null || message.isEmpty()) {
        message = getString(R.string.signin_other_error);
      }
      new AlertDialog.Builder(this).setMessage(message)
          .setNeutralButton(android.R.string.ok, null).show();
    }
  }
}

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

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

백엔드 서버에서 로그인한 플레이어를 대신하여 Google API에 액세스하는 방법을 자세히 알아보려면 서버 측 액세스 사용 설정을 참고하세요.

플레이어 로그아웃 처리

게임에서 플레이어를 로그아웃시키려면 GoogleSignInClient에서 signOut() 메서드를 호출합니다. 코드 스니펫 예는 플레이어 로그아웃.

서버에서 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