Flutter Clean Architecture中如何全局访问授权令牌?
遵循Clean Architecture的令牌访问方案
不需要给每个数据源方法都手动传入令牌参数,以下是几种符合Clean Architecture原则的实现方式:
1. 基于抽象接口的令牌提供者(TokenProvider)
核心思路是通过依赖倒置原则,让需要令牌的模块依赖抽象接口,而非具体的令牌存储实现,同时由Auth模块负责令牌的更新和管理。
- 定义抽象接口(放在Domain层,确保各层都可依赖):
abstract class TokenProvider { String? get currentToken; }
- 在Auth模块的Data层实现该接口,负责令牌的存储与更新:
class AuthTokenProvider implements TokenProvider { String? _token; @override String? get currentToken => _token; // 由Auth模块调用,比如登录成功后更新令牌,登出时置空 void updateToken(String? newToken) { _token = newToken; } }
- 通过依赖注入工具(如get_it)注册抽象与实现的绑定:
getIt.registerSingleton<TokenProvider>(AuthTokenProvider());
- 在数据源中注入
TokenProvider并直接使用:
class AlimentRemoteDataSourceImpl implements AlimentRemoteDataSource { final HttpClient client; final TokenProvider tokenProvider; AlimentRemoteDataSourceImpl({ required this.client, required this.tokenProvider, }); @override Future<(List<AlimentModel>, int)> getAllAliments() async { final http.Response response = await client.get( Uri.http(APIBaseURL, '$routeName/all'), headers: generateHeaders( contentType: null, authorization: tokenProvider.currentToken, ), ); // ... 原有逻辑不变 } }
这种方式的优势:
- 符合Clean Architecture的依赖规则,依赖抽象而非具体实现
- 测试时可轻松替换为Mock实现,便于单元测试
- 令牌的管理完全由Auth模块负责,其他模块无需关心细节
2. 封装带令牌拦截的HTTP客户端
将令牌注入逻辑封装到HTTP客户端的拦截器中,让所有请求自动携带令牌,进一步简化数据源的代码。
- 自定义HTTP客户端或使用拦截器(以Dio为例):
class AuthenticatedHttpClient { final Dio _dio; final TokenProvider _tokenProvider; AuthenticatedHttpClient(this._dio, this._tokenProvider) { _dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) { final token = _tokenProvider.currentToken; if (token != null) { options.headers['Authorization'] = 'Bearer $token'; } return handler.next(options); }, )); } Future<Response> get(String path) => _dio.get(path); // 封装其他HTTP方法:post、put等 }
- 数据源直接使用这个封装后的客户端,无需手动处理令牌:
class AlimentRemoteDataSourceImpl implements AlimentRemoteDataSource { final AuthenticatedHttpClient client; AlimentRemoteDataSourceImpl({required this.client}); @override Future<(List<AlimentModel>, int)> getAllAliments() async { final Response response = await client.get('$routeName/all'); // ... 原有逻辑不变 } }
为什么单例方式不够规范?
直接用SessionToken单例会导致:
- 代码产生硬依赖,违反依赖倒置原则,难以替换或测试
- 令牌的管理逻辑与使用逻辑耦合,不符合Clean Architecture的分层职责划分
内容的提问来源于stack exchange,提问作者Kilian Danckaerts
相关产品推荐
相关产品推荐

