Flutter ー Authentication 认证

news2024/11/8 10:55:37

Flutter ー Authentication 认证

alt

原文 https://medium.com/@simbu/flutter-authentication-adb8df7cf673

前言

如果我相信我知道你是谁那我就能让你查看你的个人 应用 application 资料。

身份验证可能是应用程序必须处理的最大的交叉问题。

将它作为一个特性添加到 DigestablePrologue 允许我们多次抽象和重用它,并通过更新一组代码来减少维护。

正文

业务需求

让我们从一个高层次的、故意模糊的业务需求开始:

“该应用程序将能够使用现代身份验证保护对屏幕和 API 的访问”

经过最初的交谈,我们决定接受这个要求:

  • 滑动登录屏幕。
  • 使用 Microsoft AD 或 Google Firebase 进行身份验证。
  • 在设置中注销。

然后,我们举办了一个研讨会,通过示例创建规范:

Login slide up specification
Login slide up specification

Login slide up specification

Auth service specification
Auth service specification

认证服务规范

Logout setting specification
Logout setting specification

注销设置规范

并将它们转换为可执行规范:

Login screen feature tests
Login screen feature tests

登录屏幕功能测试

Authentication service feature tests
Authentication service feature tests

身份验证服务特性测试

Logout setting feature tests
Logout setting feature tests

注销设置特性测试

为了缩短这篇文章的篇幅,我已经部分实现了注销设置,跳过了即将添加的 AD & Firebase 身份验证服务。

因此,特性测试的结果不再完全反映最初的规范,但是一旦深入细节,范围或方向的改变是正常的。

我发表的所有关于认证和数据访问主题的文章将很快通过一篇摘要文章(一个迷你系列文章)结合在一起。

开始

从 app_config 读取环境。Json 文件,该文件在应用程序启动时加载,并由为 live 和 UAT 进行的 CodeMagic 集成构建注入:

alt

根据环境选择身份验证服务:

AuthenticationServiceStateNotifier selectAuthenticationServiceByEnvironment() {

  var environment = GlobalEnvironmentValues.instance.environment;


  AuthenticationService authenticationService = environment == Environments.live

      ? LiveAuthenticationService()

      : environment == Environments.uat

          ? UatAuthenticationService()

          : StubbedAuthenticationService();


  return AuthenticationServiceStateNotifier(authenticationService);

}


final authenticationServiceProvider = StateNotifierProvider<

    AuthenticationServiceStateNotifier, AuthenticationService>(

  (ref) => selectAuthenticationServiceByEnvironment(),

);

当应用程序启动时,它会检测存根身份验证服务并自动验证用户:

if (ref.read(authenticationServiceProvider).typeName ==

        AuthenticationService.authenticationServiceTypeNameStubbed) {

        ref.read(authenticationProvider.notifier).setIsAuthenticated(true);

}

这个设置屏幕是使用一个很棒的包 sets_ui 添加的,它允许用户注销,并调用身份验证服务上的 signOut 方法:

Sign Out setting
Sign Out setting

注销设置

我们的自动化特性测试涵盖了所有内容:

Login feature test report
Login feature test report

登录功能测试报告

Authentication feature test report
Authentication feature test report

认证特性测试报告

在未来的帖子中,当我们添加 UAT 和 Live 环境时,它会在未经身份验证时路由到登录屏幕,并调用真正的身份验证服务来获取访问令牌,这些令牌将被 Flutter Data 用来进行安全的 API 请求。

登录屏幕和身份验证服务已经添加到 DigestablePrologue,设置屏幕添加到 DigestableMe。

引发导航事件 navigation events

为了响应导航,我在路由器上增加了一个观察者

MaterialApp.router(

 ...

    navaigationObservers: [

       NavigationEventsObserver(ref.read(eventStoreProvider))

    ],

 ...

)

每次导航发生时,它都会在事件总线上引发 Navigated 事件:

/// Raises Nativigated events when the GoRouter navigates.

class NavigationEventsObserver extends NavigatorObserver {

  final EventStore eventStore;

  NavigationEventsObserver(this.eventStore);




  @override

  void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {

    raiseNavigatedEvent(route.settings.name ?? "");

  }


  @override

  void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {

    raiseNavigatedEvent(route.settings.name ?? "");

  }


