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

我试图从验证的用户(使用Firebase身份验证)中检索Google Access令牌来访问Google REST API(如 YouTube Data API).

我已经在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令牌,见 here.

你会遇到三种类型的令牌,你会遇到火墙:

> 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();

>将Google登录按钮添加到您的应用程序

<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"
     }

希望现在有帮助!

相关文章

Android性能优化——之控件的优化 前面讲了图像的优化,接下...
前言 上一篇已经讲了如何实现textView中粗字体效果,里面主要...
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个...
WebView加载页面的两种方式 一、加载网络页面 加载网络页面,...
给APP全局设置字体主要分为两个方面来介绍 一、给原生界面设...
前言 最近UI大牛出了一版新的效果图,按照IOS的效果做的,页...