Android Firebase项目:如何修改代码实现仅存量用户OTP登录验证
Hey there! Let's fix this issue where your app sends OTPs to any phone number—even if the user isn't in your existing database. Here's how to adjust your code to only let pre-registered users proceed with login:
Key Change: Check User Existence Before Sending OTP
The core fix is adding a database check before starting the OTP process. We'll verify if the provided phone number exists in your Firebase Realtime Database first, and only send the OTP if it does.
Step-by-Step Code Modifications
Add Required Imports
First, add these imports at the top of your file to handle Firebase Database listeners:import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.ValueEventListener;Initialize Database Reference
Make sure your Firebase Database reference is set up properly inonCreate:@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); // ... existing view hooks ... // Initialize Firebase Database reference (update "users" to your actual node name) database = FirebaseDatabase.getInstance(); reference = database.getReference("users"); }Rewrite the
sendOtpMethod
Update thesendOtpmethod to include the database check before sending the OTP. Choose the query that matches your database structure:public void sendOtp(View view){ if(mobileNumber.getText().toString().equals("")){ errorMessage.setText("Please Enter phone number"); errorMessage.setVisibility(View.VISIBLE); }else if(mobileNumber.getText().toString().length() != 10){ errorMessage.setText("PhoneNumber is Invalid"); errorMessage.setVisibility(View.VISIBLE); }else{ final String phoneNum= "+91"+mobileNumber.getText().toString(); // Option 1: Use this if users have a "phoneNumber" field (most common structure) reference.orderByChild("phoneNumber").equalTo(phoneNum).addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { if(dataSnapshot.exists()){ // User exists: proceed to send OTP PhoneAuthProvider.getInstance().verifyPhoneNumber( phoneNum, 60, TimeUnit.SECONDS, TaskExecutors.MAIN_THREAD, mCallbacks); Toast.makeText(context, "OTP sent to "+phoneNum, Toast.LENGTH_SHORT).show(); verifyOtpAndLogin.setVisibility(View.VISIBLE); errorMessage.setVisibility(View.GONE); }else{ // User doesn't exist: show error errorMessage.setText("This phone number is not registered with us"); errorMessage.setVisibility(View.VISIBLE); verifyOtpAndLogin.setVisibility(View.GONE); } } @Override public void onCancelled(@NonNull DatabaseError databaseError) { Toast.makeText(context, "Database error: "+databaseError.getMessage(), Toast.LENGTH_SHORT).show(); } }); // Option 2: Use this if phone number is the direct key of user nodes // reference.child(phoneNum).addListenerForSingleValueEvent(new ValueEventListener() { // @Override // public void onDataChange(@NonNull DataSnapshot dataSnapshot) { // if(dataSnapshot.exists()){ // // Send OTP logic here // }else{ // // Show error message // } // } // @Override // public void onCancelled(@NonNull DatabaseError databaseError) { // Toast.makeText(context, "Database error: "+databaseError.getMessage(), Toast.LENGTH_SHORT).show(); // } // }); } }
Important Notes
- Match Your Database Structure: Pick either Option 1 or 2 based on how you store user data:
- Option 1 works if users are stored under a
usersnode with aphoneNumberfield (e.g.,users/{userId}/phoneNumber: "+91xxxxxxxxx"). - Option 2 works if you use the full phone number (with country code) as the user node key (e.g.,
users/+91xxxxxxxxx).
- Option 1 works if users are stored under a
- Security Tip: While this frontend check blocks most invalid requests, add a backend check with Firebase Cloud Functions to ensure no unauthorized users can bypass this restriction.
Full Modified Code
Here's the complete updated LoginActivity class with all changes included:
package com.lalbhaibrokers.lalbhaibrokerspvtltd; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.TextView; import android.widget.Toast; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.TaskExecutors; import com.google.android.material.textfield.TextInputEditText; import com.google.firebase.FirebaseException; import com.google.firebase.auth.AuthResult; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.PhoneAuthCredential; import com.google.firebase.auth.PhoneAuthProvider; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.ValueEventListener; import java.util.concurrent.TimeUnit; public class LoginActivity extends AppCompatActivity { //Variables TextInputEditText mobileNumber, otp; TextView errorMessage, sendOtp, verifyOtpAndLogin; Context context = this; String verificationCode; boolean isVerified; FirebaseDatabase database; DatabaseReference reference; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); //Hooks mobileNumber = findViewById(R.id.mobile_no_editText); otp = findViewById(R.id.otp_editText); errorMessage = findViewById(R.id.error_message_textView); sendOtp = findViewById(R.id.send_otp_btn); verifyOtpAndLogin = findViewById(R.id.verify_otp_and_login); // Initialize Firebase Database reference database = FirebaseDatabase.getInstance(); reference = database.getReference("users"); verifyOtpAndLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String userCode = otp.getText().toString(); if (!userCode.isEmpty()) { verifyCode(userCode); //verifying the code Entered by user } } }); } //method for start the OTP process public void sendOtp(View view){ if(mobileNumber.getText().toString().equals("")){ errorMessage.setText("Please Enter phone number"); errorMessage.setVisibility(View.VISIBLE); }else if(mobileNumber.getText().toString().length() != 10){ errorMessage.setText("PhoneNumber is Invalid"); //we can only accept phoneNumbers with 10 digits errorMessage.setVisibility(View.VISIBLE); }else{ final String phoneNum= "+91"+mobileNumber.getText().toString(); //we have to add country code in order to receive OTP // Check if user exists in database before sending OTP reference.orderByChild("phoneNumber").equalTo(phoneNum).addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { if(dataSnapshot.exists()){ // User exists: send OTP PhoneAuthProvider.getInstance().verifyPhoneNumber( phoneNum, // Phone number to verify 60, // Timeout duration TimeUnit.SECONDS, // Unit of timeout TaskExecutors.MAIN_THREAD, // Activity (for callback binding) mCallbacks); // OnVerificationStateChangedCallbacks Toast.makeText(context, "OTP sent to "+phoneNum, Toast.LENGTH_SHORT).show(); verifyOtpAndLogin.setVisibility(View.VISIBLE); errorMessage.setVisibility(View.GONE); }else{ // User doesn't exist: show error errorMessage.setText("This phone number is not registered with us"); errorMessage.setVisibility(View.VISIBLE); verifyOtpAndLogin.setVisibility(View.GONE); } } @Override public void onCancelled(@NonNull DatabaseError databaseError) { Toast.makeText(context, "Database error: "+databaseError.getMessage(), Toast.LENGTH_SHORT).show(); } }); } } //method that verify the OTP received or not private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() { @Override public void onCodeSent(@NonNull String s, @NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken) { super.onCodeSent(s, forceResendingToken); verificationCode = s; //verification code that should be received by phoneNumber } @Override public void onVerificationCompleted(@NonNull PhoneAuthCredential phoneAuthCredential) { String code = phoneAuthCredential.getSmsCode(); //verification code that actually received by phoneNumber if (code != null) { verifyCode(code); } } @Override public void onVerificationFailed(@NonNull FirebaseException e) { Toast.makeText(context, "Verification Failed: OTP not received", Toast.LENGTH_SHORT).show(); } }; //verifying the OTP public void verifyCode(String code) { PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationCode, code); //comparing both verification code signin(credential); } //signing in the User to update in database private void signin(PhoneAuthCredential credential) { FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(); firebaseAuth.signInWithCredential(credential).addOnCompleteListener(new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { if (task.isSuccessful()) { Toast.makeText(context, "Verification Complete", Toast.LENGTH_SHORT).show(); isVerified=true; Intent intent = new Intent(context, UserDashboard.class); startActivity(intent); finish(); } else { Toast.makeText(context, "Verification Failed: OTP wrong", Toast.LENGTH_SHORT).show(); } } }); } }
内容的提问来源于stack exchange,提问作者Hardik Trivedi

