Пустое поле электронной почты пользователя Firebase Auth с использованием интеграции с Facebook (Firebase 3.0)

Я успешно развернул учебный код с https://firebase.google.com/docs/auth/android/facebook-login для интеграции в систему Firebase Auth с Facebook. Пользователи успешно созданы в консоли Firebase Auth.

Однако я заметил, что поле "Электронная почта" в пользовательском объекте пуст (-). Как ни странно, я успешно получил информацию электронной почты непосредственно из объектов результатов поставщика, используя GraphRequest, используя полученный токен.

На основе документации, которую я прочитал (https://firebase.google.com/docs/reference/android/com/google/firebase/auth/FirebaseUser.html#getEmail()), поле электронной почты должно быть заполнено от поставщиков логинов.

Некоторое дополнительное странное поведение:

  1. После успешного входа в систему, onAuthStateChanged вызывается дважды. Значение firebaseAuth.getCurrentUser(). GetProviderId() - это Firebase в обоих случаях
  2. Я пытаюсь перечислить поставщиков из объекта FirebaseUser, user.getProviderData(). У меня есть два провайдера: firebase и facebook.com
  3. Когда я попытался обновить электронную почту с помощью FirebaseUser.updateEmail(event.getEmail()), я получил эту ошибку: произошла внутренняя ошибка. [EMAIL_EXISTS]

Я что-то пропустил или сделал что-то не так?

Вот мой код:

public class LoginActivity extends AppCompatActivity {
    private static final String TAG = "LOGIN_ACTIVITY";
    private static final int RC_SIGN_IN = 777;
    private EventBus eventBus;
    private SweetAlertDialog pDialog;

    private FirebaseAuth mAuth;
    private FirebaseAuth.AuthStateListener mAuthListener;
    private CallbackManager mCallbackManager;
    private ImageView mPasswordVisibilityView;
    private TextView txtPassword;
    private boolean justEnteredAuthStateChanged = false;
    private GoogleApiClient mGoogleApiClient;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FacebookSdk.sdkInitialize(getApplicationContext());

        setContentView(R.layout.login);

        // Firebase
        mAuth = FirebaseAuth.getInstance();

        mAuthListener = new FirebaseAuth.AuthStateListener() {
            @Override
            public void onAuthStateChanged(@NonNull final FirebaseAuth firebaseAuth) {
                final FirebaseUser user = firebaseAuth.getCurrentUser();
                if (user != null) {
                    // User is signed in
                    Util.logassert("Auth Provider = " + firebaseAuth.getCurrentUser().getProviderId()); // this is called twice, values of Provider = Firebase 
                    Util.logassert("total provider = " + user.getProviderData().size()); // output = 2. "Firebase" and "facebook.com"
                    for (int i = 0; i < user.getProviderData().size(); i++) {
                        UserInfo info = user.getProviderData().get(i);
                        Util.logassert(info.getProviderId() + ", email = " + info.getEmail()); // both empty
                        Util.logassert("current provider = " + info.getProviderId() + " - " + info);
                    }

                } else {
                    Util.logassert("onAuthStateChanged user logged out");
                }
                // ...

            }
        };
        mAuth.addAuthStateListener(mAuthListener);

        // Firebase Facebook TapAuth
        // Initialize Facebook Login button

        mCallbackManager = CallbackManager.Factory.create();

        LoginManager.getInstance().registerCallback(mCallbackManager, new FacebookCallback<LoginResult>() {
            @Override
            public void onSuccess(LoginResult loginResult) {
                Util.logassert("facebook:onSuccess:" + loginResult);
                handleFacebookAccessToken(loginResult.getAccessToken());
                Util.logassert("granted = " + loginResult.getRecentlyGrantedPermissions()); // output [email and public_profile]
                Util.logassert("denied = " + loginResult.getRecentlyDeniedPermissions());
            }

            @Override
            public void onCancel() {
                Util.logassert("facebook:onCancel");
                // ...
            }

            @Override
            public void onError(FacebookException error) {
                Util.logassert("facebook:onError" + error.getMessage());
                // ...
            }
        });

        FancyButton btnFacebook = (FancyButton) findViewById(R.id.btn_facebook_share);
        btnFacebook.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                LoginManager.getInstance().logInWithReadPermissions(LoginActivity.this, Arrays.asList("public_profile", "email"));
                Util.logassert("try facebook login");
            }
        });



        txtPassword = (EditText) findViewById(R.id.input_password);
    }



    private void handleFacebookAccessToken(AccessToken token) {
        Util.logassert("handleFacebookAccessToken:" + token);

        GraphRequest request = GraphRequest.newMeRequest(
                token,
                new GraphRequest.GraphJSONObjectCallback() {
                    @Override
                    public void onCompleted(
                            JSONObject object,
                            GraphResponse response) {
                        // Application code
                        Log.v("LoginActivity", response.toString());
                        Util.logassert("graph res = " + response.getRawResponse());

                        try {
                            /* successfully output email address from graph request here */
                            FbGraphEvent event = new FbGraphEvent(response.getJSONObject().getString("email"), response.getJSONObject().getString("name"));
                            EventBus.getDefault().postSticky(event);
                        } catch (Exception e) {
                            Log.e("MomInvoice", "Error in parsing json fb graph", e);
                        }
                    }
                });
        Bundle parameters = new Bundle();
        parameters.putString("fields", "email,name");
        request.setParameters(parameters);
        request.executeAsync();

        AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());

        mAuth.signInWithCredential(credential)
                .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        Util.logassert("signInWithCredential:onComplete:" + task.isSuccessful());


                        if (!task.isSuccessful()) {
                            Util.logassert("signInWithCredential failed coz = " + task.getException().getMessage());
                            Toast.makeText(LoginActivity.this, "Authentication failed :(",
                                    Toast.LENGTH_SHORT).show();
                        }

                    }
                });
    }


    @Override
    public void onStart() {
        super.onStart();
        Util.logassert("masuk onStart LoginActivity");
    }

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

    @Override
    protected void onDestroy() {
        if (mAuthListener != null) {
            mAuth.removeAuthStateListener(mAuthListener);
        }
        super.onDestroy();
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        super.onActivityResult(requestCode, resultCode, data);

        if (mCallbackManager != null) {
            mCallbackManager.onActivityResult(requestCode, resultCode, data);
            Util.logassert("hasilx " + requestCode + " = " + resultCode);
        }

    }
}