  @override

  void didReplace({ Route<dynamic>? newRoute, Route<dynamic>? oldRoute }) {

    raiseNavigatedEvent(newRoute?.settings.name ?? "");

  }



  void raiseNavigatedEvent(String routeName) {

    even(fn)tStore.bus.fire(Navigated(routeName));

  }

}

然后测试可以使用它来证明导航操作已经发生,当前事件存储仅保留最后一个 Navigated 事件。

通过侦听事件并记录它们,我很可能会 extension 这个功能来添加应用程序监视。

Flutter App 生命周期

为了在唤醒时强制执行所需的身份验证,我需要使用重写来捕获应用程序状态(AppLificycleState)。

@override

  void didChangeAppLifecycleState(AppLifecycleState state) {

    ref.read(appLifecycleStateProvider.notifier)

  .setLifecycleState(state);

    ref.read(authenticationServiceProvider.notifier)

  .checkAuthenticated();

  }
alt

可观察的生命周期事件(AppLificycleState) :

  • Inactive ー应用程序处于非活动状态,不接收用户输入。这个事件只能在 iOS 上运行,因为在 Android 上没有等效的事件可以映射到
  • 暂停ー应用程序当前对用户不可见,不响应用户输入,并在后台运行。这相当于 Android 中的 onPace()
  • 应用程序可见并响应用户输入,这相当于 Android 中的 onPostResume()
  • 暂停ー 应用 application 暂停。这相当于 Android 中的 onStop; 它不会在 iOS 上触发,因为在 iOS 上没有可映射到的等价事件

功能测试支持你

Feature tests letting us know we have broken other features
Feature tests letting us know we have broken other features

特性测试让我们知道我们已经破坏了其他特性

这是伟大的,我已经做了一些相当大的变化,但我知道我需要修复,以避免任何回归错误。

测试的契约确保应用程序仍然能够完成早期特性所要求的工作。

特性测试认证

事实证明,要使特性测试通过非常困难,但是为了确保身份验证按计划工作,将它们放在适当的位置是值得的。

主要问题是在测试步骤运行之前从文件加载环境,这意味着我们已经运行了检查身份验证和重定向到登录屏幕的逻辑。

在几次尝试通过代码改变环境失败后,我选择了一套单独的特性测试:

Gherkin feature test config that loads the live config value file.
Gherkin feature test config that loads the live config value file.

Gherkin 特性测试配置,加载实时配置值文件。

加载不同的环境配置文件:

Live config value file
Live config value file

实时配置值文件

它需要更多的维护,但是很有必要,因为我们将在集成和部署构建中注入配置文件以保护秘密值。

使用事件来解决难以实现的、特征化的测试步骤

登录特性的一些步骤很难实现,因为功能将在使用微应用程序 DigestablePrologue 的父应用程序 DigestableMe 中实现:

When: Making an API request

这意味着我们无法在 DigestablePrologue 中导航到屏幕或发出 API 请求。

这是一个耦合问题,我们可以用事件总线来解决。

alt

应用程序现在只是侦听事件并采取适当的操作,允许我们在步骤中引发事件,而不是实际的导航或 API 调用。

何时: 发出 API 请求事件: API 请求

使用 EventBus 还有其他优点,我们可以在以后添加这些优点,例如记录引发的事件。

规程 ーー 执行特性步骤

使用 Flutter Gherkin 最乏味的部分是创建所有的步骤方法,我将尝试使用构建器来自动创建包含要填写的框架步骤的文件。

与此同时,我使用可视化代码中的高亮来规范所需的步骤,例如:

alt

这样说:

Given: Always on authentication

And: Not authenticated

And: authenticated


When: The application is started

When: The application awakes

When: Making an API request

When: Displaying a restricted screen

When: Displaying an unrestricted screen


Then: The application routes to the 'Login Screen'

And: Records the current screen for redirection

然后将骨架方法添加到步骤文件中

路线授权

具有自定义属性的路由角色,则可以实现基于非角色的路由,大家暂时可以,但可以 extension 。

没有实现登录/id/auth 的受限屏幕,因为它的一些不同之处,它的授权和路由保护,在需要时通过 GoRouter 重定向作为保护。

Packages

  • event_bus
  • settings_ui

结束语

