Flutter how to redirect to login if not authorized
Code should have single resonpsibility. Your getPost
method are doing 2 things at the same time. You should break this function such that it either successfully get the the post, or throw exception, and its caller will handle the exception. Its caller btw must be within build
method, because only build
method has BuildContext context
, something like this:
if (response.body.toString().contains('Token is Expired')) {
throw new Exception("Token is Expired") // you may want to implement different exception class
}
body: new Container(
padding: new EdgeInsets.only(bottom: 8.0),
color: Color(0xff2c3e4e),
child: FutureBuilder<List<Post>>(
future: api.getposts(),
builder: (context, snapshot) {
if (snapshot.hasError) {
// you might want to handle different exception, such as token expires, no network, server down, etc.
Navigator.push(
context,
MaterialPageRoute(builder: (context) => LoginScreen()),
);
return Container(); // return empty widget
}
if (snapshot.hasData) {
// do somthing with data
return Text('Some data here');
}
// has no data
return Text("Loading...");
}),
),
UPDATE
Thanks to @TruongSinh I got it figured out.
Followed his example and figured out the build navigator method which works:
if (snapshot.hasError) {
@override
void run() {
scheduleMicrotask(() {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => LoginScreen()),
);
});
}
run();
}
Update: added a package containing several guards like this
I did it with a StreamBuilder
to react on change and be able to display a SplashScreen when we don't know yet if the user is connected.
StreamBuilder authGuard = StreamBuilder(
stream: Auth.authState$,
builder: (context, snapshot) {
switch (snapshot.data) {
case AuthState.PENDING:
return SplashScreen();
case AuthState.UNAUTHENTICATED:
return SignInScreen();
case AuthState.AUTHENTICATED:
return HomeScreen();
default:
return SplashScreen();
}
},
);
So it will change screen depending on the AuthState:
return MaterialApp(
// ...
home: authGuard,
);
And my auth class
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:rxdart/rxdart.dart';
enum AuthState { PENDING, AUTHENTICATED, UNAUTHENTICATED }
class Auth {
static final FirebaseAuth _auth = FirebaseAuth.instance;
static final GoogleSignIn _googleSignIn = GoogleSignIn();
static Stream<AuthState> authState$ = FirebaseAuth.instance.onAuthStateChanged
.map((state) =>
state != null ? AuthState.AUTHENTICATED : AuthState.UNAUTHENTICATED)
.startWith(AuthState.PENDING);
static Future<FirebaseUser> signInWithGoogle() async {
// ...
}
}