Ответы

Ответ 1

после чтения сообщения в google-группе firebase-talk здесь https://groups.google.com/forum/#!topic/firebase-talk/gPGNq-IkTLo, я узнал ответ. Проблема произошла, потому что я использую "Разрешить создание нескольких учетных записей с тем же адресом электронной почты" в методе входа в Firebase Auth.

Поэтому я меняю этот параметр на: "Предотвращение создания нескольких учетных записей с тем же адресом электронной почты", теперь он может работать исправно. Это просто. Это правда, мне нужно больше логики для объединения учетных записей с тем же адресом электронной почты, но все в порядке.

Может быть, все остальные, имеющие одну и ту же проблему, могут также попробовать это, и, надеюсь, оно также решит.

Ответ 2

Я нашел ту же проблему, когда для электронной почты было установлено значение "-" в firebase auth. Мне не хватало разрешения на чтение электронной почты, на которое я исправил:

LoginButton mFacebookSignInButton = (LoginButton) findViewById(R.id.facebook_sign_in_button);
mFacebookSignInButton.setReadPermissions("email", "public_profile");

Надеюсь, это поможет кому-то в будущем иметь такую же проблему.

Ответ 3

Я нашел решение. Вот мой код

import android.app.ProgressDialog;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;

import com.app.pizzawheel.Common.Globals;
import com.facebook.AccessToken;
import com.facebook.AccessTokenTracker;
import com.facebook.CallbackManager;
import com.facebook.FacebookCallback;
import com.facebook.FacebookException;
import com.facebook.FacebookSdk;
import com.facebook.GraphRequest;
import com.facebook.GraphResponse;
import com.facebook.login.LoginManager;
import com.facebook.login.LoginResult;
import com.facebook.login.widget.LoginButton;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FacebookAuthProvider;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import android.support.annotation.NonNull;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.Arrays;

public class GetStartedActivity extends AppCompatActivity {

    CallbackManager callbackManager;
    AccessTokenTracker accessTokenTracker;
    AccessToken accessToken;
    private FirebaseAuth mAuth;
    ProgressDialog progress;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FacebookSdk.sdkInitialize(this.getApplicationContext());

        setContentView(R.layout.activity_getstarted);
        getSupportActionBar().hide();
        mAuth = FirebaseAuth.getInstance();

        callbackManager = CallbackManager.Factory.create();
        final LoginButton loginButton = (LoginButton) findViewById(R.id.fb_login);
        final ImageButton btnFBLogin = (ImageButton)findViewById(R.id.btn_fb_login);
        loginButton.setReadPermissions("email", "public_profile");

