Подтвердить что ты не робот

Получить токен Google Access после аутентификации с использованием Firebase Authentication

Я пытаюсь получить токен доступа к Google для доступа к API REST Google, например API данных YouTube от аутентифицированного пользователя (с использованием Firebase Authentication).

Я успешно интегрировал вход Google в свое приложение с помощью библиотеки Firebase-UI для Android - Auth. Токен, полученный из метода FirebaseUser.getToken(), не является допустимым токеном доступа Google для API REST.

user.getToken(true).addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
    public void onComplete(@NonNull Task<GetTokenResult> task) {
        if (task.isSuccessful()) {
            String token = task.getResult().getToken();
            // 'token' is not a Google Access Token
        }
    }
});

В Вход в Google для веб-руководства, можно получить токен доступа, вызвав var token = result.credential.accessToken;, но я не могу найти аналогичный метод в Android.

Любые входы? Прокомментируйте здесь, если я не предоставил достаточную информацию. Спасибо:)

4b9b3361

Ответ 1

То, как вы делаете, даст вам токен идентификатора firebase, см. здесь.


Существует три типа токенов, которые вы встретите в firebase:

  • Идентификаторы идентификатора Firebase

    Создано Firebase при входе пользователя в приложение Firebase. Эти жетоны являются подписанными JWT, которые надежно идентифицируют пользователя в проекте Firebase. Эти токены содержат основную информацию профиля для пользователя, включая строку идентификатора пользователя, которая уникальна для проекта Firebase. Поскольку целостность идентификационных маркеров ID может быть проверена, вы можете отправить их на серверный сервер, чтобы идентифицировать пользователя, который в настоящий момент вошел в систему.

  • Идентификаторы поставщика удостоверений

    Создано федеративными поставщиками идентификаторов, такими как Google и Facebook. Эти жетоны могут иметь разные форматы, но часто используются токены доступа OAuth 2.0. Приложения Firebase используют эти токены для проверки того, что пользователи успешно прошли аутентификацию с поставщиком удостоверений, а затем конвертируют их в учетные данные, используемые службами Firebase.

  • Пользовательские токены Firebase

    Создан вашей пользовательской системой auth, чтобы пользователи могли войти в приложение Firebase, используя вашу систему auth. Пользовательские токены - это JWT, подписанные с использованием закрытого ключа учетной записи службы. Приложения Firebase используют эти токены так же, как они используют токены, возвращенные от федеративных поставщиков удостоверений.


Теперь, что вы получаете, это токен идентификатора firebase, вам нужен идентификатор провайдера Identity.

Его просто получить идентификатор провайдера Identity, его всего на один шаг раньше, чем вы показали.

Итак, способ входа в google с использованием firebase упоминается здесь.

Я добавлю ниже полный код, который отображает кнопку в пользовательском интерфейсе, который при нажатии будет входить в аккаунт пользователя google. И тогда я получу токен доступа google, который затем отправляется в firebase, где он преобразуется в идентификатор токена firebase.

Я предполагаю, что вы настроили приложение для Android для входа в google, если нет, вы можете вдаваться в подробности здесь.


(Чтобы сократить все, просто взгляните на Шаг 5 ниже, если вы уже сделали настройку.)
Код:
  • Настроить Google SignIn и GoogleApiClient:

     // Configure sign-in to request the user ID, email address, and basic
     // profile. ID and basic profile are included in DEFAULT_SIGN_IN.
     GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        .requestIdToken(getString(R.string.default_web_client_id))
        .requestEmail()
        .build();
    
     // NOTE : 
     // The string passed to requestIdToken, default_web_client_id, 
     // can be obtained from credentials page (https://console.developers.google.com/apis/credentials).
     // There mentioned Web application type client ID is this string.
    
    
     // ... 
     // Build a GoogleApiClient with access to the Google Sign-In API and the
     // options specified by gso.
     mGoogleApiClient = new GoogleApiClient.Builder(this)
        .enableAutoManage(this /* Activity */, this /* OnConnectionFailedListener */)
        .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
        .build();
    
  • Добавьте кнопку Google для входа в приложение

    <com.google.android.gms.common.SignInButton
        android:id="@+id/sign_in_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    
  • Установить прослушиватель входных данных Sign In

    findViewById(R.id.sign_in_button).setOnClickListener(new OnClickListener() {
        public void onClick(View v){
            Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
            startActivityForResult(signInIntent, RC_SIGN_IN);   
        }
    });
    
  • Переопределить OnActivityResult метод в Activity:

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
    
        // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
        if (requestCode == RC_SIGN_IN) {
            // Google Sign In was successful, authenticate with Firebase
            GoogleSignInAccount account = result.getSignInAccount();
            firebaseAuthWithGoogle(account); // This method is implemented in step 5.
        } else {
            // Google Sign In failed, update UI appropriately
            // ...
        }
    }
    
  • Аутентификация Firebase с помощью Google SignInAccount

    String idTokenString = "";
    ...
    private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
        Log.d(TAG, "Google User Id :" + acct.getId());
    
        // --------------------------------- //
        // BELOW LINE GIVES YOU JSON WEB TOKEN, (USED TO GET ACCESS TOKEN) : 
        Log.d(TAG, "Google JWT : " + acct.getIdToken());
        // --------------------------------- //
    
        // Save this JWT in global String : 
        idTokenString = acct.getIdToken();
    
        AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
        mAuth.signInWithCredential(credential)
            .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());
    
                    if(task.isSuccessful()){
                        // --------------------------------- //
                        // BELOW LINE GIVES YOU FIREBASE TOKEN ID : 
                        Log.d(TAG, "Firebase User Access Token : " + task.getResult().getToken());
                        // --------------------------------- //
                    }
                    // If sign in fails, display a message to the user. If sign in succeeds
                    // the auth state listener will be notified and logic to handle the
                    // signed in user can be handled in the listener.
                    else {
                        Log.w(TAG, "signInWithCredential", task.getException());
                        Toast.makeText(GoogleSignInActivity.this, "Authentication failed.",
                                Toast.LENGTH_SHORT).show();
                    }
                }
            });
    }
    
  • Заключительный шаг: Аутентификаторы для Firebase

    private FirebaseAuth mAuth;
    private FirebaseAuth.AuthStateListener mAuthListener;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...
        mAuth = FirebaseAuth.getInstance();
        mAuthListener = new FirebaseAuth.AuthStateListener() {
            @Override
            public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
                FirebaseUser user = firebaseAuth.getCurrentUser();
                if (user != null) {
                    // User is signed in
                    Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
                } else {
                   // User is signed out
                   Log.d(TAG, "onAuthStateChanged:signed_out");
                }
                // ...
            }
       };
       // ...
    }
    
    //...
    
    @Override
    public void onStart() {
        super.onStart();
        mAuth.addAuthStateListener(mAuthListener);
    }
    
    @Override
    public void onStop() {
        super.onStop();
        if (mAuthListener != null) {
            mAuth.removeAuthStateListener(mAuthListener);
        }
    }
    

