当前位置: 首页 > news >正文

Flutter开发 Dio拦截器实现token验证过期的功能

前言:

     之前分享过在Android中使用Retrofit实现token失效刷新的处理方案,现在Flutter项目也有“token验证过期”的需求。刚开始我使用的是EventBus来通知弹出登录页面,但是发现在refresh token过期后并没有去登录,原因是EventBus需要在有生命周期的State状态中才能发送消息,在这里我构造了全局的上下文,以便弹出登录页面。所以接下来我简单总结一下在Flutter项目中如何实现自动刷新token并重发请求的拦截器功能,希望对大家有所帮助。

需求:

     1.有两个token, 分别为access_token和refresh_Token, access_token的有效期为1小时,refresh_Token的有效期为7天;

     2.如果access_token1个小时后过期了,服务器会返回401,此时客户端要根据刷新access_token的retrofit接口去重新请求新的access_token;

     3.如果refresh_Token7天后也过期了,则要求跳到登录页面。

思路:     

     1.Dio实现网络请求

     2.自定义token拦截器,实现token自动刷新并重发请求

     3.RefreshToken过期,弹出登录页面。

实现的步骤:

1.配置Android目录的gradle依赖

dependencies {
    ...
    implementation 'de.greenrobot:eventbus:3.0.0-beta1'
}

2.在pubspec.yaml添加sdk

dependencies:
  ...
  cupertino_icons: ^0.1.0
  dio: ^2.1.7

3.封装一个获取新的accessToken方法

Future<String> getToken() async {
    String refreshToken = DataUtil.getRefreshToken; //获取当前的refreshToken
    String accessToken;
 
    Dio tokenDio = new Dio(); //创建新Dio实例
    tokenDio.options.headers['refresh-token'] = refreshToken;//设置当前的refreshToken
 
    try {
      String url = url; //refreshToken url
      var response = await tokenDio.get(url); //请求refreshToken刷新的接口
      accessToken = response.data['access_token']; //新的accessToken
      refreshToken = response.data['refresh_token'];//新的refreshToken
      DataUtil.saveRefreshToken(refreshToken); //保存新的refreshToken
    } on DioError catch (e) {    
       if(e.response.statusCode==401){ //401代表refresh_token过期
         return Navigator.of(context).push(new MaterialPageRoute(
        builder: (ctx) => new LoginPage()));//refreshToken过期,弹出登录页面
      }
    }
    return accessToken;
  }

 4.token失效时,异步获取accessToken

onError(DioError error) async { 
    if (error.response != null && error.response.statusCode == 401) { 401代表access token过期
      Dio dio = DioUtil().dio;//获取Dio单例
      dio.lock(); //加锁
      String accessToken = await getToken(); //异步获取新的accessToken
      ...
      dio.unlock(); //解锁
    }
    super.onError(error);
  }

5.重新发起一个请求获取数据

 //重新发起一个请求获取数据
      Dio tokenDio2 = new Dio(); //创建新的dio实例
      tokenDio2.options.headers['access-token'] = accessToken;
      try {
        var newRequest = await tokenDio2.request(request.path);
        return newRequest;
      } on DioError catch (e) {
        return e;
     }

6.Dio拦截器的完整代码

typedef void ChildContext(BuildContext context);
 
class TokenInterceptor extends Interceptor {
  ChildContext context; //上下文
 
  @override
  onError(DioError error) async {
    if (error.response != null && error.response.statusCode == 401) { //401代表token过期
      Dio dio = DioUtil().dio;//获取Dio单例
      dio.lock(); //加锁
      String accessToken = await getToken(); //异步获取新的accessToken
 
      //重新发起一个请求获取数据
      Dio tokenDio2 = new Dio();//创建新的Dio实例
      tokenDio2.options.headers['access-token'] = accessToken;
 
      try {
        var newRequest = await tokenDio2.request(request.path);
        return newRequest;
      } on DioError catch (e) {
        return e;
      }
      dio.unlock(); //解锁
    }
    super.onError(error);
  }
 
 
  Future<String> getToken() async { 
    String refreshToken = DataUtil.getRefreshToken; //获取当前的refreshToken
     String accessToken ;
 
    Dio tokenDio =new Dio(); //创建新的Dio实例
    tokenDio.options.headers['refresh-token'] = refreshToken ;//设置当前的refreshToken 
 
    try {
      String url = url; //refreshToken url
      var response = await tokenDio.get(url); //请求refreshToken刷新的接口
      accessToken = response.data['access_token']; //新的accessToken
      refreshToken = response.data['refresh_token'];//新的refreshToken
      DataUtil.saveAccessToken(accessToken); //保存新的accessToken
      DataUtil.saveRefreshToken(refreshToken); //保存新的refreshToken
    } on DioError catch (e) {
      if(e.response.statusCode==401){//401代表refresh_token过期
        return Navigator.of(context).push(new MaterialPageRoute(
        builder: (ctx) => new LoginPage()));//refreshToken过期,弹出登录页面
      }
    }
    return accessToken;
  }
 
}

