I am currently trying to get the user id in Flutter with Firebase authentication, and I am initializing a variable in initState because I want to use that variable later for a Future call to fetch data from Firebase Real-time database with future builder. (This doesn't work because I have to reload the screen each time and then, get the user id).
And here is my code,
final FirebaseAuth auth = FirebaseAuth.instance;
User user;
String currentUId;
String currentEmail;
#override
void initState() {
super.initState();
user = auth.currentUser;
// Future.delayed(Duration(seconds: 5));
// sleep(Duration(seconds: 5));
currentUId = user.uid;
currentEmail = user.email;
print(currentUId);
}
I tried using sleep, but it didn't work, Is there another place where I can put sleep in, that will make the program wait for the user id then run the rest of the program?
The auth.currentUser variable is initialized automatically by Firebase, once it's verified the user's authenticate state. But since verifying the state may require a call to the server, this may not have completed by the time your currentUId = user.uid runs.
Instead of trying to wait for the result with sleep calls, I recommend using an auth state listener as shown in the documentation on handling authentication state. This gives you a Stream<User>, which you can easily feed into a StreamBuilder.
For a longer example, also see: How to use .currentUser method in flutter
Related
I have made a sign-in page, and a sign-up page with Firebase Authentication in Flutter and Dart.
After the sign up, I'm trying to retrieve the current user's displayName, however, when I try retrieving it, I seem to get not the current one, but the one that I signed up with before this one.
However, when I for example hot-restart the app, I get the current user's details just fine.
I try to retrieve the current user's displayName property with this code:
static String? getUsername() {
return FirebaseAuth.instance.currentUser?.displayName!;
}
The way I call this, is I initialize a variable to store the username which I get from the method, on a different dart file, different from the signUp page I got. I also call this method in the initState() method.
This is how I sign-up the user and set the displayName:
static void signUpUser(String username, String emailAddress, String password) async {
try {
final credential =
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: emailAddress,
password: password,
);
// Here I set the displayName property
await credential.user!.updateDisplayName(username);
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {}
else if (e.code == 'email-already-in-use') {}
} catch (e) {}
}
I tried to use the user.reload(), and FirebaseAuth.userChanges() functions, but these did not seem to fix my problem.
Maybe I'm trying to retrieve the displayName property wrong, what am I missing? I'm quite new to developing my own apps and working with Firebase.
The Future that updateDisplayName returns completes when the call has been made to the underlying Firebase SDK. It does not automatically update the user profile in your application at that point though. That will only happen automatically once every hour (when the SDK refreshes the ID token on which that profile is based), or when the user signs out and in again.
To force a refresh of the profile from your application code outside of those automatic conditions, you can call reload() on the user object.
I'm implementing firebase authentication in flutter application but while trying to get user uid , it is crashing and show noSuchMethodError uid is null , if anyone could help , it is deeply appreciated
That's how i init my variables
class _UserRegistrationState extends State<UserRegistration> {
FirebaseAuth auth;
DocumentReference reference;
Reference storage;
PickedFile imageUri;
final ImagePicker _imagePicker = new ImagePicker();
#override
void initState() {
super.initState();
auth = FirebaseAuth.instance;
// the uid is where the logcat is pointing too and it is null
reference = FirebaseFirestore.instance.collection('users').doc(auth.currentUser.uid);
storage = firebase_storage.FirebaseStorage.instance.ref('avatar').child(auth.currentUser.uid);
}
When you sign in to Firebase Authentication, the SDK automatically persists the user's credentials in local storage. When you restart the app, the SDK tries to restore the user's authentication state from the stored credentials. This requires that it calls the servers to get a new ID token, and for example to check if the account was deleted/disabled in the meantime.
Depending on the platform where you run your code, the calls to the server may have completed before your auth.currentUser runs, or not. To safely respond to the user state, always use an auth state listener as shown in the FlutterFire documentation on responding to auth state changes:
#override
void initState() {
super.initState();
auth = FirebaseAuth.instance;
FirebaseAuth.instance.authStateChanges().listen((User user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
reference = FirebaseFirestore.instance.collection('users').doc(auth.currentUser.uid);
storage = firebase_storage.FirebaseStorage.instance.ref('avatar').child(auth.currentUser.uid);
}
});
}
currentUser → User?
Returns the current User if they are currently signed-in, or null if not.
So most likely thing is that you are not logged in and therefore passing null to reference
Using Flutter 1.20.2.
My Flutter app uses Firestore as it's backend database. For the current version I am using and throughout the development of this mobile app I have noticed that if my app is in the background for a period of time (could be a few mins) then when I bring the app back into the foreground the queries are very slow to return data. This does not happen on iOS. It only happens on Android.
I use CircularProgressIndicators when my app is busy retrieving data from Firestore. I am using a solid state management setup where each of my Views have a model that extends a BaseModel:
class BaseModel extends ChangeNotifier {
ViewState _state = ViewState.Idle;
ViewState get state => _state;
bool isDisposed = false;
void setState(ViewState viewState) {
_state = viewState;
if (!isDisposed) {
notifyListeners();
}
}
#override
void dispose() {
isDisposed = true;
super.dispose();
}
}
My views then use my view specific models in the following way:
#override
Widget build(BuildContext context) {
return BaseView<MyProfileModel>(
//onModelReady: (model) => model.initialise(Provider.of<User>(context, listen: false)),
onModelReady: (model) => model.initialise(),
builder: (context, model, child) => Scaffold(
resizeToAvoidBottomInset: false,
...
I do not use the AppLifecycleState class yet to do anything special when the app is in the background or is resumed from the background.
When my model is busy retrieving data I show busy circular progress indicators.
The issue is that when I resume my app from the background into the foreground, sometimes the app could be busy for up to 1 minute before it retrieves the data - but only the first time after being back in the foreground. All subsequent calls are normal. Sometimes, it even hangs on first attempt to get data after coming back to the foreground.
I feel like I am not implementing a best practice in relation to resuming an app into the foreground that uses the Firestore database. I have a suspicion that it has something to do with re-establishing the Firestore connection and/or local cache. My App uses the default settings for these.
All of my Firestore API calls are contained in it's own class and I call it the same way each time:
await Firestore.instance
.collection(DBStrings.COLLECTION_AD_MESSAGES)
.document(ad.adId)
.collection(DBStrings.COLLECTION_CHILD_AD_MESSAGES)
.document()
.setData({
// Set fields...
}).catchError((e) {
res = false;
});
Can someone give me some insight into this issue and what could be potentially causing it?
It seem to me that your app is loosing the connection and the data retrieved is from the cache. My suggestion is for you to try to change the backend data from the Firebase console while your app is in the background, then test to see if the retrieved data is the updated or the old one.
If the data is the old one, it means your app could not restore the connection. To overcome this problem you need to check the auth status (if used) and to check the connection status. A simple way to identify connection status and not allow the app to take a very long time before going cache, is to force the app to ask data from remote and provide a timeout, like this:
QuerySnapshot snapshot = await query.getDocuments(source: Source.server).timeout(
_timeoutDuration,
// this or any other callback to handle timeout
onTimeout: () => query.getDocuments(source: Source.cache));
If you are using auth, you can check the auth status by calling:
FirebaseUser currentUser = await _auth.currentUser();
if (currentUser != null) {
// Handle your auth problem here
}
If you are not using auth and the app is retrieving the data from the server after this long period, check if the app would come back faster without the firebase query.
I've created a login and registration screen that works with my Flutter app, using Firebase as the backend authentication service. I'm able to switch between the login, registration and reset password screens well.
The Issue
At the moment, the registration screen accepts any email address that is entered, whether or not it is real. For example, if I were to type in gvevg#gverwbgw.com, it would allow the user to register. This is obviously an issue, when it comes to fake accounts and spam etc.
The Aim
I would basically like to be able to edit my code, to automatically generate an email address verification email, which prevents the user from signing in, before their email address has been verified. The code I have made uses a Future, FirebaseAuth and async/await to make this happen.
My Current Code
Firstly, I define an AuthBase abstract class, that creates the 'createUserWithEmailAndPassword' function (amongst others) as follows:
abstract class AuthBase {
Stream<User> get onAuthStateChanged;
Future<User> currentUser();
Future<User> createUserWithEmailAndPassword(String email, String password);
}
Then, I create an Auth function, that implements AuthBase, gets the current user from Firebase and creates the registration Future function, as follows:
class Auth implements AuthBase {
final _firebaseAuth = FirebaseAuth.instance;
// This creates the user ID token variable (if one doesn't already exist) which is then populated using one of the login methods.
User _userFromFirebase(FirebaseUser user) {
if (user == null) {
return null;
}
return User(uid: user.uid);
}
// This helps to get the user from Google Firebase, noting if there is or isn't a user with those login details already.
#override
Stream<User> get onAuthStateChanged {
return _firebaseAuth.onAuthStateChanged.map(_userFromFirebase);
}
// This identifies the current user, who is logged in at the time.
#override
Future<User> currentUser() async {
final user = await _firebaseAuth.currentUser();
return _userFromFirebase(user);
}
// This creates the user account for an email-and-password sign-in, with firebase, if it doesn't already exist.
#override
Future<User> createUserWithEmailAndPassword(
String email, String password) async {
final authResult = await _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password);
return _userFromFirebase(authResult.user);
}
}
My Question
How do I edit my code, so that it allows me to implement email verification automatically for any user that wants to sign in with email? I believe the sendEmailVerification() function must use FirebaseUser, although I am not sure how to implement it here. I would appreciate any help. Thanks!
Email+password authentication requires nothing more than that the user knows the combination of email+password. It doesn't in itself require the email address to be verified to sign in. If you want the email address to be verified before allowing access to other data, you can do that by checking the user's token for the email_verified claim for example in the security rules of your database.
Also see:
How do I lock down Firebase Database to any user from a specific (email) domain?
Firebase email verification at SignUp
How to prevent user authentication in Firebase/Vue.js BEFORE email is verified
Only let pre-verified users log into Firebase
I am using Firebase authentication in my app and signing up a user with email and password. I want to get other users details (separate from the logged-in user) as well while a user is signed in with their own account. How can I get that information?
Values like email, display name and id (specific to authentication system) are available off of the Firebase User object. You can get a reference to the current logged in user off of the FIRAuth class. I provided links and class names for iOS, but other platforms are similarly structured.
If you want to store additional data for users, I would recommend including a users root node, using the uid off of the Firebase User object as the key for users child nodes.
//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 {
String user_id = auth.getCurrentUser().getUid();
DatabaseReference current_user_db = _Database.child(user_id);
current_user_db.child("name").setValue(name);
current_user_db.child("image").setValue("default");
startActivity(new Intent(SignupActivity.this, ProfileActivity.class));
finish();
}
}
});
}
});
It's not a security issue, but just a mean of how you treat personal information. You can store what you want in firebase so you can easily store when the user login his/her avatar url (aka facebook url) or just id or any other infos anyway, then retrieve it.
If you need to retrieve infos of users which are not using your apps beside, thden you can also easily via the facebook sdk with user permission of course. take care–