如果本文对你有帮助,请转发让更多的朋友阅读。

也许这个操作只要你 3 秒钟,对我来说是一个激励,感谢。

祝你有一个美好的一天~


© 猫哥

  • 微信 ducafecat

  • https://wiki.ducafecat.tech

  • https://video.ducafecat.tech

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/59200.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HashMap JDK1.7与1.8的区别

结构 首先HashMap在1.7中是以数组链表的形式存在的, 而HashMap在1.8中则是以数组链表红黑树构成的, 当一个节点的链表长度超过8并且数组长度超过64时会将链表转换为红黑树, 初始化 初始容量大小介绍 说到数组就不得不提HashMap里面的成员变量DEFAULT_INITIAL_CAPACITY也就是…

Mysql进阶学习(八)DDL语言+数据类型和DTL语言

Mysql进阶学习&#xff08;八&#xff09;DDL语言与DTL语言DDL语言1、简介&#xff1a;1.1、库的管理1.1.1、库的创建1.1.2、库的修改1.1.3、库的删除1.2、表的管理1.2.1.表的创建 ★1.2.2.表的修改1.2.3.表的删除1.2.4.表的复制测试案例1. 创建表dept12. 将表departments中的数…

SpringBoot_整合Thymeleaff模板引擎

Thymeleaf模板引擎的主要目标是将优雅的自然模板带到开发工作流程中&#xff0c;并将HTML在浏览器中正确显示&#xff0c;并且可以作为静态原型&#xff0c;让开发团队能更容易地协作。Thymeleaf能够处理HTML&#xff0c;XML&#xff0c;JavaScript&#xff0c;CSS甚至纯文本。…

Qt扫盲-Qt Designer 设计师使用总结

Designer 设计师使用总结一、顶部菜单栏1. 常用的菜单内容2. 快捷工具栏说明二、左侧控件栏1. 组件分类2. 筛选三、中间绘图区1. 左侧控件区拖放控件到中间2. 中间区域布局3. 属性修改四、右侧属性栏1. 对象查看器2. 属性编辑器3.组织结构2. 属性设置五、美化专栏1.单个设置层叠…

微服务框架 SpringCloud微服务架构 12 DockerCompose 12.2 部署微服务集群

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构12 DockerCompose12.2 部署微服务集群12.2.1 直接开干12 DockerCompose 1…

大数据:Hive简介及核心概念

一、简介 Hive 是一个构建在 Hadoop 之上的数据仓库&#xff0c;它可以将结构化的数据文件映射成表&#xff0c;并提供类 SQL 查询功能&#xff0c;用于查询的 SQL 语句会被转化为 MapReduce 作业&#xff0c;然后提交到 Hadoop 上运行。 特点&#xff1a; 简单、容易上手 (…

做短视频不知道靠什么变现,分享三个自我商业定位的方法,适用普通人

如果说你还停留在我也不知道我可以靠什么赚钱这样的一个状态当中。那我给你三个自我商业定位的方法。篇幅较长&#xff0c;点赞收藏慢慢看哦 首先第一个方法&#xff0c;从工作上或者专业的事情上找变现的方法。 那么你们需要了解一个概念叫做知识的诅咒。什么意思呢&#xf…

【论文整理1】On the Continuity of Rotation Representations in Neural Networks

1.前置知识 1.1 Gram-Schmidt正交化 【参考阅读】Gram-Schmidt过程 看完这篇应该基本能理解&#xff0c;但是他对于公式的讲解有一个地方讲解得不是很清楚! 即为什么分母是平方形式呢&#xff1f; 1.2 差集 定义&#xff1a;差集是一种集合运算&#xff0c;记A&#xff0…

Java并发编程—CompletableFuture的介绍和使用

在博主上一篇博客介绍中&#xff0c;Java并发编程—java异步Future的迭代过程_小魏快起床的博客-CSDN博客&#xff0c;这里面给大家分析了Future的使用过程和一些存在的问题&#xff0c;那么针对里面出现的阻塞问题&#xff0c;博主将在这一篇文章给大家介绍清楚 &#x1f34f…

MyBatis框架简介

