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 !