首页 文章

使用Firebase身份验证进行身份验证后检索Google Access令牌

提问于
浏览
28

我正在尝试从经过身份验证的用户(使用Firebase身份验证)检索Google Access令牌以访问Google REST API,例如YouTube Data API .

我已经在Firebase-UI for Android - Auth库的帮助下成功地在我的应用中集成了Google登录 . 从 FirebaseUser.getToken() 方法检索的令牌不是REST API的有效Google Access令牌 .

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中找不到类似的方法 .

有什么输入?如果我没有提供足够的信息,请在这里发表评论 . 谢谢 :)

3 回答

  • 20

    您的方式将为您提供firebase id令牌,请参阅here .


    您将在firebase中遇到三种类型的令牌:

    • Firebase ID tokens

    用户登录Firebase应用时由Firebase创建 . 这些令牌是签名的JWT,可以安全地识别Firebase项目中的用户 . 这些令牌包含用户的基本配置文件信息,包括用户的ID字符串,这是Firebase项目所特有的 . 由于可以验证ID令牌的完整性,因此您可以将它们发送到后端服务器以识别当前登录的用户 .

    • Identity Provider tokens

    由联合身份提供商(如Google和Facebook)创建 . 这些令牌可以具有不同的格式,但通常是OAuth 2.0访问令牌 . Firebase应用使用这些令牌来验证用户是否已成功通过身份提供商进行身份验证,然后将其转换为Firebase服务可用的凭据 .

    • Firebase Custom tokens

    由您的自定义身份验证系统创建,允许用户使用您的身份验证系统登录Firebase应用 . 自定义令牌是使用服务帐户的私钥签名的JWT . Firebase应用程序使用这些令牌非常类似于使用联合身份提供程序返回的令牌 .


    现在,你得到的是firebase Id令牌,你需要的是身份提供者令牌 .

    它很容易获得身份提供者令牌,它只是您显示的步骤之前的一步 .

    因此,我们使用firebase登录谷歌的方式是here .

    我将在下面添加完整的代码,在UI中显示一个按钮,点击该按钮,将用户登录到Google帐户 . 然后我将获得google访问令牌,然后将其发送到firebase,然后将其转换为firebase令牌ID .

    我假设您已经为谷歌登录配置了Android应用程序,如果没有,您可以进入详细信息here .


    (To cut things short, just look at Step 5 below, if you have done setup already.)

    Code

    • Configure Google SignIn and 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();
    
    • Add the Google Sign-In button to your app
    <com.google.android.gms.common.SignInButton
        android:id="@+id/sign_in_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    
    • Set SignIn Click 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);   
        }
    });
    
    • Override OnActivityResult method in 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 Authentication With 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();
                    }
                }
            });
    }
    
    • Final Step : Auth Listeners for 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 :

    Its important that in Step 1, you request for token Id, otherwise in Step 5, you will get null token id. For more see here. I have updated Step 1.


    UPDATE :

    As per discussion, the retrieved token was JWT token as written here. And what we need is google access token. Below code uses the JWT token to fire at OAuth backend and retrieve this access token :

    (注意:我使用过okhttp 2.6.0版,其他版本可能有不同的方法)

    Code :

    ...
    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 {
            }
        }
    }
    
  • 35

    我正在关注@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) .

相关问题