我正在尝试在我的Flutter应用程序中实现用户身份验证,该应用程序应该同时适用于Android和iOS。
我使用JWT来验证应用程序对服务器的请求,因此我在登录时为用户提供了一个JWT令牌,应用程序将令牌安全地保存在设备上,然后使用该令牌与服务器通信。
当应用程序启动时,我运行HomePage,其中有一条if语句,其中应用程序在安全存储中查找JWT令牌。如果没有令牌,应用程序将显示登录页面。
HomePage类:
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(...);
}
}
我试过Navigator.pushReplacementNamed
,Navigator.pushNamed
,Navigator.popAndPushNamed
...所有这些都会让我进入登录页面。所以这很好。我的问题是,反之亦然。
当我成功登录(获得JWT令牌)时,我无法使应用程序返回首页。如果我重新启动应用程序,它会正确地显示主页(因为现在安全存储中有一个JWT ),所以令牌检查工作正常。它必须是从登录页面重新路由到主页中的某些内容。
登录页面片段:
if (serverResponse.containsKey('jwt_token')) {
await storage.write(
key: 'jwt_token', value: serverResponse['jwt_token']);
Navigator.pushReplacementNamed(context, '/');
我还尝试了Navigator.pop
和Navigator.pushNamed(context, '/')
、Navigator.pushNamedAndRemoveUntil(context, '/', (route) => false)
、Navigator.pushReplacementNamed(context, '/')
,但都不起作用。
看起来页面正在改变,但它最终又变成了登录页面。当调用rerouting命令时,我检查了令牌已经在存储中。此外,我在HomePage中的令牌检查上方有一条调试消息,并且在登录后不会打印调试字符串,因此根本不会调用主页。
你在我的代码中发现了什么错误吗?我怎么才能让它工作呢?
发布于 2021-01-12 20:51:03
这里的问题是您正在检查主页build
上的令牌。因此,每次启动屏幕时,当用户未登录时,它都会被正确地重定向到登录页面。
但是,由于您已经使用了Navigator.pushReplacementNamed
,它将从您的路由列表中删除home
,因此如果您尝试使用任何选项来移回路由列表,就像使用Navigator.pop
一样,路由列表上将不再有home。
因此,根据您想要的行为,您基本上有两个选项需要处理:
1.默认登录页面
这是我在实践中看到的最常见的方法,在这种情况下,您的第一个应用程序屏幕是登录屏幕,因此只需在登录成功后使用Navigator.pushReplacementNamed
发送到/home
,将登录替换为主页,并提供通过Logout
功能返回登录屏幕的方法。
2.重构用于令牌检查的登录
我建议使用initState
来检查会话并重定向,而不是在build
上使用检查,这样您就可以使用更简洁的生命周期进行重定向。只有一件事我不明白,那就是你没有在你的/
路由中定义。尽管它们看起来是一样的,但我已经看到了一些与此相关的问题,因为home
定义了应用程序启动的视图,而/
定义了路由映射,所以为了以防万一,我也试着删除其他变量,如果是这样的话(我个人只使用命名路由,以使用户被发送到哪里的代码更加清晰)。
遵循一个使用Option 1
的示例,但使用使用initState
的Option 2
上的建议
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();
}
...
希望这会有帮助,如果没有帮助,请让我知道你有任何问题/问题。
https://stackoverflow.com/questions/65683630
复制相似问题