Not changing screen based on Authentication Status Flutter - firebase

I am trying to go to the home screen or stay on auth screen based on whether or not the user is successfully authenticated. Using Firebase authentication's authStateChanges and a stream builder.
I get no error codes and the console reads
D/FirebaseAuth(21665): Notifying id token listeners about user ( pG6pORODSGMi21fuaoql29hqXZp2 ).
D/FirebaseAuth(21665): Notifying auth state listeners about user ( pG6pORODSGMi21fuaoql29hqXZp2 ).
so the authentication is successful and when I hot restart the app it goes to the home screen and displayed info as it should.
Here is the code
FutureBuilder(
future: _initialization,
builder: (context, appsnapShot) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: {
SignupScreen.routeName: (ctx) => SignupScreen(),
AuthScreen.routeName: (ctx) => AuthScreen(),
HomeScreen.routeName: (ctx) => HomeScreen(),
UserPhoneAdds.routeName: (ctx) => UserPhoneAdds(),
PhoneAddForm.routeName: (ctx) => PhoneAddForm(),
EditPhoneScreen.routeName: (ctx) => EditPhoneScreen(),
},
home: appsnapShot.connectionState != ConnectionState.done
? SplashScreen()
: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return SplashScreen();
}
if (snapshot.hasData) {
return HomeScreen();
} else {
return AuthScreen();
}
},
),
);
});
FYI-this is off of a course and in the app it came from this works correctly
Thank you for any help.

The authStateChanges doesn't return a snapshot but a User as you can see in the officaial documentation:
FirebaseAuth.instance
.authStateChanges()
.listen((User user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
}
});
So you sould just check if User is null or not.

Related

What is the best way to create a Flutter/Firebase wrapper that auto-redirects based on auth status?

I am building a flutter app with a Firebase backend. The issue is redirecting the user to the Home Screen if they are signed in and to the Auth Screens if they are signed out. When a user signs out while at the home screen, they are automatically redirected to the auth pages, however, when they sign in, the app stays on that page and I have to restart for it to go to the home screen.
This is my app structure
main - Splash - Wrapper - Home/Auth
My wrapper code is
final auth = Provider.of<AuthService>(context);
return StreamBuilder<User?>(
stream: auth.user,
builder: (_, AsyncSnapshot<User?> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
final User? user = snapshot.data;
return user == null ? AndroidAuth() : AndroidHome();
} else {
return Scaffold(
body: CircularProgressIndicator(),
);
}
},
);
}
my main where I initialize Firebase
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(const MyApp());
}
Material App is wrapped in multiprovider.
return MultiProvider(
providers: [
Provider<AuthService>(
create: (_) => AuthService(),
)
],
child: MaterialApp(
title: 'Flightbag',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const AndroidSplash(),
),
);
I get auth state changes like so:
Stream<User?>? get user {
return _auth.authStateChanges().map(_userFromFirebase);
}
And create User object like :
User? _userFromFirebase(auth.User? user) {
if (user == null) {
return null;
}
return User(user.uid, user.email);
}
Please help. I have been stuck on this for days.

Flutter Firebase Auth - change home widget if the user is logged in

I'm building an app that supports only google login using google_sign_in package. When the app is run, it first checks if FirebaseAuth is alive. If user in FirebaseAuth.instance.authStateChanges().listen((User? user) is not null, HomePage() should be shown. If the user is null it should go to AuthPage() which has a google sign-in button.
The code for main.dart is shown below.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
Widget _defaultHome = HomePage();
// Check if user already logged in
FirebaseAuth auth = FirebaseAuth.instance;
auth.authStateChanges().listen((User? user) {
if (user == null) {
_defaultHome = AuthPage();
}
print(user);
});
runApp(MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => SignInProvider()),
ChangeNotifierProvider(create: (_) => DataProvider()),
],
child: new MaterialApp(
title: 'Mentea',
home: _defaultHome,
routes: {
'auth': (context) => AuthPage(),
'home': (context) => HomePage(),
},
),
));
}
But when I run it, console gives
I/flutter (14933): null
which means no logged in user, but the emulator shows HomePage() instead of AuthPage(). Anybody know how to fix this? I tried changing 'home:' attribute to 'initialRoute:', but it doesn't work either (directs to HomePage() while printing null).
String _defaultHome = 'home';
...
auth.authStateChanges().listen((User? user) {
if (user == null) {
_defaultHome = 'auth;
}
});
...
child: new MaterialApp(
title: 'Mentea',
initialRoute: _defaultHome,
routes: {
'auth': (context) => AuthPage(),
'home': (context) => HomePage(),
},
),
We can assign a StreamBuilder that listens to FirebaseAuth state changes, to the home property:
StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (user) {
return user == null ? AuthPage() : HomePage(),
}
),
Follows a full example:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => SignInProvider()),
ChangeNotifierProvider(create: (_) => DataProvider()),
],
child: MaterialApp(
title: 'Mentea',
home: StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (user) {
return user == null ? AuthPage() : HomePage(),
},
),
routes: {
'auth': (context) => AuthPage(),
'home': (context) => HomePage(),
},
),
));
}

