Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
732 views
in Technique[技术] by (71.8m points)

dart - How to get back to app home page after successful login in Flutter

I'm trying to implement the user authentification into my Flutter app that is supposed to work for both Android and iOS.

I am using the JWT for the authentification of the app's request to the server, so I provide the user with a JWT token at login and the app saves the token securely on the device and then uses the token to communicate with my server.

When the app launches, I run the HomePage where there is a if statement where app looks to the secure storage for a JWT token if there is no token, the app shows the login page.

HomePage class:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.orange,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'App Title'),
      routes: <String, WidgetBuilder>{
        '/login': (BuildContext context) => new SignInPage(),
      },
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  ...
  @override
  Widget build(BuildContext context) {

    storage.read(key: 'jwt_token').then((token) {
      logger.d('MAIN APP GOT TOKEN: ' + token.toString());
      if (token == null) {
        Navigator.pushReplacementNamed(context, '/login');
      }
    });

    return Scaffold(...);
  }
}

I tried Navigator.pushReplacementNamed, Navigator.pushNamed, Navigator.popAndPushNamed... All of those get me to the login page. So that's fine. My problem is, that it doesn't work the other way around.

When I login sucessfully (obtain a JWT token), I can't make the app to return to the home page. If I restart the application it correctly shows the home page (as now there is a JWT in the secure storage), so the token check works fine. It must be something in rerouting from the login page to the home page.

login page snippet:

if (serverResponse.containsKey('jwt_token')) {
    await storage.write(
         key: 'jwt_token', value: serverResponse['jwt_token']);
    Navigator.pushReplacementNamed(context, '/');

I tried also Navigator.pop and Navigator.pushNamed(context, '/'), Navigator.pushNamedAndRemoveUntil(context, '/', (route) => false), Navigator.pushReplacementNamed(context, '/'), non of which worked.

It looks like the page is changing, but it ends up being the login page again. I checked that the token is already inside the storage when the rerouting command is called. Also I have a debug message above the token check in the HomePage and the debug string is never printed after the login, so the Home page is simply not called at all.

Do you see something wrong in my code? How can I make it work?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The issue here is that you're checking the token on the home page build. So every time you start the screen, and the user is not logged in, it's being redirected to the login page correctly.

However, since you've used the Navigator.pushReplacementNamed, which is removing the home from your routes list, then if you try any option to move back the routing list, like with Navigator.pop, there's no home anymore on the routes list.

So you basically have two options to deal with, according to the behavior you want:

1. Login page as default

This is the most common approach I've seen in practice, where your first app screen is the login one, so you only send with Navigator.pushReplacementNamed to /home after the login succeeds, replacing login with home, and providing the way to return to login screen through a Logout feature.

2. Refactor the login you're using for the token check

Instead of using a check on the build, I suggest using the initState, to check the session and redirect, so you have a more concise life cycle usage for redirecting. Just a thing I didn't understand, is that you didn't define in your / route. Even though they seem the same, I've seen already some issues related to that, because the home defines which view is started with the app, and the / defines the route mapping, so try that as well, just in case, to remove other variable, if that's the case (I personally only use named routes, to become clear code-wise where the users is being sent).

Follows one example that uses the Option 1, but uses the suggested on the Option 2 of using the initState:

class LoginScreen extends StatefulWidget {
  @override
  _LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  void checkPreviousSessionAndRedirect() async {
    String loginToken = await LocalDb.getAttribute('loginToken');
    if (loginToken != null) {
      Navigator.pushNamedAndRemoveUntil(
          context, RouteViews.MAIN, (Route<dynamic> route) => false);
    }
  }

  void initState() {
    super.initState();
    checkPreviousSessionAndRedirect();
  }
...

Hope that helps, and if it doesn't, please let me know if you have any question / issues.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...