Flutter ー Authentication 认证
原文 medium.com/@simbu/flut…
前语
假如我信任我知道你是谁那我就能让你查看你的个人 运用 application 材料。
身份验证可能是运用程序必须处理的最大的交叉问题。
将它作为一个特性增加到 DigestablePrologue 答应咱们多次抽象和重用它,并经过更新一组代码来减少维护。
正文
事务需求
让咱们从一个高层次的、故意含糊的事务需求开始:
“该运用程序将能够运用现代身份验证维护对屏幕和 API 的访问”
经过开始的交谈,咱们决定接受这个要求:
- 滑动登录屏幕。
- 运用 Microsoft AD 或 Google Firebase 进行身份验证。
- 在设置中刊出。
然后,咱们举办了一个研讨会,经过示例创立标准:
Login slide up specification
认证服务标准
刊出设置标准
并将它们转换为可执行标准:
登录屏幕功用测验
身份验证服务特性测验
刊出设置特性测验
为了缩短这篇文章的篇幅,我现已部分完成了刊出设置,跳过了即将增加的 AD & Firebase 身份验证服务。
因而,特性测验的结果不再完全反映开始的标准,可是一旦深化细节,范围或方向的改动是正常的。
我发表的所有关于认证和数据访问主题的文章将很快经过一篇摘要文章(一个迷你系列文章)结合在一起。
开始
从 app_config 读取环境。Json 文件,该文件在运用程序启动时加载,并由为 live 和 UAT 进行的 CodeMagic 集成构建注入:
根据环境挑选身份验证服务:
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 办法:
刊出设置
咱们的主动化特性测验涵盖了所有内容:
登录功用测验报告
认证特性测验报告
在未来的帖子中,当咱们增加 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();
}
可观察的生命周期事情(AppLificycleState) :
- Inactive ー运用程序处于非活动状况,不接纳用户输入。这个事情只能在 iOS 上运行,由于在 Android 上没有等效的事情能够映射到
- 暂停ー运用程序当前对用户不行见,不响运用户输入,并在后台运行。这相当于 Android 中的 onPace()
- 运用程序可见并响运用户输入,这相当于 Android 中的 onPostResume()
- 暂停ー 运用 application 暂停。这相当于 Android 中的 onStop; 它不会在 iOS 上触发,由于在 iOS 上没有可映射到的等价事情
功用测验支持你
特性测验让咱们知道咱们现已破坏了其他特性
这是巨大的,我现已做了一些相当大的改动,但我知道我需求修复,以避免任何回归过错。
测验的契约保证运用程序依然能够完成早期特性所要求的工作。
特性测验认证
事实证明,要使特性测验经过非常困难,可是为了保证身份验证按计划工作,将它们放在恰当的位置是值得的。
主要问题是在测验过程运行之前从文件加载环境,这意味着咱们现已运行了查看身份验证和重定向到登录屏幕的逻辑。
在几次测验经过代码改动环境失利后,我挑选了一套独自的特性测验:
Gherkin 特性测验装备,加载实时装备值文件。
加载不同的环境装备文件:
实时装备值文件
它需求更多的维护,可是很有必要,由于咱们将在集成和布置构建中注入装备文件以维护隐秘值。
运用事情来解决难以完成的、特征化的测验过程
登录特性的一些过程很难完成,由于功用将在运用微运用程序 DigestablePrologue 的父运用程序 DigestableMe 中完成:
When: Making an API request
这意味着咱们无法在 DigestablePrologue 中导航到屏幕或宣布 API 恳求。
这是一个耦合问题,咱们能够用事情总线来解决。
运用程序现在仅仅侦听事情并采纳恰当的操作,答应咱们在过程中引发事情,而不是实践的导航或 API 调用。
何时: 宣布 API 恳求事情: API 恳求
运用 EventBus 还有其他长处,咱们能够在今后增加这些长处,例如记录引发的事情。
规程 ーー 执行特性过程
运用 Flutter Gherkin 最乏味的部分是创立所有的过程办法,我将测验运用构建器来主动创立包括要填写的结构过程的文件。
与此同时,我运用可视化代码中的高亮来标准所需的过程,例如:
这样说:
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
-
wiki.ducafecat.tech
-
video.ducafecat.tech