Some Problems In Flutter Firebase Login

I tried coding a login and registration form in an app with firebase auth. There are some problems in my login from.
Please look at this loginForm function which will execute when login button is pressed.
Future loginForm() async {
FormState formSate = _formKey.currentState;
if (formSate.validate()) {
final User firebaseUser = (await firebaseAuth
.signInWithEmailAndPassword(
email: _emailcontroller.text,
password: _passwordcontroller.text)
.catchError((errMsg) {
displayToast("Error: " + errMsg.toString(), context);
}))
.user;
if (firebaseUser != null) {
setState(() {
loading = true;
});
usersRef.child(firebaseUser.uid).once().then((DataSnapshot snap) async {
if (snap.value != null) {
SharedPreferences preferences =
await SharedPreferences.getInstance();
preferences.setString("email", _emailcontroller.text);
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) {
return LocationHome();
}));
displayToast("Succesfully LoggedIn!", context);
} else {
firebaseAuth.signOut();
displayToast("No user found! Please try SignUp", context);
}
});
} else {
displayToast("Error Occured! Cannot log you in", context);
}
}
}
}
You can see here that after login I have programmed it to navigate to Location Page.
But to make user stay logged in I have used a StreamBuilder and checking if snapshot.hasdata in the main file
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MaterialApp(
title: 'TaakStore',
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
if (snapshot.hasData) {
print(snapshot);
return Home();
} else {
return Login();
}
},
),
));
}
In this, you can see that if snapshot.hasdata it should navigate to home screen and if not data then nav to the login screen. The first time when a user opens the app the snapshot has no data so it will open a login screen which is perfect. But the problem is when the user clicks on login button instead of going to location screen it is directly going to home screen because the snapshot has data which is ridiculous.
If someone understand my problem please help me
I think the problem is occuring by using the streamBuilder as streamBuilder continously keeps looking for stream or data and as soon it found the appropriate data it performs the assigned function which is navigating the user to the homeScreen() instead of LocationScreen()
Repleace StreamBuilder on the Main() with the bellow code:
if (FirebaseAuth.instance.currentUser != null) {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Home(),
),
);
} else {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Location(
),
),
);
}
This will not keep on looking for the stream and only execute the function once when the app is restarted. The same method have been suggested by FirebaseFlutter .

How to redirect to login page after signout button is pressed in flutter

Here i am using firebase phone authentication, so whenever i click sigout button it gets signed out from firebase instance but it doesn't redirect to the login page.
Here is the code for the sigout button
return Scaffold(
body: Center(
child: RaisedButton(
child: Text('Signout'),
onPressed: () {
AuthService().signOut();
},
)
)
);
Here is the code for AuthService
class AuthService {
handleAuth() {
return StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (BuildContext context, snapshot) {
if (snapshot.hasData) {
return HomeScreen();
} else {
return LoginPage();
}
});
}
//Sign out
signOut() {
FirebaseAuth.instance.signOut();
}
//SignIn
signIn(AuthCredential authCreds) {
FirebaseAuth.instance.signInWithCredential(authCreds);
}
signInWithOTP(smsCode, verId) {
AuthCredential authCreds = PhoneAuthProvider.getCredential(
verificationId: verId, smsCode: smsCode);
signIn(authCreds);
}
}
How do i redirect it to the login page when signout button is pressed?
Call your login screen and clear out all the previous paths
you can use below shown code
it will clear all the paths and your history and launch new LoginScreen
Navigator.of(context).pushAndRemoveUntil(
new MaterialPageRoute(
builder: (context) =>
new LoginScreen()),
(route) => false);

Flutter firebase auth security check

I'm new to flutter and i'm using firebase auth as my authentication to the application. I'm from a php background and do I need to check if the user is logged in every new page like we check state in php. I'm using this method to handle auth,
Widget handleCurrentScreen() {
return StreamBuilder<FirebaseUser>(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Scaffold(
appBar: AppBar(
title: Text("Splash"),
),
body: Text("Splash"),
);
} else {
if (snapshot.hasData) {
return HomePage(_auth,_googleSignIn);
}
return LoginScreen3();
}
}
);
}
My question is here once I'm in this page HomePage(), Do I need to verify auth as a good practice or to prevent from hackers?

Resources