Flutter : User null pendant la déconnexion

a marqué ce sujet comme résolu.

Bonsoir ! :)

Afin de pratiquer un peu Flutter, je redéveloppe une app créée initialement avec Electron.

Cependant, je rencontre un problème. J’ai une API en NodeJS, qui gère l’authentification via JWT.

La connexion dans Flutter fonctionne bien, mais lorsque je me déconnecte, les champs du model User deviennent null juste avant que je sois redirigé sur l’écran de connexion, ce qui pose un problème.

Sachant que cette applications requière d’être connecté pour pouvoir l’utiliser.

Voici mon code actuel :

class User {
  late int id;
  late String email;
  late String firstname;
  late String lastname;
  late String role;

  User.fromJson(Map<String, dynamic> json) {
    id = json["id"];
    email = json["email"];
    firstname = json["firstname"];
    lastname = json["lastname"];
    role = json["role"];
  }
}
class AuthProvider extends ChangeNotifier {
  final String host = "http://localhost:3000/api";

  User? _user;
  String? _token;

  User? get currentUser {
    return _user;
  }

  Future<dynamic> login(String email, String password) async {
    try {
      http.Response response = await http.post(
        Uri.parse("$host/users/login"),
        headers: {
          "Content-Type": "application/json",
        },
        body: jsonEncode({
          "email": email,
          "password": password,
        }),
      );

      Map<String, dynamic> body = jsonDecode(response.body);

      _user = User.fromJson(body["user"]);
      _token = body["token"];

      notifyListeners();
    } catch (e) {
      rethrow;
    }
  }

  void logout() {
    _user = null;
    _token = null;

    notifyListeners();
  }
}
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  bool isUserLoggedIn(BuildContext context) {
    return Provider.of<AuthProvider>(context, listen: false).currentUser !=
        null;
  }

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (context) => AuthProvider(),
        ),
      ],
      child: MaterialApp.router(
        debugShowCheckedModeBanner: false,
        routerDelegate: RoutemasterDelegate(
          routesBuilder: (context) => RouteMap(routes: {
            LoginView.routeName: (routeData) =>
                MaterialPage(child: LoginView()),
            MainView.routeName: (routeData) => isUserLoggedIn(context)
                ? MaterialPage(child: MainView())
                : Redirect(LoginView.routeName),
            // ...
          }),
        ),
        routeInformationParser: RoutemasterParser(),
      ),
    );
  }
}

class MainView extends StatelessWidget {
  static String routeName = "/";

  const MainView({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    User user = Provider.of<AuthProvider>(context).currentUser!;

    return Layout(
        child: Text("${user.email}"),
    );
  }
}
class Layout extends StatelessWidget {
  final Widget child;

  const Layout({
    Key? key,
    required this.child,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("MyApp"),
        actions: [
          IconButton(
            onPressed: () {
              Provider.of<AuthProvider>(context, listen: false).logout();
              Routemaster.of(context).replace(LoginView.routeName);
            },
            icon: Icon(Icons.logout),
          ),
        ],
      ),
      body: child,
    );
  }
}

Comme vous pouvez le voir, j’utilise le package routemaster pour gérer les routes, ce qui me permet d’avoir des guards.

Dans ce code-ci, au moment du clique sur le bouton de déconnexion (voir dernier code), j’ai une erreur à la ligne 9 de l’avant dernier code. Normal, puisque j’indique que currentUser n’est jamais null, alors qu’il le deviens à la déconnexion.

Si j’enlève le !, j’ai pas d’erreur, mais j’ai l’email qui affiche null, ce que je ne souhaite pas.

Ce que je veux, c’est que si je me déconnecte, ça déconnecte l’utilisateur, et ça le redirige sur la vue de connexion. Mais sans afficher de valeur null entre temps, ce qui rend pas bien, en plus de devoir checker partout si l’utilisateur est OK, alors qu’il est censé l’être tout le temps car l’utilisateur doit être connecté pour voir n’importe quelle vue.

J’ai aussi essayé en inversant les deux lignes qui gèrent la déconnexion et la redirection, mais rien à faire.

Avez-vous une idée ?

Merci ! :)

+0 -0

Si on résume, tu as les étapes suivantes pour la déconnexion:

  • L’utilisateur est sur MainView, il appui sur Logout
  • On exécute la méthode Logout de AuthProvider.
    • La variable _user est passé à null
    • On notifie les listeners Ici on a un premier problème, car MainView est reconstruit, et _user vaut null !*
  • Ensuite on remplace la vue par la vue de Login.
  • La vue est en transition

* En soit, le code suivant n’est jamais réinterprêté:

MainView.routeName: (routeData) => isUserLoggedIn(context)
                ? MaterialPage(child: MainView())
                : Redirect(LoginView.routeName),

** De plus, la page MainView n’est pas supprimé immédiatement, elle reste le temps de la transition.


Pour résoudre le problème, je verrais bien le fait que tu passe l’objet User à MainView, sans faire usage de AuthProvider. Ceci empêche la mise à jour de la vue lorsque User est modifié. (Car oui, quand tu délogue l’utilisateur, il est modifié, il devient Null. Alors forcément la vue est reconstruire et ça coince).

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte