Skip to content

Commit

Permalink
fix: refresh token issue (#353)
Browse files Browse the repository at this point in the history
  • Loading branch information
2paperstar authored Sep 15, 2024
1 parent 376dc4b commit a0eeff1
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:dio/dio.dart';
import 'package:injectable/injectable.dart';
import 'package:mutex/mutex.dart';
import 'package:ziggle/app/di/locator.dart';
import 'package:ziggle/app/modules/user/data/data_sources/remote/user_api.dart';
import 'package:ziggle/app/modules/user/domain/repositories/token_repository.dart';
Expand All @@ -8,6 +9,7 @@ import 'package:ziggle/app/modules/user/domain/repositories/token_repository.dar
class AuthorizeInterceptor extends Interceptor {
final TokenRepository _repository;
static const retriedKey = '_retried';
final mutex = ReadWriteMutex();

AuthorizeInterceptor(this._repository);

Expand All @@ -19,22 +21,11 @@ class AuthorizeInterceptor extends Interceptor {
if (statusCode != 401) return handler.next(err);
final token = await _repository.token.first;
if (token == null) return handler.next(err);
final retried = err.requestOptions.extra.containsKey(retriedKey);
if (retried) return handler.next(err);
err.requestOptions.extra[retriedKey] = true;
if (err.requestOptions.retried) return handler.next(err);
err.requestOptions.retried = true;

try {
final userApi = sl<UserApi>();
try {
userApi.testTokenInfo();
} catch (e) {
try {
final token = await userApi.refresh();
await _repository.saveToken(token.accessToken);
} catch (e) {
await _repository.deleteToken();
return handler.next(err);
}
}
if (!(await _refresh())) return handler.next(err);
final retriedResponse = await dio.fetch(err.requestOptions);
return handler.resolve(retriedResponse);
} on DioException {
Expand All @@ -47,19 +38,47 @@ class AuthorizeInterceptor extends Interceptor {
RequestOptions options,
RequestInterceptorHandler handler,
) async {
if (options.retried) return handler.next(options);
if (_repository.tokenExpiration != null) {
if (DateTime.now().isAfter(_repository.tokenExpiration!)) {
try {
final userApi = sl<UserApi>();
final token = await userApi.refresh();
await _repository.saveToken(token.accessToken);
} catch (_) {}
await _refresh();
}
}
final token = await _repository.token.first;
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';

try {
await mutex.acquireRead();
final token = await _repository.token.first;
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
handler.next(options);
} finally {
mutex.release();
}
handler.next(options);
}

Future<bool> _refresh() async {
if (mutex.isWriteLocked) {
await mutex.acquireRead();
mutex.release();
return true;
}
await mutex.acquireWrite();
final userApi = sl<UserApi>();
try {
final token = await userApi.refresh();
await _repository.saveToken(token.accessToken);
return true;
} catch (e) {
await _repository.deleteToken();
return false;
} finally {
mutex.release();
}
}
}

extension _RequestOptionsX on RequestOptions {
bool get retried => extra.containsKey(AuthorizeInterceptor.retriedKey);
set retried(bool value) => extra[AuthorizeInterceptor.retriedKey] = value;
}
4 changes: 0 additions & 4 deletions lib/app/modules/user/data/data_sources/remote/user_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ abstract class UserApi {
@Extra({AuthorizeInterceptor.retriedKey: true})
Future<TokenModel> refresh();

@GET('info')
@Extra({AuthorizeInterceptor.retriedKey: true})
Future testTokenInfo();

@GET('info')
Future<UserModel> info();
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class RestAuthRepository implements AuthRepository {
Stream<bool> get isSignedIn => _tokenRepository.token.asyncMap(
(_) async {
try {
await _api.testTokenInfo();
await _api.info();
return true;
} catch (_) {
return false;
Expand Down
1 change: 1 addition & 0 deletions lib/app/modules/user/presentation/bloc/auth_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ sealed class AuthState with _$AuthState {

bool get hasUser => this is _Authenticated;
bool get isLoading => this is _Loading;
bool get hasError => this is _Error;
}
2 changes: 1 addition & 1 deletion lib/app/modules/user/presentation/pages/profile_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class _Layout extends StatelessWidget {
_Profile(user: state.user!)
else
BlocBuilder<AuthBloc, AuthState>(
buildWhen: (c, p) => p.isLoading,
buildWhen: (c, p) => p.isLoading || p.hasError,
builder: (context, authState) => Stack(
alignment: Alignment.center,
children: [
Expand Down
8 changes: 8 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.6"
mutex:
dependency: "direct main"
description:
name: mutex
sha256: "8827da25de792088eb33e572115a5eb0d61d61a3c01acbc8bcbe76ed78f1a1f2"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
nested:
dependency: transitive
description:
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ dependencies:
collection: ^1.18.0
flutter_inappwebview: ^5.8.0
url_launcher: ^6.3.0
mutex: ^3.1.0

dev_dependencies:
flutter_test:
Expand Down

0 comments on commit a0eeff1

Please sign in to comment.