22

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

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

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 Sign-In for Web guide, можно получить маркер доступа по телефону var token = result.credential.accessToken;, но я не могу найти подобный метод в Android.

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

+0

Вы включили API с консоли –

+0

, какая консоль @KrunalKapadiya? Я включил Google в Firebase Authentication Console – Wilik

+0

https://console.developers.google.com/apis/dashboard?project=YOUR_PROJECT_ID, Включить API данных YouTube v3 –

ответ

30

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


Есть три типа маркеров вы столкнетесь в firebase:

  • Firebase ID лексемы

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

  • Идентичность Provider лексемы

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

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

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


Теперь, что вы получаете, firebase Id лексема, что вам нужно, это идентичность поставщика маркеров.

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

Так упоминается способ, которым мы входим в Google с использованием firebase. here.

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

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


(. Для того, чтобы вырезать вещи Короче говоря, просто посмотрите на шаге 5 ниже, если вы сделали установку уже)
Код:

  1. Настройка Google для входа в аккаунт и GoogleApiClient :

    // Configure sign-in to request the user's 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(); 
    
  2. Добавьте кнопку Google для входа в аккаунт, чтобы приложение

    <com.google.android.gms.common.SignInButton 
        android:id="@+id/sign_in_button" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" /> 
    
  3. Набор LISTENER Нажмите для входа в аккаунт

    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); 
        } 
    }); 
    
  4. Переопределить OnActivityResult метод в деятельности:

    @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 
         // ... 
        } 
    } 
    
  5. 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(); 
           } 
          } 
         }); 
    } 
    
  6. Заключительный шаг: Auth Слушателей для 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.

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


UPDATE:

Ее важно, что на шаге 1, вы запрашиваете для маркера Id, в противном случае на шаге 5, вы получите нулевой токен. Подробнее см. here. Я обновил Шаг 1.


UPDATE:

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

(Примечание: Я использовал okhttp версию 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" 
    } 

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

+0

Благодарим вас за прекрасный ответ, но 'acct.getIdToken()' не является токеном Google Access, основанным на [этом SO-ответе] (http://stackoverflow.com/a/10299106/5292961), токен доступа к Google с 'ya29.AHES ...' и всего лишь 60 символов ('acct.getIdToken()' возвращает 1088 символов). Еще раз спасибо за ваш ответ! По крайней мере, теперь мне просто нужно знать, как получить «токен доступа» от «id token». После быстрых исследований похоже, что мне нужно развернуть бэкэнд для получения токена доступа. [ссылка] (http://stackoverflow.com/questions/33998335/how-to-get-access-token-after-user-is-signed-in-from-gmail-in-android) – Wilik

+0

Хорошо, я думаю, что я здесь неправильно, токен, который вы получите здесь, - это JWT (Json Web Token). Если вы не знаете разницы между токенами JWT и OAuth, пожалуйста, сообщите об этом в Google. То, что вы говорите о 60 char long, это токен доступа OAuth. Итак, что вам нужно сделать, это использовать этот токен jwt, чтобы нажать 'https: // www.googleapis.com/oauth2/v4/token', теперь это можно сделать на стороне клиента, без необходимости на стороне сервера. Я обновляю свой код для выбора маркера доступа oauth из самого Android. Спасибо, что указали это, обновите как можно раньше. –

+1

Код, который вы только что обновили, получен из ссылки в моем предыдущем комментарии. Я пробовал это, и я получаю этот ответ '{" error ":" invalid_grant "," error_description ":" Bad Request "}'. Должен ли я поместить то же значение для «code», как в вашем ответе, или где я могу получить этот «код устройства»? Из [данного руководства] (https://developers.google.com/identity/protocols/OAuth2InstalledApp) выглядит так, что значение для «code» является ответом от запроса авторизации. Теперь я смущен. haha – Wilik

12

Попробуйте GoogleAuthUtil.getToken где scope походит «OAuth2: обл1 обл2 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 { 
     } 
    } 
} 
+0

Спасибо, кучка чувак :) – Shahal

+0

Спасибо, друг, сэкономленный ma day –

+0

Жаль, что у меня было больше бонусов, чтобы дать. Спасибо за помощь. – MikeCocoa

1

Я после решения @vovkas, и хочу, чтобы вы знали, что с момента последнего обновления 11.6.0 вы можете получить Account требуется более легко, так что вы можете иметь все, что внутри удобно денди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).