본문 바로가기
Unity 공부

[Android] Firebase에서 Google Play Games로 유저 식별하기

by 개발하는 디토 2023. 3. 6.

각 유저별로 가지고 있는 유료 재화의 내역을 보관하기 위해 Firebase Realtime Database를 사용하고 싶었고, 유저를 식별하기 위해 Firebase Authentication을 사용하게 되었다. 나의 경우 Google Play Games로 로그인을 시키기 때문에 해당 로그인 정보로 Firebase Authentication에서 유저를 식별하고자 했고, Authentication에서 식별한 유저의 아이디를 키값으로 Firebase Realtime Database에서 유저의 지갑 정보에 접근하고자 했다.

아래의 문서에서는 구글 플레이 게임 로그인 관련 세팅은 모두 되어 있다고 가정하고 시작한다.

 

공식문서

공식문서부터 읽자.

https://firebase.google.com/docs/auth/unity/play-games?hl=ko 

 

Google Play 게임 서비스를 사용하여 Unity에서 인증  |  Firebase

Google은 흑인 공동체를 위한 인종적 평등을 추구하기 위해 노력하고 있습니다. 자세히 알아보기 이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English 의견 보내기 Google Play 게임 서

firebase.google.com

 

Authentication 앱 시작하기

로그인 방법 설정 또는 Sign-in method 탭 클릭

 

Play 게임즈

 

 

 

로그인 제공 업체에 정보를 입력하기 위해서 다음 주소로 이동한다. Google Play Console

프로젝트를 선택한 뒤 사용자 인증 정보 > OAuth 2.0 Client ID > Web client (auto created by Google Service)를 클릭한다.

 

Web client로 클릭해야 한다. 다른 거 클릭하면 연결 안 된다.

 

 

Web client 에서 클라이언트 ID, 클라이언트 보안 비밀을 각각 복사해 Firebase Authentication의 클라이언트 ID, 클라이언트 보안 비밀번호에 붙여넣는다.

클라이언트 ID, 클라이언트 보안 비밀 복사 -> Firebase Authentication 로그인 제공 업체 쪽에 붙여넣기!

 

또한 위의 Client ID를 Unity의 구글 플레이 게임즈 서비스와도 연결해야 한다. Windows > Google Play Games > Setup > Android setup > Web Client ID (Optional)에 복사한 Client ID를 넣어준다.

Windows > Google Play Games > Setup > Android setup > Web Client ID (Optional)

 

아래쪽 Client ID에 연결

 

 

 

현재 로그인한 사용자 가져오기

구글 플레이 사용자 정보를 받는 내용은 이쪽

https://firebase.google.com/docs/auth/unity/play-games?hl=ko 

 

Unity에서 Google Play 게임즈 서비스를 사용하여 인증  |  Firebase

Google은 흑인 공동체를 위한 인종적 평등을 추구하기 위해 노력하고 있습니다. 자세히 알아보기 의견 보내기 Unity에서 Google Play 게임즈 서비스를 사용하여 인증 컬렉션을 사용해 정리하기 내 환

firebase.google.com

 

 

구글 플레이 사용자 정보 받기

구글 플레이 로그인을 시킨다면 어디에선가 PlayGamesClientConfiguration config를 받을 것이다. 해당 config가 세팅되어 있고 PlayGamesPlatform이 활성화되어 있다면 준비 완료이다.

using GooglePlayGames;
using GooglePlayGames.BasicApi;
using UnityEngine.SocialPlatforms;
using System.Threading.Tasks;

// 특정 Class 안에서 아래의 내용 실행
PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder()
    .RequestServerAuthCode(false /* Don't force refresh */)
    .Build();

PlayGamesPlatform.InitializeInstance(config);
PlayGamesPlatform.Activate();

 

Firebase Authentication 초기화