7.添加自定义的token拦截器

/*
 *Dio网络请求的工具类
 */
class DioUtil {
  Dio dio;
  static DioUtil _instance;
 
  static DioUtil getInstance() {
    if (_instance == null) {
      _instance = DioUtil();
    }
    return _instance;
  }
 
  //get方法
  Future<Response> get(url, {data, options, cancelToken}) async {
   String accessToken = DataUtil.getAccessToken; //获取当前的accessToken 
 
    options = BaseOptions(
      connectTimeout: 15000,
      headers: {
        Constants.accessToken: accessToken
      },
    );
 
    dio = new Dio(options);
 
    //添加自定义的token拦截器
    dio.interceptors.add(new TokenInterceptor());
 
    Response response;
    try {
      response = await dio.get(url, cancelToken: cancelToken);
    } on DioError catch (e) {
      print(e.response.data);
    }
    return response;
  }
 
}

8.总结

在Flutter项目中自定义一个自动刷新并重发请求的Dio拦截器,经过不断调试,最终实现了功能。如果有什么疑问的话,欢迎留言联系我哦!

 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 实践人生 ,一个普通IT人的十年回顾(四)
  • flutter实用系列(五)之网络请求dio,请求,拦截器简单示例
  • 译者后记 ——《DOOM启示录》读后感(二)
  • centos7 -pm2定时任务重启
  • Borland挺进南极
  • 仿携程首页项目的静态页面布局项目
  • C++Builder使用经验谈 (转)
  • flex布局详解
  • 看完了Essential c++......
  • vue打包上传到服务器加载慢的优化
  • nginx部署多个 vue项目
  • 转载--中国手机游戏市场焦点分析报告
  • 角色扮演游戏引擎的设计原理--转自MOVE2008
  • flutter指纹识别
  • CC++中,typedef与#define
  • @angular/forms 源码解析之双向绑定
  • 【402天】跃迁之路——程序员高效学习方法论探索系列(实验阶段159-2018.03.14)...
  • 【个人向】《HTTP图解》阅后小结
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • 2018天猫双11|这就是阿里云!不止有新技术,更有温暖的社会力量
  • canvas 五子棋游戏
  • idea + plantuml 画流程图
  • input实现文字超出省略号功能
  • PV统计优化设计
  • Python_网络编程
  • Python学习之路16-使用API
  • REST架构的思考
  • uni-app项目数字滚动
  • vuex 学习笔记 01
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 前端代码风格自动化系列(二)之Commitlint
  • 如何编写一个可升级的智能合约
  • 小程序开发中的那些坑
  • 延迟脚本的方式
  • 做一名精致的JavaScripter 01:JavaScript简介
  • 昨天1024程序员节,我故意写了个死循环~
  • #考研#计算机文化知识1(局域网及网络互联)
  • (1)(1.19) TeraRanger One/EVO测距仪
  • (17)Hive ——MR任务的map与reduce个数由什么决定?
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (附源码)spring boot基于小程序酒店疫情系统 毕业设计 091931
  • (附源码)springboot人体健康检测微信小程序 毕业设计 012142
  • (三)Kafka离线安装 - ZooKeeper开机自启
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (五)c52学习之旅-静态数码管
  • (一)Thymeleaf用法——Thymeleaf简介
  • (转载)深入super,看Python如何解决钻石继承难题
  • .Family_物联网
  • .net Application的目录
  • .NET Core 将实体类转换为 SQL(ORM 映射)
  • .NET Standard 支持的 .NET Framework 和 .NET Core
  • .NET 将多个程序集合并成单一程序集的 4+3 种方法
  • .net 连接达梦数据库开发环境部署
  • .NET程序集编辑器/调试器 dnSpy 使用介绍