【问题标题】:How to add extra fields to Firebase auth? Age & Gender如何向 Firebase 身份验证添加额外字段?年龄和性别
【发布时间】:2017-11-15 06:25:11
【问题描述】:

到目前为止,Firebase 给我留下了深刻的印象。但我想知道如何自定义我的用户电子邮件身份验证。我想添加以下字段:AgeGender 供用户在注册时填写。 p>

这是我的 SignUpActivity.java。

public class SignUpActivity extends AppCompatActivity {
private EditText inputEmail, inputPassword, signupInputUsername, signupInputAge;
private Button btnLinkLogin, btnSignUp, btnResetPassword;
private ProgressBar progressBar;
private FirebaseAuth auth;
private Spinner sexSpinner;
String defaultTextForSpinner = "Sex";
String[] arrayForSpinner = {"Male", "Female"};


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

    //Get Firebase auth instance
    auth = FirebaseAuth.getInstance();

    inputEmail = (EditText) findViewById(R.id.signup_input_email);
    signupInputUsername = (EditText) findViewById(R.id.signup_input_username);
    inputPassword = (EditText) findViewById(R.id.signup_input_password);
    signupInputAge = (EditText) findViewById(R.id.signup_input_birthday);
    sexSpinner = (Spinner)findViewById(R.id.spinner);
    sexSpinner.setAdapter(new CustomSpinnerAdapter(this, R.layout.spinner_row, arrayForSpinner, defaultTextForSpinner));

    btnSignUp = (Button) findViewById(R.id.btnSignUp2);
    btnLinkLogin = (Button) findViewById(R.id.btnorlogin);
    progressBar = (ProgressBar) findViewById(R.id.progressBar);
    EditText edittext = (EditText) findViewById(R.id.signup_input_birthday);


    edittext.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            //To show current date in the datepicker
            Calendar mcurrentDate = Calendar.getInstance();
            int mYear = mcurrentDate.get(Calendar.YEAR);
            int mMonth = mcurrentDate.get(Calendar.MONTH);
            int mDay = mcurrentDate.get(Calendar.DAY_OF_MONTH);

            DatePickerDialog mDatePicker=new DatePickerDialog(SignUpActivity.this, new DatePickerDialog.OnDateSetListener() {
                public void onDateSet(DatePicker datepicker, int selectedyear, int selectedmonth, int selectedday) {
                    // TODO Auto-generated method stub
                /*      Your code   to get date and time    */
                }
            },mYear, mMonth, mDay);
            mDatePicker.setTitle("Select birthday");
            mDatePicker.show();  }
    });


    btnSignUp.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            String email = inputEmail.getText().toString().trim();
            String password = inputPassword.getText().toString().trim();

            if (TextUtils.isEmpty(email)) {
                Toast.makeText(getApplicationContext(), "Enter email address.", Toast.LENGTH_SHORT).show();
                return;
            }

            if (TextUtils.isEmpty(password)) {
                Toast.makeText(getApplicationContext(), "Enter password.", Toast.LENGTH_SHORT).show();
                return;
            }

            if (password.length() < 6) {
                Toast.makeText(getApplicationContext(), "Password too short, enter minimum 6 characters.", Toast.LENGTH_SHORT).show();
                return;
            }

            progressBar.setVisibility(View.VISIBLE);
            //create user
            auth.createUserWithEmailAndPassword(email, password)
                    .addOnCompleteListener(SignUpActivity.this, new OnCompleteListener<AuthResult>() {
                        @Override
                        public void onComplete(@NonNull Task<AuthResult> task) {
                            Toast.makeText(SignUpActivity.this, "createUserWithEmail:onComplete:" + task.isSuccessful(), Toast.LENGTH_SHORT).show();
                            progressBar.setVisibility(View.GONE);
                            // 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.
                            if (!task.isSuccessful()) {
                                Toast.makeText(SignUpActivity.this, "Authentication failed." + task.getException(),
                                        Toast.LENGTH_SHORT).show();
                            } else {
                                startActivity(new Intent(SignUpActivity.this, MainActivity.class));
                                finish();
                            }
                        }
                    });

        }
    });
}

@Override
protected void onResume() {
    super.onResume();
    progressBar.setVisibility(View.GONE);
}

public class CustomSpinnerAdapter extends ArrayAdapter<String> {

    Context context;
    String[] objects;
    String firstElement;
    boolean isFirstTime;

    public CustomSpinnerAdapter(Context context, int textViewResourceId, String[] objects, String defaultText) {
        super(context, textViewResourceId, objects);
        this.context = context;
        this.objects = objects;
        this.isFirstTime = true;
        setDefaultText(defaultText);
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        if(isFirstTime) {
            objects[0] = firstElement;
            isFirstTime = false;
        }
        return getCustomView(position, convertView, parent);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        notifyDataSetChanged();
        return getCustomView(position, convertView, parent);
    }

    public void setDefaultText(String defaultText) {
        this.firstElement = objects[0];
        objects[0] = defaultText;
    }

    public View getCustomView(int position, View convertView, ViewGroup parent) {

        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View row = inflater.inflate(R.layout.spinner_row, parent, false);
        TextView label = (TextView) row.findViewById(R.id.spinner_text);
        label.setText(objects[position]);

        return row;
    }

}

