【问题标题】:Firebase user: isEmailVerified returns falseFirebase 用户:isEmailVerified 返回 false
【发布时间】:2021-05-26 01:39:49
【问题描述】:

我正在开发一个使用 Firebase 身份验证的 Android 应用。创建新用户后,我将发送一封验证电子邮件。

Firebase.auth.currentUser?.let {user ->
        user.sendEmailVerification().addOnCompleteListener {verificationTask ->
            if(verificationTask.isSuccessful){
                _verificationSuccess.value = true
            } else {
                _verificationError.value = verificationTask.exception
            }
        }
    }

在我的清单中,我添加了一个 Intent 过滤器,当用户尝试打开验证链接时它会打开我的应用。

<intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.BROWSABLE"/>
                <data
                    android:host="test-project.firebaseapp.com"
                    android:scheme="https"/>
            </intent-filter>

问题是,当链接打开我的应用程序时,电子邮件未经过验证。我有这个总是返回 false 的验证

if(Firebase.auth.currentUser.isEmailVerified){
                        //Email verified
                    } else {
                        throw Exception("Email not verified")
                    }

只有在网络浏览器中打开验证链接时,验证才会返回 true。如何在我的应用内验证电子邮件?

【问题讨论】:

    标签: android firebase kotlin firebase-authentication


    【解决方案1】:

    通过应用您拥有的意图过滤器,您已经告诉 Android 您将处理所有以https://test-project.firebaseapp.com 为目标的网络请求。既然您的应用程序已经限制浏览到此 URL,您现在需要代表用户向服务器发出请求。

    默认情况下,当您向用户发送电子邮件验证时,他们将收到一封包含如下链接的电子邮件:

    https://<PROJECT_ID>.firebaseapp.com/__/auth/action?mode=verifyEmail&oobCode=<VERIFICATION_CODE>&apiKey=<API_KEY>&lang=<LANGUAGE>
    

    注意:可以使用custom action handlers 自定义这些链接,或者您可以使用dynamic links,这样您就不会拦截所有指向https://test-project.firebaseapp.com 的内容。

    由于用户可能希望在浏览器中访问您应用的网站,因此您应该使您的意图过滤器更具体地处理电子邮件操作。

    <intent-filter android:label="@string/filter_view_handle_action_code">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="https"
              android:host="test-project.firebaseapp.com"
              android:pathPrefix="/__/auth/action" />
    </intent-filter>
    

    免责声明:我没有测试过以下方法是否有效,但理论上应该可以。

    如果截取这样的URL,需要在onCreate方法中处理:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    
        Intent intent = this.getIntent();
        if (intent.hasCategory(android.intent.category.BROWSABLE)) {
            // intent came from browser
            Uri data = intent.getData();
            String mode = data.getQueryParameter("mode");
            String oobCode = data.getQueryParameter("oobCode");
            if (mode != "verifyEmail" || oobCode == null) {
                Log.i("MyActivity", "Started with unexpected browsable intent");
                return;
            }
    
            handleVerifyEmailActionCode(oobCode);
        }
    }
    
    private handleVerifyEmailActionCode(String oobCode) {
        String email = null;
        FirebaseAuth.getInstance().checkActionCode(oobCode)
            .onSuccessTask( actionCodeResult -> {
                if (actionCodeResult.getOperation() != ActionCodeResult.VERIFY_EMAIL) {
                    throw new UnsupportedActionCodeOperationException(actionCodeResult.getOperation());
                }
    
                email = actionCodeResult.getInfo().getEmail();
                return FirebaseAuth.getInstance().applyActionCode(oobCode);
            })
            .addOnCompleteListener( applyActionCodeTask -> {
                if (!applyActionCodeTask.isSuccessful()) {
                    Exception ex = applyActionCodeTask.getException();
                    // TODO: Handle exceptions
                    Toast.makeText(getApplicationContext(), "Failed to verify email. " + ex.getMessage(), Toast.LENGTH_SHORT).show();
                    return;
                }
    
                // email verified successfully!
                // do something interesting
                Toast.makeText(getApplicationContext(), email + " was verified!", Toast.LENGTH_SHORT).show();
                FirebaseUser user = FirebaseAuth.getCurrentUser(); // WARN: May not have finished initializing yet?
                if (user != null && user.getEmail() == email) {
                    user.reload()
                        .addOnFailureListener(ex -> {
                            Log.e(MyActivity.class, "Failed to refresh user token: " + ex.getMessage());
                        });
                } else {
                    Log.i(
                        MyActivity.class,
                        user == null
                            ? "User wasn't signed in, skipping reload"
                            : "User email mismatch, skipping reload"
                    );
                }
        });
    }
    
    /**
     * Custom exception to be used when a OOB code's `ActionCodeResult.Operation`
     * doesn't match what it was expected to be.
     * 
     * @see https://firebase.google.com/docs/reference/android/com/google/firebase/auth/ActionCodeResult#constant-summary
     */
    public class UnsupportedActionCodeOperationException extends Exception { 
        protected int operation;
    
        public UnsupportedActionCodeOperationException(int operation) {
            super("The ActionCodeResult.Operation value of " + operation + " is not supported");
            this.operation = operation;
        }
    
        public int getOperation() {
            return this.operation;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-05
      • 2017-03-31
      • 2018-06-26
      • 2020-03-28
      • 2019-07-17
      • 2016-12-20
      • 2020-10-03
      • 2020-05-23
      相关资源
      最近更新 更多