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

时间:2016-11-28 06:15:25

标签: android firebase-authentication google-signin google-login

我正在尝试从经过身份验证的用户(使用Firebase身份验证)检索Google Access令牌以访问{REST(3 {3)}等Google REST API。

我已在YouTube Data API库的帮助下成功将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
        }
    }
});

Firebase-UI for Android - Auth中,可以通过调用var token = result.credential.accessToken;来获取访问令牌,但我在Android中找不到类似的方法。

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

3 个答案:

答案 0 :(得分:41)

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

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

  • Firebase ID令牌

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

  • 身份提供商令牌

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

  • Firebase自定义令牌

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

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

获取身份提供者令牌很简单,它只是您所显示步骤之前的一步。

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

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

我认为你已经为google登录配置了Android应用程序,如果没有,你可以进入详细信息here

<小时/> (简而言之,如果您已经完成设置,请查看下面的第5步。) 代码

  1. 配置Google SignIn和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. 设置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);   
        }
    });
    
  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. 使用Google SignInAccount进行Firebase身份验证

    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. 最终步骤:Firebase的Auth Listeners

    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);
        }
    }
    
  7. 因此,您的答案位于第5步,就在您对firebase进行身份验证之前,以及在Google登录后进行身份验证之后。

    希望它有所帮助!

    更新:

    重要的是,在步骤1中,您请求令牌ID,否则在步骤5中,您将获得空令牌ID。有关详情,请参阅here。我已更新第1步。

    更新:

    根据讨论,检索到的令牌是JWT令牌,写为here。我们需要的是谷歌访问令牌。下面的代码使用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"
         }
    

    希望现在有所帮助!

答案 1 :(得分:25)

尝试GoogleAuthUtil.getToken,其中scope就像&#34; oauth2:scope1 scope2 scope3&#34;

@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 {
        }
    }
}

答案 2 :(得分:4)

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