【问题讨论】:

    标签: android firebase firebase-authentication


    【解决方案1】:

    当您使用带有用户名和密码的 Firebase 身份验证时,您在身份验证后可以获取的唯一数据是您从 FirebaseUser 对象获取的数据。正如您可能看到的,还有一些方法可以帮助您更轻松地获取数据,例如:getEmail()getDisplayName()getPhotoUrl() 等等。

    很遗憾,您无法将 agegender 等其他数据添加到 FirebaseUser 对象。如果您想添加额外的数据,您需要为您的用户创建一个模型类,然后将其存储在您的 Firebase 数据库中。

    你的模型类应该是这样的:

    public class User {
        String name, gender, emailAddress;
        int age;
    
        public User(String name, String gender, String emailAddress, int age) {
            this.name = name;
            this.gender = gender;
            this.emailAddress = emailAddress;
            this.age = age;
        }
    
        public String getName() {return name;}
        public void setName(String name) {this.name = name;}
    
        public String getGender() {return gender;}
        public void setGender(String gender) {this.gender = gender;}
    
        public String getEmailAddress() {return emailAddress;}
        public void setEmailAddress(String emailAddress) {this.emailAddress = emailAddress;}
    
        public int getAge() {return age;}
        public void setAge(int age) {this.age = age;}
    }
    

    【讨论】:

    • 如何使用setDisplayName 方法将自定义字段存储为JSON 对象,如示例{"display_name": "User 1", "age": 25, "gender": "Male", "points": 5371}?这是好习惯吗?我可以在 display_name 中存储的最大字符数是多少?
    • @TahaSami 这甚至是不可能的。 setDisplayName()` 方法接受一个字符串类型的参数。您不能使用 JSON 对象调用该方法。
    • 但我可以将 JSON 对象转换为字符串类型。顺便说一句,我自己尝试过,当我在显示名称字段中对长内容进行排序时,结果将为空,我不知道在哪里可以存储自定义字段,我不想使用 Firestore,因为有很多场景,比如连接失败,Firestore 和 Auth 之间也没有支持事务。我不知道为什么 Firebase 团队不向 Auth 添加新字段,而该字段将用于自定义字段。我不想使用 Firebase Functions,因为它也可能会失败。还有其他解决方案吗?
    • @TahaSami 使用额外的步骤将 JSON 对象转换为字符串可能是可能的。我不知道任何其他解决方案。但是,如果没有看到你的代码,我不能说你为什么得到空值。如果您正在寻找解决方案,请使用自己的MCVE 在 StackOverflow 上发布一个新问题,以便我和其他 Firebase 开发人员可以帮助您。除此之外,将其作为请求直接发送给 Firebase 团队。也许它会在某个时间点实现这样的功能。
    • 好的,感谢您的帮助,谢谢。
    【解决方案2】:

    一般来说,注册后,您可以为用户喜欢的图片创建一个节点树。 然后,您可以通过调用 FirebaseUser 获取带有用户密钥的信息。 我希望它有所帮助。如果您有任何问题,请告诉我。

    【讨论】:

    • users 是自定义表吗?
    • 是的,是@VaibS
    【解决方案3】:

    抱歉耽搁了,但我正在寻找如何存储更大的自定义数据 - 这是不可能的,但我是这样做的。

    在 displayName (Javascript) 中存储少量额外数据。

    result.user.updateProfile({
        displayName: gender + '|' + sex + '|' + username
    })
    .then(function () {
        console.log(`Profile updated.`);
    

    要检索数据,只需拆分 displayName (Node.js):

            return admin.auth().getUser(uid)
        })
        .then(userRecord => {
            displayName = userRecord.getDisplayName();
    
            parts = String(user.displayName).split('|');
    
            gender = parts[0];
            sex = parts[1];
            username = parts[2];
    

    【讨论】:

    • 这是一个很好的解决方法,谢谢。你知道我可以在这个领域输入多少信息吗?多少个字符?我在任何地方都找不到该信息。
    • 在我原来的回复中,我发现了使用“Firebase Auth Custom Claims”的“正确”方法。你可以在这里阅读:firebase.google.com/docs/auth/admin/custom-claims,这里有一段精彩的 NetNin​​ja 视频:youtube.com/…
    • 您应该使用您的 firebase db 或 firestore 来存储此类数据。使用 displayName 来存储这些信息可能会起作用,但它没有任何意义,而且是错误的!自定义声明也用于存储“角色”等信息。如:检查用户是否为管理员。如果您查看自定义声明的文档,您将看到警告和最佳实践。
    • 不建议使用自定义声明获取其他数据,请参阅 google 文档中的此声明 Custom claims are only used to provide access control. They are not designed to store additional data (such as profile and other custom data). While this may seem like a convenient mechanism to do so, it is strongly discouraged as these claims are stored in the ID token and could cause performance issues because all authenticated requests always contain a Firebase ID token corresponding to the signed in usershorturl.at/enENP
    【解决方案4】:

    注册新用户后,您将从 Firebase 收到用户生成的 uuid,此时您需要获取 uuid 并使用您提供的 uuid 在 Firestore 存储库/实时数据库中创建新用户条目,并且附加信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-17
      • 1970-01-01
      • 1970-01-01
      • 2016-10-15
      • 1970-01-01
      • 2019-03-17
      • 1970-01-01
      • 2017-05-14
      相关资源
      最近更新 更多