TF-606 Implement refresh token when access token expired

This commit is contained in:
dab246
2022-06-03 17:17:31 +07:00
committed by Dat H. Pham
parent 02a5fa4b4f
commit 693f4dbc15
14 changed files with 248 additions and 54 deletions
@@ -1,32 +1,141 @@
import 'dart:convert';
import 'dart:io';
import 'package:core/utils/app_logger.dart';
import 'package:dio/dio.dart';
import 'package:model/model.dart';
import 'package:model/account/account.dart';
import 'package:model/account/authentication_type.dart';
import 'package:model/oidc/oidc_configuration.dart';
import 'package:model/oidc/token.dart';
import 'package:model/oidc/token_oidc.dart';
import 'package:tmail_ui_user/features/login/data/local/account_cache_manager.dart';
import 'package:tmail_ui_user/features/login/data/local/token_oidc_cache_manager.dart';
import 'package:tmail_ui_user/features/login/data/network/oidc_http_client.dart';
class AuthorizationInterceptors extends InterceptorsWrapper {
String? _authorization;
Token? _token;
void changeAuthorization(String? userName, String? password) {
final Dio _dio;
final OIDCHttpClient _oidcHttpClient;
final TokenOidcCacheManager _tokenOidcCacheManager;
final AccountCacheManager _accountCacheManager;
AuthenticationType _authenticationType = AuthenticationType.none;
OIDCConfiguration? _configOIDC;
Token? _token;
String? _authorization;
AuthorizationInterceptors(
this._dio,
this._oidcHttpClient,
this._tokenOidcCacheManager,
this._accountCacheManager
);
void setBasicAuthorization(String? userName, String? password) {
_authorization = base64Encode(utf8.encode('$userName:$password'));
_authenticationType = AuthenticationType.basic;
}
void setToken(Token? newToken) {
void setTokenAndAuthorityOidc({Token? newToken, OIDCConfiguration? newConfig}) {
_token = newToken;
_configOIDC = newConfig;
_authenticationType = AuthenticationType.oidc;
log('AuthorizationInterceptors::setToken(): newToken: $newToken');
log('AuthorizationInterceptors::setToken(): tokenId: ${newToken?.tokenIdHash}');
log('AuthorizationInterceptors::setToken(): EXPIRE_DATE: ${newToken?.expiredTime?.toIso8601String()}');
}
void _updateNewToken(Token newToken) {
_token = newToken;
}
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
if (_authorization != null) {
options.headers[HttpHeaders.authorizationHeader] = _getAuthorizationAsBasicHeader(_authorization);
} else if (_token != null && _token?.isTokenValid() == true) {
options.headers[HttpHeaders.authorizationHeader] = _getTokenAsBearerHeader(_token!.token);
switch(_authenticationType) {
case AuthenticationType.basic:
if (_authorization != null) {
options.headers[HttpHeaders.authorizationHeader] = _getAuthorizationAsBasicHeader(_authorization);
}
break;
case AuthenticationType.oidc:
if (_token != null && _token?.isTokenValid() == true) {
options.headers[HttpHeaders.authorizationHeader] = _getTokenAsBearerHeader(_token!.token);
}
break;
case AuthenticationType.none:
break;
}
super.onRequest(options, handler);
}
@override
void onError(DioError err, ErrorInterceptorHandler handler) async {
final requestOptions = err.requestOptions;
log('AuthorizationInterceptors::onError(): $err');
if ((_isTokenExpired() || err.response?.statusCode == 401) &&
_isAuthenticationOidcValid()) {
try {
final newToken = await _oidcHttpClient.refreshingTokensOIDC(
_configOIDC!.clientId,
_configOIDC!.redirectUrl,
_configOIDC!.discoveryUrl,
_configOIDC!.scopes,
_token!.refreshToken);
await Future.wait([
_tokenOidcCacheManager.persistOneTokenOidc(newToken),
_accountCacheManager.deleteSelectedAccount(_token!.tokenIdHash),
_accountCacheManager.setSelectedAccount(Account(
newToken.tokenIdHash,
AuthenticationType.oidc,
isSelected: true)),
]);
log('AuthorizationInterceptors::onError(): refreshToken: $newToken');
log('AuthorizationInterceptors::setToken(): refreshTokenId: ${newToken.tokenIdHash}');
_updateNewToken(newToken.toToken());
requestOptions.headers[HttpHeaders.authorizationHeader] =
_getTokenAsBearerHeader(newToken.token);
final response = await _dio.fetch(requestOptions);
return handler.resolve(response);
} catch(e) {
log('AuthorizationInterceptors::onError(): $e');
super.onError(err, handler);
}
} else {
super.onError(err, handler);
}
}
bool _isTokenExpired() {
if (_token?.isExpired == true) {
log('AuthorizationInterceptors::_isTokenExpired(): TOKE_EXPIRED');
return true;
}
return false;
}
bool _isAuthenticationOidcValid() {
if (_authenticationType == AuthenticationType.oidc &&
_configOIDC != null &&
_token != null) {
log('AuthorizationInterceptors::_isAuthenticationOidcValid()');
return true;
}
return false;
}
String _getAuthorizationAsBasicHeader(String? authorization) => 'Basic $authorization';
String _getTokenAsBearerHeader(String token) => 'Bearer $token';
void clear() {
_authorization = null;
_token = null;
_configOIDC = null;
_authenticationType = AuthenticationType.none;
}
}