Flutter认证授权插件harmony_auth的使用
Flutter认证授权插件harmony_auth的使用
安装
在项目中添加此库,将以下行添加到你的 pubspec.yaml
文件中:
dependencies:
harmony_auth: ^latest.version
# 其他库
dio: ^5.4.0
如果你正在使用 dio 4,使用以下配置:
dependencies:
harmony_auth: ^2.0.0
# 其他库
dio: 4.0.0
导入 harmony_auth:
import 'package:harmony_auth/harmony_auth.dart';
简介
harmony_auth 的职责是管理令牌以验证用户访问服务器API时的身份。它还能够监控或检索用户的认证状态。该库的设计理念是使用 dio
作为 HTTP 库。
harmony_auth 包含许多工作模块,但最重要的两个是存储库 AuthRepository
和拦截器 AuthInterceptor
。存储库用于保存、编辑、删除或刷新令牌,并公开 API 以检索或监控用户认证状态。拦截器用于拦截每个 dio 请求并将其令牌添加到头部(或其他操作)。当在拦截过程中遇到未认证错误时,它还会刷新令牌并重试请求。如果无法对用户进行身份验证,则会抛出 dio 错误,以便库用户将用户重定向到登录页面。通常情况下,当发送下游错误时,我们没有令牌或令牌已被移除,因为它们已失效。
你主要关心的是存储库,因为它是你操作令牌和获取认证状态的地方。拦截器不直接由用户使用,而是添加到 dio 拦截器中。创建所有认证系统部分后,只需通过依赖注入注册存储库和操作过的 dio。
存在一种 AuthToken
类型来表示包含访问令牌和刷新令牌的令牌。你必须拥有完整的认证令牌对或没有任何令牌。不存在只有部分令牌的情况。登录时应将访问令牌和刷新令牌设置到存储库中,登出时应从存储库中移除令牌。如果需要重新登录用户或通过任何方式获得新令牌,应更新存储库中的令牌。这是罕见的情况,但在安全原因下需要刷新令牌时,可以调用存储库上的刷新方法。当在存储库上调用刷新方法时,它会刷新并替换令牌为新的令牌,由于令牌无效而失败,这将移除令牌并抛出异常,并且遇到网络问题也会抛出 DioErrors。大多数方法返回 Future,因此它们应该被等待。务必阅读 auth repository dart 文档以了解任何自定义用法。
要获取用户的认证状态,应在将 auth 存储添加到 auth 存储库时添加 streaming
能力。之后,你可以通过使用存储库上的 status
获取器来访问认证状态,这将返回一个包含两种可能值的枚举:已登录和未登录。你还可以通过使用 statusStream
获取器来获取认证状态更改的流。如果需要在状态流上获取初始状态,请在存储库上调用 initializeStatusStream
方法。如果没有向存储添加 streaming 能力,这些方法将在使用时抛出错误。
在通常的使用中,harmony_auth 本身不会抛出任何错误。错误的唯一方式是在调用 dio 的 http 方法时抛出错误。例如,当你在 dio 上调用 get
时,如果你使用了 async/await 或者在没有使用 async/await 的 catchErrors
方法中,你可能会在 catch 子句中得到一个 DioError
错误。这些 DioError 对象有许多字段。两个是 error
和 type
。类型将指示错误的类型,例如 DioErrorType.response
将指示错误响应码,如 500
。错误将指示内部实际抛出的错误,例如当遇到网络问题时,错误将是 SocketException
类型。通过其拦截器,harmony_auth 还会抛出一些 DioErrors。最重要的一种情况是当我们遇到不可恢复的未认证错误时。在这种情况下,通常没有可用的令牌,你应该将用户重定向到登录页面。这个 DioError
类型为 DioErrorType.other
,错误类型为 AuthException
。你可以使用 DioError
上的 isAuthException
扩展方法来方便地识别这种错误。还有另一种类型的错误源自此库,但它只会在非常罕见的情况下发生。
使用步骤概要
- 创建一个 dio。
- 如果需要,创建并添加一个日志记录器。
- 创建一个认证存储。
- 创建一个认证检查器。
- 创建一个认证 REST。
- 通过使用存储和 REST 创建一个认证存储库。
- 创建一个认证匹配器。
- 创建一个认证检查器。
- 创建一个认证操作器。
- 通过使用存储库、匹配器、检查器和操作器创建一个拦截器。
- 将拦截器添加到 dio 拦截器。
- 通过依赖注入注册存储库和 dio。
使用步骤详情
首先,你需要创建一个 dio 对象,并添加任何你需要的选项。请记住,你不应该改变 dio 属性的方式使其将未认证错误视为成功。
final dio = Dio();
然后,如果你希望从 harmony_auth 获取日志,请创建一个日志记录器并添加你需要的任何选项。通过以下方式将此日志记录器添加到 harmony_auth 中:
final logger = Logger();
AuthConfig.logger = logger;
然后,你应该创建一个认证存储。它可以通过 AuthStorage
工厂实现。标准的一个在 Android 和 iOS 上基于 shared_preferences 创建存储,在其他平台上类似。还有一个 inMemory
实现,这是一个内存中的存储。
final storage = AuthStorage();
如果你需要访问认证状态或认证状态流,向你的存储添加 streaming
能力。如果你在 dio 上执行并发请求(通常这是推荐的),向存储添加 locked
能力。
storage = storage.streaming().locked();
然后,你需要创建一个认证 REST。它可以通过 AuthRest
工厂创建。它的第一个责任是获取令牌对并进行网络请求以刷新令牌,然后返回新的令牌。它可以成功返回新令牌,也可以因无效令牌而失败(将抛出 AuthRestException
类型的异常)或因其他问题(如网络问题)而失败(将抛出 DioError
类型的异常)。它不应该有任何副作用。另一个责任是返回一个认证匹配器,以匹配刷新请求,因为我们使用相同的 dio 来完成整个 harmony_auth 部分。标准实现是当你发送刷新令牌并从服务器获取新的刷新和访问令牌对时。accessOnly
实现是当刷新令牌是常量并且你仅在刷新请求时获得新的访问令牌。有一个 general
工厂,你可以用来创建自定义的 REST。请查看 dart 文档以了解自定义用法。你应该提供一个认证检查器,标准和访问仅实现通常一个简单的 AuthChecker()
就足够了。它的责任是检查 HTTP 结果,看是否是因为令牌无效。
final rest = AuthRest(
dio: dio,
refreshUrl: refreshUrl,
checker: AuthChecker(),
);
然后,你需要通过传递存储和 REST 创建一个认证存储库。它只有一个标准工厂。
final repository = AuthRepository(
storage: storage,
rest: rest,
);
如果有并发请求(通常这是推荐的),向你的存储库添加 locked
能力。还考虑添加 debounce
能力,这将限制在时间内的刷新请求次数。例如,带有 1 分钟 debounce 的 harmony_auth 在不到一分钟内不会刷新令牌。
repository = repository.debounce(Duration(minutes: 1)).locked();
然后,你应该为拦截器创建一个认证匹配器。AuthMatcher
用于匹配请求,以检查是否需要认证。你应该精确匹配所有需要认证的请求,并且不匹配不需要认证的请求,否则你会遇到问题。认证匹配器有许多工厂:
all
和 none
用于匹配所有和无请求。url
和 urls
用于匹配 URL,也可以用正则表达式表示。baseUrl
和 baseUrls
用于匹配 URL 的起始部分。byUrl
使你完全控制 URL。method
和 methods
用于匹配方法,也可以用正则表达式表示。方法总是以大写格式表示,如 GET
。byMethod
使你完全控制方法。methodAndUrl
、methodAndBaseUrl
和 byMethodAndUrl
类似。general
使你完全控制每个请求。所有匹配器都支持标准的集合操作,如 |
、&
、_
和 !
。
final matcher = AuthMatcher.baseUrl(baseUrl) -
AuthMatcher.urls({
'$baseUrl/ignored/1',
'$baseUrl/ignored/2',
});
然后,你应该为拦截器创建一个认证检查器。AuthChecker
的责任是检查 DioErrors 是否与未认证有关。标准的 AuthChecker
只检查是否是来自响应的错误,其代码是 401。有其他工厂用于认证检查器,如 statusCodes
和 byStatusCode
,以完全控制状态码。还有 general
用于完全控制 DioErrors。
final checker = AuthChecker();
然后,你应该为拦截器创建一个认证操作器。AuthManipulator
的责任是通过使用给定的认证令牌就地操作 dio 请求。标准的 AuthManipulator()
将 Authorization: Bearer $accessToken
添加到请求头。有一些工厂,如 headers
用于添加多个头,header
用于添加一个头,headerPrefixed
用于添加一个头,其值是访问令牌前缀给定字符串。还有 general
,它给你完全控制。
final manipulator = AuthManipulator();
然后,你需要创建一个拦截器,这是通过使用其标准工厂 AuthInterceptor()
完成的。
final interceptor = AuthInterceptor(
dio: dio,
matcher: matcher,
checker: checker,
manipulator: manipulator,
repository: repository,
);
然后,你需要将拦截器添加到 dio 拦截器:
dio.interceptors.add(interceptor);
然后,你需要通过依赖注入注册 dio 和存储库。
注意: 你应该在整个 harmony_auth 库中使用相同的 dio。
完整示例
简单示例
// 请查看引导文件夹中的示例。
void main() {}
复杂示例
// 请查看引导文件夹中的示例。
void main() {}
更多关于Flutter认证授权插件harmony_auth的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter认证授权插件harmony_auth的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用harmony_auth
插件进行认证授权的一个简单示例。请注意,实际使用中可能需要根据具体业务逻辑进行调整和扩展。
1. 添加依赖
首先,在pubspec.yaml
文件中添加harmony_auth
依赖:
dependencies:
flutter:
sdk: flutter
harmony_auth: ^最新版本号 # 请替换为实际的最新版本号
然后运行flutter pub get
来安装依赖。
2. 导入插件
在你的Dart文件中(比如main.dart
),导入harmony_auth
插件:
import 'package:flutter/material.dart';
import 'package:harmony_auth/harmony_auth.dart';
3. 初始化HarmonyAuth
通常你会在应用的初始化阶段配置HarmonyAuth。这里是一个简单的配置示例:
void main() {
WidgetsFlutterBinding.ensureInitialized();
// 初始化HarmonyAuth
HarmonyAuth.configure(
clientId: '你的客户端ID',
clientSecret: '你的客户端密钥', // 如果需要
redirectUri: '你的回调URI',
authorizationEndpoint: '认证端点URL',
tokenEndpoint: '令牌端点URL',
userInfoEndpoint: '用户信息端点URL', // 可选,用于获取用户信息
scopes: ['scope1', 'scope2'], // 你需要的权限范围
);
runApp(MyApp());
}
4. 使用HarmonyAuth进行认证
在你的应用逻辑中,可以使用HarmonyAuth.authorize()
方法进行认证。下面是一个简单的按钮点击事件处理示例:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('HarmonyAuth 示例'),
),
body: Center(
child: ElevatedButton(
onPressed: () async {
try {
// 发起认证请求
AuthResult result = await HarmonyAuth.authorize();
if (result.accessToken != null) {
// 认证成功,处理访问令牌
print('访问令牌: ${result.accessToken}');
// 你可以在这里使用访问令牌去获取用户信息或者访问受保护的资源
UserInfo userInfo = await HarmonyAuth.getUserInfo();
print('用户信息: ${userInfo.toJson()}');
} else {
print('认证失败');
}
} catch (e) {
print('认证过程中发生错误: $e');
}
},
child: Text('进行认证'),
),
),
),
);
}
}
5. 处理用户信息和错误
在上面的示例中,我们演示了如何在认证成功后获取用户信息,并打印到控制台。在实际应用中,你可能需要将这些信息存储到本地或使用它们来更新UI。
同时,我们也展示了如何捕获并处理认证过程中可能发生的错误。
注意事项
- 请确保你已经注册了相应的OAuth应用,并获得了
clientId
、clientSecret
(如果需要)、redirectUri
等必要信息。 - 根据你的OAuth服务提供者,认证端点、令牌端点、用户信息端点等URL可能会有所不同。
- 安全性是非常重要的,不要在客户端代码中硬编码敏感信息,如
clientSecret
。如果必须使用,请确保它们受到适当的保护。
希望这个示例能帮助你理解如何在Flutter项目中使用harmony_auth
插件进行认证授权。如果你有更具体的需求或问题,请随时提问。