Handle call retry up to 3 time when statusCode=401

(cherry picked from commit 09a93eff116a1dffc6a59ab97226a86cba47998e)
This commit is contained in:
dab246
2023-09-08 19:38:06 +07:00
committed by Dat Vu
parent a822d98c15
commit 604698d4e4
@@ -15,6 +15,9 @@ import 'package:tmail_ui_user/features/login/data/network/authentication_client/
class AuthorizationInterceptors extends QueuedInterceptorsWrapper { class AuthorizationInterceptors extends QueuedInterceptorsWrapper {
static const int _maxRetryCount = 3;
static const String RETRY_KEY = 'Retry';
final Dio _dio; final Dio _dio;
final AuthenticationClientBase _authenticationClient; final AuthenticationClientBase _authenticationClient;
final TokenOidcCacheManager _tokenOidcCacheManager; final TokenOidcCacheManager _tokenOidcCacheManager;
@@ -41,7 +44,6 @@ class AuthorizationInterceptors extends QueuedInterceptorsWrapper {
_token = newToken; _token = newToken;
_configOIDC = newConfig; _configOIDC = newConfig;
_authenticationType = AuthenticationType.oidc; _authenticationType = AuthenticationType.oidc;
log('AuthorizationInterceptors::setToken(): newToken: $newToken | configOIDC: $_configOIDC');
} }
void _updateNewToken(Token newToken) { void _updateNewToken(Token newToken) {
@@ -54,6 +56,8 @@ class AuthorizationInterceptors extends QueuedInterceptorsWrapper {
@override @override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) { void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
log('AuthorizationInterceptors::onRequest():DATA: ${options.data}');
log('AuthorizationInterceptors::onRequest():TOKEN_HASHCODE_CURRENT: ${_token?.token.hashCode}');
switch(_authenticationType) { switch(_authenticationType) {
case AuthenticationType.basic: case AuthenticationType.basic:
if (_authorization != null) { if (_authorization != null) {
@@ -73,77 +77,87 @@ class AuthorizationInterceptors extends QueuedInterceptorsWrapper {
@override @override
void onError(DioError err, ErrorInterceptorHandler handler) async { void onError(DioError err, ErrorInterceptorHandler handler) async {
logError('AuthorizationInterceptors::onError():dioType: ${err.type} | statusCode: ${err.response?.statusCode} | message: ${err.message} | statusMessage: ${err.response?.statusMessage}'); logError('AuthorizationInterceptors::onError(): $err');
try { logError('AuthorizationInterceptors::onError():TOKEN_HASHCODE_CURRENT: ${_token?.token.hashCode}');
if (_validateToRefreshToken(err)) {
log('AuthorizationInterceptors::onError:RefreshTokenCalled:configOIDC: $_configOIDC | refreshTokenCurrent: ${_token?.refreshToken}');
final newToken = await _authenticationClient.refreshingTokensOIDC(
_configOIDC!.clientId,
_configOIDC!.redirectUrl,
_configOIDC!.discoveryUrl,
_configOIDC!.scopes,
_token!.refreshToken
);
final accountCurrent = await _accountCacheManager.getSelectedAccount(); final requestOptions = err.requestOptions;
final extraInRequest = requestOptions.extra;
var retries = extraInRequest[RETRY_KEY] ?? 0;
await _accountCacheManager.deleteSelectedAccount(_token!.tokenIdHash); if (_validateToRefreshToken(err)) {
log('AuthorizationInterceptors::onError:>> _validateToRefreshToken');
final newToken = await _authenticationClient.refreshingTokensOIDC(
_configOIDC!.clientId,
_configOIDC!.redirectUrl,
_configOIDC!.discoveryUrl,
_configOIDC!.scopes,
_token!.refreshToken
);
await Future.wait([ final accountCurrent = await _accountCacheManager.getSelectedAccount();
_tokenOidcCacheManager.persistOneTokenOidc(newToken),
_accountCacheManager.setSelectedAccount( await _accountCacheManager.deleteSelectedAccount(_token!.tokenIdHash);
PersonalAccount(
newToken.tokenIdHash, await Future.wait([
AuthenticationType.oidc, _tokenOidcCacheManager.persistOneTokenOidc(newToken),
isSelected: true, _accountCacheManager.setSelectedAccount(
accountId: accountCurrent.accountId, PersonalAccount(
apiUrl: accountCurrent.apiUrl, newToken.tokenIdHash,
userName: accountCurrent.userName AuthenticationType.oidc,
) isSelected: true,
accountId: accountCurrent.accountId,
apiUrl: accountCurrent.apiUrl,
userName: accountCurrent.userName
) )
]); )
log('AuthorizationInterceptors::onError():NewToken: $newToken'); ]);
_updateNewToken(newToken.toToken()); _updateNewToken(newToken.toToken());
final requestOptions = err.requestOptions; final requestOptions = err.requestOptions;
requestOptions.headers[HttpHeaders.authorizationHeader] = _getTokenAsBearerHeader(newToken.token); requestOptions.headers[HttpHeaders.authorizationHeader] = _getTokenAsBearerHeader(newToken.token);
final response = await _dio.fetch(requestOptions); final response = await _dio.fetch(requestOptions);
return handler.resolve(response); return handler.resolve(response);
} else { } else if (_validateToRetry(err, retries)) {
super.onError(err, handler); log('AuthorizationInterceptors::onError:>> _validateToRetry | retries: $retries');
} retries++;
} catch (e) {
logError('AuthorizationInterceptors::onError():Exception: $e'); final requestOptions = err.requestOptions;
requestOptions.headers[HttpHeaders.authorizationHeader] = _getTokenAsBearerHeader(_token!.token);
requestOptions.extra = {RETRY_KEY: retries};
final response = await _dio.fetch(requestOptions);
return handler.resolve(response);
} else {
super.onError(err, handler); super.onError(err, handler);
} }
} }
bool _isTokenExpired() { bool _isTokenExpired() => _token?.isExpired == true;
if (_token?.isExpired == true) {
log('AuthorizationInterceptors::_isTokenExpired(): TOKE_EXPIRED');
return true;
}
return false;
}
bool _isAuthenticationOidcValid() { bool _isAuthenticationOidcValid() => _authenticationType == AuthenticationType.oidc && _configOIDC != null;
if (_authenticationType == AuthenticationType.oidc &&
_configOIDC != null &&
_token != null) {
log('AuthorizationInterceptors::_isAuthenticationOidcValid()');
return true;
}
return false;
}
bool _isRefreshTokenNotEmpty() => _token != null && _token!.refreshToken.isNotEmpty; bool _isTokenNotEmpty() => _token?.token.isNotEmpty == true;
bool _isRefreshTokenNotEmpty() => _token?.refreshToken.isNotEmpty == true;
bool _validateToRefreshToken(DioError dioError) { bool _validateToRefreshToken(DioError dioError) {
if (_isTokenExpired() && if (dioError.response?.statusCode == 401 &&
(dioError.response == null || dioError.response?.statusCode == 401) && _isAuthenticationOidcValid() &&
_isRefreshTokenNotEmpty() && _isRefreshTokenNotEmpty() &&
_isAuthenticationOidcValid()) { _isTokenExpired()
) {
return true;
}
return false;
}
bool _validateToRetry(DioError dioError, int retryCount) {
if (dioError.type == DioErrorType.badResponse &&
dioError.response?.statusCode == 401 &&
_isTokenNotEmpty() &&
retryCount < _maxRetryCount
) {
return true; return true;
} }
return false; return false;