Итак, ваш ответ лежит на шаге 5, который был как раз перед тем, как вы прошли проверку подлинности на firebase и сразу после того, как вы аутентифицировали вход в Google.

Надеюсь, что это поможет!


ОБНОВЛЕНИЕ:

Важно то, что на шаге 1 вы запрашиваете идентификатор токена, иначе на шаге 5 вы получите идентификатор нулевого маркера. Подробнее см. здесь. Я обновил Шаг 1.


ОБНОВЛЕНИЕ:

В соответствии с обсуждением извлеченным токеном был токен JWT, как написано здесь. И нам нужен токен доступа google. Ниже код использует токен JWT для запуска в OAuth и извлекает этот токен доступа:

(Примечание: я использовал okhttp version 2.6.0, другие версии могут иметь разные методы)

Код:

...
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormEncodingBuilder()
            .add("grant_type", "authorization_code")
            .add("client_id", "<Your-client-id>")   // something like : ...apps.googleusercontent.com
            .add("client_secret", "{Your-client-secret}")
            .add("redirect_uri","")
            .add("code", "4/4-GMMhmHCXhWEzkobqIHGG_EnNYYsAkukHspeYUk9E8") // device code.
            .add("id_token", idTokenString) // This is what we received in Step 5, the jwt token.
            .build();

final Request request = new Request.Builder()
        .url("https://www.googleapis.com/oauth2/v4/token")
        .post(requestBody)
        .build();

client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(final Request request, final IOException e) {
        Log.e(LOG_TAG, e.toString());                
    }

    @Override
    public void onResponse(Response response) throws IOException {
        try {
            JSONObject jsonObject = new JSONObject(response.body().string());
            final String message = jsonObject.toString(5);
            Log.i(LOG_TAG, message);                    
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
});

Вот результат, который имеет токен доступа по мере необходимости:

I/onResponse: {
          "expires_in": 3600,
          "token_type": "Bearer",
          "refresh_token": "1\/xz1eb0XU3....nxoALEVQ",
          "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjQxMWY1Ym......yWVsUA",
          "access_token": "ya29.bQKKYah-........_tkt980_qAGIo9yeWEG4"
     }

Надеюсь, теперь это поможет!

Ответ 2

Попробуйте GoogleAuthUtil.getToken, где scope как "oauth2: scope1 scope2 scope3"

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(getString(R.string.default_web_client_id))
            .requestEmail()
            .build();

    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .enableAutoManage(this, this)
            .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
            .build();
}

private void signIn() {
    Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
    startActivityForResult(signInIntent, RC_SIGN_IN);
}

@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()) {
            final GoogleSignInAccount account = result.getSignInAccount();

                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        try {
                            String scope = "oauth2:"+Scopes.EMAIL+" "+ Scopes.PROFILE;
                            String accessToken = GoogleAuthUtil.getToken(getApplicationContext(), account.getAccount(), scope, new Bundle());
                            Log.d(TAG, "accessToken:"+accessToken); //accessToken:ya29.Gl...

                        } catch (IOException e) {
                            e.printStackTrace();
                        } catch (GoogleAuthException e) {
                            e.printStackTrace();
                        }
                    }
                };
                AsyncTask.execute(runnable);

        } else {
        }
    }
}

Ответ 3

Я следую решению @vovkas и хочу сообщить вам, что с последним обновлением 11.6.0 вы можете легко получить Account, чтобы вы могли иметь все внутри удобного dandy AsyncTask до повторно использовать, когда захотите:

public class GetToken extends AsyncTask<Void, Void, String> {

    private final Context context;

    public GetToken(Context context) {
        this.context = context;
    }

    @Override
    protected String doInBackground(Void... voids) {
        try {
            String scope = "oauth2:" + Scopes.EMAIL + " " + Scopes.PROFILE;
            GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(context);
            return GoogleAuthUtil.getToken(context, account.getAccount(), scope, new Bundle());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (GoogleAuthException e) {
            e.printStackTrace();
        }
        return null;
    }
}

Ключ должен использовать GoogleSignIn.getLastSignedInAccount(context).