Code前端首页关于Code前端联系我们

flutter-login-token本地存储(shared_preferences),路由拦截

terry 2年前 (2023-09-23) 阅读数 70 #移动小程序

逻辑登录逻辑

添加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

        flutter-登录token本地存储(shared_preferences)、路由拦截

      有一个抽屉参数,领取一个小部件

      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前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门