首页 > 解决方案 > 从适用于 Android 的 Google 登录迁移到 Firebase 身份验证

问题描述

目前,我们计划使用Google Sign-In for Android作为我们的服务器身份验证方法。

这是我们计划做的。

客户端(Android 版 Google 登录)

GoogleSignInAccount account = completedTask.getResult(ApiException.class);
// This idToken will sent to backend server.
String idToken = account.getIdToken();

服务器端(适用于 Android 的 Google 登录)

// Based on received idToken from client, backend server will call https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=... 
// to identify who is this user.

{
 // These six fields are included in all Google ID Tokens.
 "iss": "https://accounts.google.com",
 "sub": "110169484474386276334",
 "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "iat": "1433978353",
 "exp": "1433981953",

 // These seven fields are only included when the user has granted the "profile" and
 // "email" OAuth scopes to the application.
 "email": "testuser@gmail.com",
 "email_verified": "true",
 "name" : "Test User",
 "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
 "given_name": "Test",
 "family_name": "User",
 "locale": "en"
}

将来,我们可能希望迁移以提供更多登录选项。这是我未来的迁移计划,从 Android 的 Google 登录迁移到 Firebase 身份验证。

客户端(Firebase 身份验证)

FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser();
mUser.getIdToken(true)
    .addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
        public void onComplete(@NonNull Task<GetTokenResult> task) {
            if (task.isSuccessful()) {
                // This idToken will sent to backend server.
                String idToken = task.getResult().getToken();

            } else {
                // Handle error -> task.getException();
            }
        }
    });

服务器端(适用于 Android 的 Google 登录)

# idToken comes from the client app (shown above)
decoded_token = auth.verify_id_token(idToken)
uid = decoded_token['uid']

我的问题是

  1. 对于适用于 Android 的 Google Sign-In,我们计划将"sub": "110169484474386276334", 作为代表用户的唯一标识符进行存储。那是要使用的正确字段吗?每个用户都是唯一的吗?到目前为止,我的测试是,在客户端,idToken对于同一个用户(在不同的日子),我们可能会得到不同的结果。与idToken同一用户不同,在服务器端仍会产生相同的结果。sub

  2. 有一天,我们可能会迁移到Firebase 身份验证以支持更多登录方法。它是否仍然向后兼容Google Sign-In for Android. 是否Firebase Authentication能够返回与"sub"以前返回的相同Google Sign-In for Android?正如您在代码示例中看到的,Firebase Authentication正在返回uid.

如何比较新Firebase Authenticationuid和以前存储Google Sign-Insub

标签: androidfirebase-authenticationgoogle-signin

解决方案


Q1:基本上在这里回答:

Google 帐户的电子邮件地址可能会更改,因此请勿使用它来识别用户。相反,使用帐户的 ID,您可以在客户端上使用 获取该 ID GoogleSignInAccount.getId(),并在后端subID 令牌的声明中获取该 ID。

Q2:Google 作为 Firebase 的身份验证提供者仍然使用相同的 Google 登录流程(在开始时),然后它也会针对 Firebase 项目对用户进行身份验证。

有一个例子说明了这一点:

private void signIn() {
    Intent signInIntent = mGoogleSignInClient.getSignInIntent();
    startActivityForResult(signInIntent, REQUESTCODE_SIGN_IN);
}

@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 == REQUESTCODE_SIGN_IN) {

        Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
        try {

            // Google Sign In was successful
            GoogleSignInAccount account = task.getResult(ApiException.class);
            String idToken = account.getIdToken();
            // Send token to your backend via HTTPS

            // authenticate with Firebase
            firebaseAuthWithGoogle(account);

        } catch (ApiException e) {
            Log.w(TAG, "Google sign in failed", e);
        }
    }
}

哪里GoogleSignInAccount account仍然是相同的响应。

编辑:甚至可以通过以下方式验证 ID 令牌FirebaseAuth

FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser();

mUser.getIdToken(true).addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
    public void onComplete(@NonNull Task<GetTokenResult> task) {
        if (task.isSuccessful()) {

            String idToken = task.getResult().getToken();
            // Send token to your backend via HTTPS

        } else {
            // Handle error -> task.getException();
        }
    }
});

推荐阅读