我的一个Flutter应用程序中的BloC提供程序出现问题。我使用Chopper作为HTTP客户端,它在应用程序的开头创建了一个Chopper实例,然后在我想从API获取数据的任何地方注入get_id。在此期间,我实现了一个ChopperAuthenticator,当旧的令牌过期时,它会从API获取新的令牌(状态代码401(。但问题是,如果刷新令牌也过期了,则用户应该注销。为此,我只检查刷新令牌的获取是否成功,如果不是这样,则应通知我的Authentication BloC用户不再登录。
但我不能调用BlocProvider.of<AuthenticationBloc>(context).add(Logout());
,因为在斩波器实例中,构建上下文是未知的。有没有其他方法可以改变集团公司的状态?你有什么想法吗?我该如何重建整件事,让它发挥作用?
FlutterSecureStorage storage = locator.getIt<FlutterSecureStorage>();
UserRepository userRepository = locator.getIt<UserRepository>();
Swagger getClient(String baseUrl) {
return Swagger.create(
baseUrl: baseUrl,
authenticator: ChopperAuthenticator(),
interceptors: [
MobileDataInterceptor(),
const HeadersInterceptor(
{
'content-type': 'application/json',
'Accept': 'application/json',
},
),
HttpLoggingInterceptor(),
(Response response) async {
return response;
},
(Request request) async {
final String? token = await storage.read(key: 'accessToken');
if (token != null && !request.url.contains('refresh')) {
final Map<String, String> map = {'authorization': 'Bearer $token'};
request.headers.addAll(map);
}
return request;
},
],
);
}
class ChopperAuthenticator extends Authenticator {
@override
FutureOr<Request?> authenticate(
Request request,
Response<dynamic> response, [
Request? originalRequest,
]) async {
if (response.statusCode == 401) {
final String? refreshToken = await storage.read(
key: 'refreshToken',
);
final String? accessToken = await storage.read(
key: 'accessToken',
);
final Response newResponse =
await userRepository.apiClient.apiAuthenticateRefreshTokenPost(
body: RefreshRequestDTO(
accessToken: accessToken,
refreshToken: refreshToken,
),
);
if (newResponse.isSuccessful) {
await storage.write(
key: 'accessToken',
value: newResponse.body['accessToken'].toString(),
);
await storage.write(
key: 'refreshToken',
value: newResponse.body['refreshToken'].toString(),
);
String? newToken = newResponse.body['accessToken'].toString();
final Map<String, String> updatedHeaders =
Map<String, String>.of(request.headers);
newToken = 'Bearer $newToken';
updatedHeaders.update(
'Authorization',
(String _) => newToken!,
ifAbsent: () => newToken!,
);
debugPrint('Token renewed');
return request.copyWith(headers: updatedHeaders);
} else {
<Here should be the logic to log out the user>
}
}
return null;
}
}
快速肮脏的解决方案:
由于您使用的是getIt
,因此在创建区块时应将其添加到其中,如:
BlocProvider<AuthBloc>(
create: (context) {
var bloc = AuthBloc();
getIt.registerLazySingleton(() => bloc); //registering for later use
return bloc;
},
)
然后在注销部分,您可以直接致电
getIt<AuthBloc>().add(LogOut());
正确的解决方案:
创建一个保存身份验证的存储库。这个存储库应该有一个AuthBloc
订阅的流。将存储库注入斩波器Authenticator
,然后从那里操作存储库的流。
您的AuthBloc
应该对流更改做出反应,从而注销用户。
这种方法将符合官方文件https://bloclibrary.dev/#/architecture