MyBatis是一个开源的数据持久层框架&#xff0c;内部封装了通过JDBC访问数据库的操作&#xff0c;支持普通的SQL查询、存储过程和高级映射。作为持久层框架&#xff0c;主要思想是将程序中的大量的SQL语句分离出来&#xff0c;配置在相应的配置文件中&#xff0c;这样可以在不修…

Java—数据类型

文章目录数据类型八大基本数据类型Java中有了基本数据类型&#xff0c;为什么还要包装类型String字符串类型函数字符串类的length()方式是否能够得到字符串内有多少个字符&#xff1f;不可变字符串String为什么要设计成不可变的&#xff1f;boolean类型占多少位&#xff1f;为什…

【springboot进阶】使用aop + 注解方式,简单实现spring cache功能

目录 一、实现思路 二、定义缓存注解 三、aop 切面处理 四、使用方式 五、灵活的运用 六、总结 前几天有同学看了 SpringBoot整合RedisTemplate配置多个redis库 这篇文章&#xff0c;提问spring cache 能不能也动态配置多个redis库。介于笔者没怎么接触过&#xff0c;所以…

【Java开发】 Spring 08 :访问 Web 资源( 借助 RestTemplate or WebClient )

web 资源就是运行在服务器上的资源&#xff0c;比如放到 web 下的页面 js 文件、图片、css等&#xff0c;web资源分为静态web资源和动态web资源两类&#xff0c;接下来访问的就是动态资源&#xff08;页面返回的数据是动态的&#xff0c;由后端程序产生&#xff09;&#xff0…

Android 使用元数据

Android 使用元数据 前提介绍Metadata 有时候为安全起见&#xff0c;某个参数要给某个活动专用&#xff0c;并不希望其他活动也能获取该参数&#xff0c;也就是要使用第三方SDK时。Activity提供了元数据&#xff08;Metadata&#xff09;的概念&#xff0c;元数据是一种描述其…

C++类和对象(二)构造函数、析构函数、拷贝构造函数

目录 1.类的6个默认成员函数 2. 构造函数 2.1 概念 2.2 特性 3.析构函数 3.1 概念 3.2 特性 4. 拷贝构造函数 4.1 概念 4.2 特征 1.类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;…

【菜菜的sklearn课堂笔记】聚类算法Kmeans-聚类算法的模型评估指标

视频作者&#xff1a;菜菜TsaiTsai 链接&#xff1a;【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili 可以只看轮廓系数和卡林斯基-哈拉巴斯指数 不同于分类模型和回归&#xff0c;聚类算法的模型评估不是一件简单的事。在分类中&#xff0c;有直接结…

【尚硅谷】Java数据结构与算法笔记02 - 队列

文章目录一、使用场景二、队列介绍三、数组模拟队列3.1 思路分析3.2 Java代码实现3.3 问题分析与优化四、数组模拟环形队列4.1 思路分析4.2 Java代码实现一、使用场景 银行排队&#xff0c;先到先得测核酸&#xff0c;先到先测 二、队列介绍 队列是一个有序列表, 可以用数组…

硬盘压缩将C盘拓展成D盘和E盘

硬盘压缩将C盘拓展成D盘和E盘1. 现状2. 硬盘压缩2.1 进入计算机管理2.2 磁盘管理压缩卷3. 分配新盘符3.1 查看盘符是否被占用3.2 新建D盘刚安装好系统的电脑有可能只有一个C盘&#xff0c;我们工作学习的时候远远不够&#xff0c;那怎么拓展其他盘符呢&#xff1f; 接下来让我们…

PyQt5基础练习1

0. 本文学习地址 1. PyQt5是由一系列Python模块组成 超过620个类&#xff0c;6000函数和方法。能在诸如Unix、Windows和Mac OS等主流操作系统上运行。 1.1 PyQt5有两种证书 GPL商业证书 2. 实验1 实现简单的窗体 2.1 完整代码 #!/usr/bin/python3 # -*- coding: utf-8 -*…

专业尖端远心光学,高精度视觉检测解决者

随着机器视觉系统在精密检测领域的广泛应用&#xff0c;在精密光学测量系统中&#xff0c;由于普通光学镜头会存在一定的制约因素&#xff0c;如影像的变形、视角选择而造成的误差、不适当光源干扰下造成边界的不确定性等问题&#xff0c;进而影响测量的精度。为弥补普通镜头应…