Start나 Awake에서 InitializeFirebaseAuth()를 호출해 Firebase Authentication을 초기화해준다.

    // Handle initialization of the necessary firebase modules:
    private void InitializeFirebaseAuth()
    {
        Debug.Log("Setting up Firebase Auth");
        _auth = FirebaseAuth.DefaultInstance;
        _auth.StateChanged += AuthStateChanged;
        AuthStateChanged(this, null);
    }
    

    // Track state changes of the auth object.
    private void AuthStateChanged(object sender, System.EventArgs eventArgs)
    {
        if (_auth.CurrentUser != _userInFirebase) {
            bool signedIn = _userInFirebase != _auth.CurrentUser && _auth.CurrentUser != null;
            if (!signedIn && _userInFirebase != null) {
                Debug.Log("Signed out " + _userInFirebase.UserId);
            }
            _userInFirebase = _auth.CurrentUser;
            if (signedIn) {
                Debug.Log("Signed in " + _userInFirebase.UserId);
            }
        }
    }

    // Handle removing subscription and reference to the Auth instance.
    // Automatically called by a Monobehaviour after Destroy is called on it.
    private void OnDestroy() {
        _auth.StateChanged -= AuthStateChanged;
        _auth = null;
    }

 

Firebase 로그인을 위한 Auth Code 받기

구글 플레이 게임즈로 로그인하면 authCode를 받을 수 있고, 이 authCode를 Firebase 사용자 인증을 위해 사용할 수 있다. 받은 authCode를 Firebase Auth 쪽에서 GetCredential을 할 때 사용한다.

Social.localUser.Authenticate((bool success) => {
  if (success) {
    authCode = PlayGamesPlatform.Instance.GetServerAuthCode();
  }
});
Firebase.Auth.FirebaseAuth auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
Firebase.Auth.Credential credential =
    Firebase.Auth.PlayGamesAuthProvider.GetCredential(authCode);
auth.SignInWithCredentialAsync(credential).ContinueWith(task => {
  if (task.IsCanceled) {
    Debug.LogError("SignInWithCredentialAsync was canceled.");
    return;
  }
  if (task.IsFaulted) {
    Debug.LogError("SignInWithCredentialAsync encountered an error: " + task.Exception);
    return;
  }

  Firebase.Auth.FirebaseUser newUser = task.Result;
  Debug.LogFormat("User signed in successfully: {0} ({1})",
      newUser.DisplayName, newUser.UserId);
});

 

참고로, 이때 newUser.Email로 접근해봤자 이메일이 안 나온다. 이메일을 얻고 싶으면 PlayGames 쪽에서 받아와야 한다.

((PlayGamesLocalUser)Social.localUser).Email

 

아무튼 이런 식으로 Google Play Games 로그인으로부터 Firebase Authentication의 사용자와 연결할 수 있다!

 

 

 

후기

처음에 무슨 짓을 해도 authCode가 안 넘어오길래 뭘까...했는데 알고 보니 내가 PC에서 테스트해서 그런 거였다. PC에서는 당연히 구글 플레이 게임즈 로그인이 안 되므로...^^

 

요상하게도 구글 플레이 게임즈에서 제공하는 authCode는 재로그인할 때도 항상 같은 값을 넘겨준다. GetAnotherServerCode 같은 함수가 있길래 시도해봤는데...  참고한 자료

GetAnotherServerAuthCode로 시도해본 흔적

결과는?

응 또 에러~

Error Unity SignInWithCredentialAsync encountered an error: System.AggregateException: One or more errors occurred. (One or more errors occurred. (The supplied auth credential is malformed or has expired. [ Error getting access token from playgames.google.com, OAuth2 redirect uri is: http://localhost, response: OAuth2TokenResponse{params: error=invalid_grant&error_description=Bad%20Request, httpMetadata: HttpMetadata{status=400, cachePolicy=NO_CACHE, cacheDurationJava=null, cacheImmutable=false, staleWhileRevalidate=null, filename=null, lastModified=null, retryAfter=null, crossOriginEmbedderPolicy=null, crossOriginOpenerPolicy=null, crossOriginResourcePolicy=null, headers=HTTP/1.1 200 OK, contentSecurityPolicies=[], originTrials=[], reportToHeaders=[], varyHeaderNames=[], cookieList=[]}} ])) ---> System.AggregateException: One or more errors occurred. (The supplied auth credential is malformed or has expired. [ Error getting access token from playgames.google.com, OAuth2 redirect uri is: http://localhost, response:

 

잘 안 됐다^^ 

똑같은 authCode로 Firebase Auth 쪽에서 GetCredential을 하면 이미 사용한 에러가 나므로 그 부분은 이미 로그인 되어 있으면 GetCredential 하지 않는 방식 등으로 처리하면 좋을 것 같다.

댓글