        if (loginButton != null) {
            loginButton.registerCallback(callbackManager,
                    new FacebookCallback<LoginResult>() {
                        @Override
                        public void onSuccess(LoginResult loginResult) {
                            // App code
                            loginButton.setVisibility(View.INVISIBLE);
                            btnFBLogin.setVisibility(View.VISIBLE);
                            accessToken = loginResult.getAccessToken();
                            FBLogin();

                        }

                        @Override
                        public void onCancel() {
                            // App code
                        }

                        @Override
                        public void onError(FacebookException exception) {
                            // App code
                        }
            });
        }
        if(AccessToken.getCurrentAccessToken()!=null) {
            accessToken = AccessToken.getCurrentAccessToken();
            btnFBLogin.setVisibility(View.VISIBLE);
        }
        btnFBLogin.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                FBLogin();
            }
        });

    }

    private void FBLogin(){
        progress = new ProgressDialog(GetStartedActivity.this);
        progress.setMessage("Please Wait...");
        progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        progress.setCancelable(false);
        progress.show();

        AuthCredential credential = FacebookAuthProvider.getCredential(accessToken.getToken());
        mAuth.signInWithCredential(credential)
                .addOnCompleteListener(GetStartedActivity.this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {

                        if (task.isSuccessful()) {
                            GraphRequest request = GraphRequest.newMeRequest(accessToken, new GraphRequest.GraphJSONObjectCallback(){

                                @Override
                                public void onCompleted(JSONObject object, GraphResponse response) {
                                    progress.hide();
                                    progress.dismiss();
                                    try {
                                        Globals.email_address = object.getString("email");
                                        Globals.first_name = object.getString("first_name");
                                        Globals.last_name = object.getString("last_name");
                                    } catch (JSONException e) {
                                        e.printStackTrace();
                                    }

                                    Intent intent = new Intent(GetStartedActivity.this, WelcomeActivity.class);
                                    startActivity(intent);
                                    finish();
                                }
                            });
                            Bundle parameters = new Bundle();
                            parameters.putString("fields","id,email,first_name,last_name");
                            request.setParameters(parameters);
                            request.executeAsync();
                            // Sign in success, update UI with the signed-in user information

                        } else {
                            progress.hide();
                            progress.dismiss();
                            // If sign in fails, display a message to the user.
//                                    Log.w(TAG, "signInWithCredential:failure", task.getException());
//                                    Toast.makeText(FacebookLoginActivity.this, "Authentication failed.",
//                                            Toast.LENGTH_SHORT).show();
//                                    updateUI(null);
                        }

                    }
                });
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        callbackManager.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

Ответ 4

Некоторые учетные записи Facebook создаются с использованием мобильных номеров, поэтому, когда мы запрашиваем адрес электронной почты, мы получаем пустую строку.

На следующем изображении вы можете видеть, что учетная запись Facebook может установить своего основного контакта в качестве адреса электронной почты или номера мобильного телефона. Таким образом, если человек пометил номер мобильного телефона как основной, его адрес электронной почты не может быть восстановлен.

В моем случае я забыл подтвердить свою учетную запись Facebook, поэтому изначально мой адрес электронной почты даже не отображался в основном контакте. Итак, если вы не получаете адрес электронной почты, перейдите в Общие настройки и посмотрите, установлен ли основной аккаунт на адрес электронной почты или нет.

enter image description here

Ответ 5

@Мухаммад Райхан. Я также сделал то же самое. Я использовал FirebaseUser.updateEmail() после того, как получил электронное письмо от Fb GraphRequest. Он работал без проблем.

Ответ 6

У меня была такая же проблема. Это было вызвано созданием входа в Facebook без каких-либо разрешений на чтение, протестировало вход в систему, все ОК - затем добавили разрешения для чтения для электронной почты.

Facebook показал обновленный диалог прав доступа, но Firebase не захватил новое электронное письмо.

Я должен был удалить пользователя в консоли Firebase. Разыграл приложение снова, вошел в систему, и теперь электронная почта показывает.

Ответ 7

Я решил так

 _facebookLoginButton.setReadPermissions(Arrays.asList(
                "email", "public_profile"));
            _facebookLoginButton.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
                @Override
                public void onSuccess(LoginResult loginResult) {
                    credential = FacebookAuthProvider.getCredential(facebookAccessToken.getToken());
                    GraphRequest request = GraphRequest.newMeRequest(
                        loginResult.getAccessToken(), (me, response) -> {

                            if (response.getError() != null) {
                                // handle error
                                hideProgress();
                                Logcum.w(" GirisActivity ", "facebookSignIn: Giriş anında hata oluştu", response.getError().getException());
                            } else {

                                user_email = response.getJSONObject().optString("email");
                                facebookSignInCredential(user_email);

                            }
                        });

                    Bundle parameters = new Bundle();
                    parameters.putString("fields", "email");
                    request.setParameters(parameters);
                    request.executeAsync();

                }

                @Override
                public void onCancel() {
                    Log.d(TAG, "facebook:onCancel");
                    hideProgress(); // progresi gizle

                }

                @Override
                public void onError(FacebookException error) {
                    Log.d(TAG, "facebook:onError", error);
                    hideProgress(); // progresi gizle
                }
            });

Ответ 8

@Мухаммед Райхан. Я тоже сделал то же самое. Я использовал updateUI (currentUSer) после этого я получил письмо от Authentication.CurrentUser.getEmail(). Работало без проблем.