我已经在Firebase-UI for Android – Auth图书馆的帮助下,在我的应用程序中成功集成了Google登录.从FirebaseUser.getToken()方法检索的令牌不是REST API的有效Google访问令牌.
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中找不到类似的方法.
任何投入?如果我没有提供足够的信息,请给我留言.谢谢 :)
解决方法
你会遇到三种类型的令牌,你会遇到火墙:
> Firebase ID令牌
当用户登录到Firebase应用程序时,由Firebase创建.这些令牌是签名的JWT,可以安全地识别Firebase项目中的用户.这些令牌包含用户的基本配置文件信息,包括用户的ID字符串,这是Firebase项目唯一的.由于可以验证ID令牌的完整性,因此可以将其发送到后端服务器,以识别当前登录的用户.
>身份提供者令牌
由联合身份提供商(如Google和Facebook)创建.这些令牌可以有不同的格式,但通常是OAuth 2.0访问令牌. Firebase应用程序使用这些令牌来验证用户已经使用身份提供程序成功进行身份验证,然后将其转换为Firebase服务可用的凭据.
> Firebase自定义令牌
由您的自定义验证系统创建,以允许用户使用您的验证系统登录Firebase应用.自定义令牌是使用服务帐户的私钥签名的JWT. Firebase应用程序使用这些令牌非常像使用从联合身份提供者返回的令牌.
现在,你得到的是Firebase Id令牌,你需要的是Identity Provider Token.
所以,我们使用firebase登录google的方式是here.
我将在下面添加完整的代码,在UI中显示一个按钮,点击后,将登录用户到谷歌帐户.然后我会得到google访问令牌,然后将其发送到firebase,在那里将其转换为firebase token Id.
我假设你已经配置Android应用程序进行谷歌登录,如果没有,你可以详细介绍here.
(为了简化,只要看下面的步骤5,如果你已经完成了设置.)
代码:
>配置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();
<com.google.android.gms.common.SignInButton android:id="@+id/sign_in_button" android:layout_width="wrap_content" android:layout_height="wrap_content" />
>设置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); } });
>覆盖活动中的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 // ... } }
>使用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(); } } }); }
>最后一步: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之前,并在您的身份验证后,谷歌登录.
希望有帮助!
更新:
重要的是,在步骤1中,您请求令牌ID,否则在步骤5中,您将获得空标记ID.有关更多信息,请参阅here.我已更新步骤1.
更新:
根据讨论,检索的令牌是写入here的JWT令牌.我们需要的是谷歌访问令牌.以下代码使用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" }
希望现在有帮助!