flutter-login-token本地存储(shared_preferences),路由拦截
逻辑登录逻辑
添加token
- 登录成功,保存token到本地,跳转回首页,跳转回首页 移除token
- 未登录 路由拦截器找不到token,跳转到登录页面或弹出
- 令牌过期,后台返回token,移除到API拦截,跳转到登录页面
- 注销 移除token,跳转到登录页面,移除之前的所有路由栈
本地存储
flutter 目前没有内置本地存储,官方推荐
shared_preferences
shared_preferences: ^0.5.4+1 复制代码
import 'package:shared_preferences/shared_preferences.dart'; 复制代码
基本用法
- 实例 保存
存储字符类型数据
数据集setInt
设置布尔类型数据setBool
设置double 类型数据setDouble
获取
获取字符型数据
getString❀ t
获取布尔型数据getBool
获取双精度型数据getDouble
删除
- 删除数据
删除
Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => route == null,); 复制代码
清除 清晰
(更多详情请参见官方文档,大部分
SharedPreferences类
)记录数据保存成功(保存登录令牌)
Map<String, Object> data = response_map['data']; final prefs = await SharedPreferences.getInstance(); final setTokenResult = await prefs.setString('user_token', data['token']); await prefs.setInt('user_phone', data['phone']); await prefs.setString('user_phone', data['name']); if(setTokenResult){ debugPrint('保存登录token成功'); Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => route == null,); }else{ debugPrint('error, 保存登录token失败'); } 复制代码
如果未登录,跳转到登录页面 flutter自带
抽屉
组件抽屉gif
有一个抽屉
参数,领取一个小部件Scaffold( drawer: new MyDrawer(), ) 复制代码
MyDrawer
class MyDrawer extends StatelessWidget { const MyDrawer({ Key key, }) : super(key: key); @override Widget build(BuildContext context) { return Drawer( child: MediaQuery.removePadding( context: context, removeTop: true, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Container(height: 100,), Expanded( child: ListView( children: <Widget>[ GestureDetector( onTap: () async{ final prefs = await SharedPreferences.getInstance(); final result = await prefs.clear(); if(result){ debugPrint('退出登录成功'); Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => route == null,); } }, child: ListTile( leading: const Icon(Icons.outlined_flag), title: const Text('退出登录'), ), ) ], ), ), ], ), ), ); } } 复制代码
注销并确认两次
AlertDialog( content: Text('是否确认退出登录?'), actions: <Widget>[ FlatButton( child: Text('取消'), onPressed: () { debugPrint('取消'); Navigator.pop(context); }, ), FlatButton( child: Text('确认'), onPressed: () async{ debugPrint('确认退出'); Navigator.pop(context); final prefs = await SharedPreferences.getInstance(); final result = await prefs.clear(); if(result){ debugPrint('退出登录成功'); Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => route == null,); } }, ), ], ); 复制代码
我们已实施登录和注销,但未登录尚未处理。非登录需要路由拦截
路由拦截
onGenerateRoute
可以监听里面的路由(只有当路由和家乡不匹配时才会执行) ❙删除路由(如果有) 删除家(如果有的话))
MaterialApp( ...代码 // home: IndexHome(), onGenerateRoute: onGenerateRoute, // routes: routes, ); 复制代码
新建一个onGenerateRoute函数
Route<dynamic> onGenerateRoute(RouteSettings setting) { if(setting.name == 路由名称){ return aterialPageRoute(builder: (context) => Widget); } return MaterialPageRoute(builder: (BuildContext context) => Container(child: Text('404'),)); } 复制代码
- 在onGenerateRoute函数中添加如下代码,并在
Map<String, Widget> routes = { 你的路由 }; bool mathMap = false; Route<dynamic> mathWidget; routes.forEach((key, v){ if(key == setting.name){ mathMap = true; mathWidget = MaterialPageRoute(builder: (BuildContext context) => v); } }); if(mathMap){ return mathWidget; } 复制代码
中输入路由,此时我们可以在里面添加一个钩子管理
路由实现的完整代码这里有时我们必须在里面写钩子,这比较复杂。本来开始写一个beforeHook来接收一个next函数,突然发现本地存储是异步的,很伤心。此时我只能使用路由来跳回来。进入登录页面。
Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => route == null,); 复制代码
拦截登录实现
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; routeBeforeHook(RouteSettings setting, navigatorKey) async{ String LoginPath = '/login'; if(setting.name == LoginPath || setting.name == '/rigister'){ return; } final prefs = await SharedPreferences.getInstance(); final token = prefs.getString('user_token') ?? ''; if(token == ''){ navigatorKey.currentState.pushNamedAndRemoveUntil(LoginPath, (route) => route == null,); } } 复制代码
上下文全球化
导航器必须信任
上下文
。这时候没有上下文
或者上下文
在顶层就会出现问题,这时候就可以使用全局密钥了。
既可以用于路由拦截,也可以用于Api拦截。navigatorKey
navigatorKey: navigatorKey, 复制代码
context.currentState
下的final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>(); 复制代码
MaterialApp对应
Navigator.of(context)❝其他
试试看功能完成了,可以试试
pubspec .yaml
。看名字就知道是shared_preferences
。 lib文件下还有一个shared_preferences
文件。这很奇怪。 ,怎么会找不到呢?
(然后我就不敢想象问题了,可能是编辑器的问题,所以我重新启动就好了QAQ)作者:秀月lonelyBoy
链接:https://juejin. im/post/5db6d6f16fb9a0206965a0f3
来源:掘金
版权归作者所有。商业转载请联系作者获取授权。非商业转载请注明来源。 - 删除数据
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。