首页 > 解决方案 > Firebase getCurrentUser 在 linkWithCredentials 之后返回 null 有时

问题描述

我正在使用电子邮件/密码和电话方法注册用户。
注册过程如下
使用PhoneAuthCredential登录用户>通过输入的电子邮件和密码使用EmailCredential链接创建的用户>发送电子邮件验证>数据库条目

public class Sign_Up_page extends AppCompatActivity {

    private String TAG = "Sign_Up_page";

    // UI Widgets.
    private View sign_up_btn;

    // Firebase
    private FirebaseAuth firebaseAuth;
    private DatabaseReference reference;
    private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks;
    private PhoneAuthProvider.ForceResendingToken mResendToken;
    private FirebaseAuth.AuthStateListener authListener;

    private UserPojo userPojo;

    private String mVerificationId = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sign__up_page);

        firebaseAuth = FirebaseAuth.getInstance();

        authListener = new FirebaseAuth.AuthStateListener() {
            @Override
            public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {

                if (firebaseAuth.getCurrentUser() == null) {
                    Toast.makeText(Sign_Up_page.this, "user is null", Toast.LENGTH_LONG).show();
                } else {
                    Toast.makeText(Sign_Up_page.this, "user not null", Toast.LENGTH_LONG).show();
                }
            }
        };

        mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {

            @Override
            public void onVerificationCompleted(PhoneAuthCredential credential) {
                signInWithPhoneAuthCredential(credential);
            }

            @Override
            public void onVerificationFailed(FirebaseException e) {

            }

            @Override
            public void onCodeSent(String verificationId,
                                   PhoneAuthProvider.ForceResendingToken token) {
                mResendToken = token;
            }
        };

    }

    @Override
    public void onClick(View v) {
        super.onClick(v);

        if (v == sign_up_btn) {
              firebaseAuth.fetchSignInMethodsForEmail(userEmail).addOnCompleteListener(new OnCompleteListener<SignInMethodQueryResult>() {
                    @Override
                    public void onComplete(@NonNull Task<SignInMethodQueryResult> task) {

                        if (task.isSuccessful()) {

                            SignInMethodQueryResult result = task.getResult();
                            List<String> signInMethods = result != null ? result.getSignInMethods() : null;

                            if (signInMethods != null && signInMethods.size() == 0) {

                                startPhoneNumberVerification(userPhone);

                                verifyPhoneDialog();
                            }
                        }
                    }
                });
        }
    }

    private void signInWithPhoneAuthCredential(final PhoneAuthCredential credential) {

        firebaseAuth.signInWithCredential(credential)
                .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        if (task.isSuccessful()) {

                            if (task.getResult() != null) {

                                if (task.getResult().getAdditionalUserInfo().isNewUser()) {

                                    AuthCredential emailCredential = EmailAuthProvider.getCredential(userEmail, userPass);

                                    Toast.makeText(Sign_Up_page.this, "Signedin with phone", Toast.LENGTH_LONG).show();

                                    linkUserCredentials(emailCredential);
                                } else {

                                    firebaseAuth.signOut();
                                    Toast.makeText(THIS, "This Phone no. is already registered with different account", Toast.LENGTH_SHORT).show();
                                }
                            }
                        }
                    }
                });
    }

    private void linkUserCredentials(final AuthCredential credential) {

        firebaseAuth.getCurrentUser().linkWithCredential(credential)
                .addOnCompleteListener(Sign_Up_page.this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {

                        if (task.isSuccessful()) {

                            if (task.getResult() != null) {

                                FirebaseUser user = task.getResult().getUser();

                                Toast.makeText(Sign_Up_page.this, "credential linked", Toast.LENGTH_LONG).show();

                                // null current user was causing the account to create in Firebase Auth 
                                // but no entry in Database so here I'm using user instance returned on 
                                // linkCredentialSuccess for furthur use instead of "firebaseAuth.getCurrentUser()" to prevent that issue
                                sendVerificationEmail(user);
                            }
                        } else {
                            firebaseAuth.getCurrentUser().delete();
                        }

                    }
                });
    }

    private void sendVerificationEmail(final FirebaseUser createdUser) {
        if (firebaseAuth.getCurrentUser() != null) {
            firebaseAuth.getCurrentUser().sendEmailVerification()
                    .addOnCompleteListener(this, new OnCompleteListener<Void>() {
                        @Override
                        public void onComplete(@NonNull Task<Void> task) {

                            Toast.makeText(Sign_Up_page.this, "email verification Op complete", Toast.LENGTH_LONG).show();

                            createUser(emailDelivery, createdUser);
                        }
                    });
        }
    }

    private void createUser(final boolean emailDelivery, final FirebaseUser createdUser) {

        reference = FirebaseDatabase.getInstance().getReference("users");

        Toast.makeText(Sign_Up_page.this, "Creating user", Toast.LENGTH_LONG).show();

        userPojo = new UserPojo();
        userPojo.setValues(...);

        String uid = "";
        if (createdUser != null) {

            uid = createdUser.getUid();
        }

        if (firebaseAuth.getCurrentUser() == null) {
            AuthCredential emailCredential = EmailAuthProvider.getCredential(userEmail, userPass);
            if (createdUser != null) {
                createdUser.reauthenticate(emailCredential).addOnCompleteListener(new OnCompleteListener<Void>() {
                    @Override
                    public void onComplete(@NonNull Task<Void> task) {
                        if (task.isSuccessful()) {
                            Toast.makeText(Sign_Up_page.this, "user reAuthenticated", Toast.LENGTH_LONG).show();
                        }
                    }
                });
            }
        }

        if (!uid.equals("")) {

            UserProfileChangeRequest userProfile = new UserProfileChangeRequest.Builder()
                    .setDisplayName(userName).build();
            createdUser.updateProfile(userProfile);

            userPojo.setUid(uid);

            final String path = "" + FirebaseDatabase.getInstance().getReference("users").child(uid);

            reference.child(uid).setValue(userPojo).addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                    if (task.isSuccessful()) {
                        startActivity(new Intent(Sign_Up_page.this, Home_Screen.class));
                    } else {

                        createdUser.delete();

                        AlertDialog.Builder DbEntryFailDialog = new AlertDialog.Builder(Sign_Up_page.this);

                        DbEntryFailDialog.setTitle("Error")
                                    .setMessage("Error" + task.getException().getMessage()
                                            + "\n\nentry url is " + path)
                                    .setPositiveButton("Ok", null)
                                    .show();

                        Toast.makeText(Sign_Up_page.this, "Error occurred creating account when Db entry fail, Please try again", Toast.LENGTH_LONG).show();
                    }
                }
            });

        } else {
            if (createdUser != null) {

                createdUser.delete();
            }
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        firebaseAuth.addAuthStateListener(authListener);
    }

    @Override
    protected void onStop() {
        super.onStop();
        firebaseAuth.addAuthStateListener(authListener);
    }
}

现在问题出在 10 次尝试中,有 1 次尝试firebaseAuth.getCurrentUser()在使用电子邮件凭据链接后变为 null
我添加了 authStateListener 以跟踪用户身份验证状态的变化
这里是 步骤的屏幕截图

这是我的用户表 的数据库写入规则

"users":{           
       "$uid":{
      ".write": "auth.uid != null && newData.exists()",
        },        
   ".indexOn": "role"
 }

现在我可以处理空用户或数据库故障,但我想知道并防止导致这个问题的原因是
我做错了什么,或者这是一个 firebase 错误......?

标签: androidfirebasefirebase-realtime-databasefirebase-authentication

解决方案


推荐阅读