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
@@ -63,7 +63,7 @@ abstract class ReloadableController extends BaseController {
void _setUpInterceptors(GetCredentialViewState credentialViewState) { void _setUpInterceptors(GetCredentialViewState credentialViewState) {
_dynamicUrlInterceptors.changeBaseUrl(credentialViewState.baseUrl.origin); _dynamicUrlInterceptors.changeBaseUrl(credentialViewState.baseUrl.origin);
_authorizationInterceptors.changeAuthorization( _authorizationInterceptors.setBasicAuthorization(
credentialViewState.userName.userName, credentialViewState.userName.userName,
credentialViewState.password.value, credentialViewState.password.value,
); );
@@ -119,13 +119,15 @@ class HomeController extends BaseController {
void _goToSessionWithTokenOidc(GetStoredTokenOidcSuccess storedTokenOidcSuccess) { void _goToSessionWithTokenOidc(GetStoredTokenOidcSuccess storedTokenOidcSuccess) {
_dynamicUrlInterceptors.changeBaseUrl(storedTokenOidcSuccess.baseUrl.toString()); _dynamicUrlInterceptors.changeBaseUrl(storedTokenOidcSuccess.baseUrl.toString());
_authorizationInterceptors.setToken(storedTokenOidcSuccess.tokenOidc.toToken()); _authorizationInterceptors.setTokenAndAuthorityOidc(
newToken: storedTokenOidcSuccess.tokenOidc.toToken(),
newConfig: storedTokenOidcSuccess.oidcConfiguration);
pushAndPop(AppRoutes.SESSION); pushAndPop(AppRoutes.SESSION);
} }
void _goToSessionWithBasicAuth(GetCredentialViewState credentialViewState) { void _goToSessionWithBasicAuth(GetCredentialViewState credentialViewState) {
_dynamicUrlInterceptors.changeBaseUrl(credentialViewState.baseUrl.origin); _dynamicUrlInterceptors.changeBaseUrl(credentialViewState.baseUrl.origin);
_authorizationInterceptors.changeAuthorization( _authorizationInterceptors.setBasicAuthorization(
credentialViewState.userName.userName, credentialViewState.userName.userName,
credentialViewState.password.value, credentialViewState.password.value,
); );
@@ -0,0 +1,14 @@
import 'package:flutter_appauth/flutter_appauth.dart';
import 'package:model/model.dart';
extension TokenResponseExtension on TokenResponse {
TokenOIDC toTokenOIDC() {
return TokenOIDC(
accessToken ?? '',
TokenId(idToken ?? ''),
refreshToken ?? '',
expiredTime: accessTokenExpirationDateTime ?? DateTime.now());
}
}
@@ -25,4 +25,9 @@ class AccountCacheManager {
log('AccountCacheManager::setSelectedAccount(): $_accountCacheClient'); log('AccountCacheManager::setSelectedAccount(): $_accountCacheClient');
return _accountCacheClient.insertItem(account.id, account.toCache()); return _accountCacheClient.insertItem(account.id, account.toCache());
} }
Future<void> deleteSelectedAccount(String accountId) {
log('AccountCacheManager::deleteSelectedAccount(): $accountId');
return _accountCacheClient.deleteItem(accountId);
}
} }
@@ -26,8 +26,8 @@ class TokenOidcCacheManager {
await _tokenOidcCacheClient.clearAllData(); await _tokenOidcCacheClient.clearAllData();
} }
log('TokenOidcCacheManager::persistOneTokenOidc(): key: ${tokenOIDC.tokenId.uuid}'); log('TokenOidcCacheManager::persistOneTokenOidc(): key: ${tokenOIDC.tokenId.uuid}');
log('TokenOidcCacheManager::persistOneTokenOidc(): key\'s hash: ${tokenOIDC.tokenId.hashCode.toString()}'); log('TokenOidcCacheManager::persistOneTokenOidc(): key\'s hash: ${tokenOIDC.tokenIdHash}');
log('TokenOidcCacheManager::persistOneTokenOidc(): token: ${tokenOIDC.token}'); log('TokenOidcCacheManager::persistOneTokenOidc(): token: ${tokenOIDC.token}');
await _tokenOidcCacheClient.insertItem(tokenOIDC.tokenId.hashCode.toString(), tokenOIDC.toTokenOidcCache()); await _tokenOidcCacheClient.insertItem(tokenOIDC.tokenIdHash, tokenOIDC.toTokenOidcCache());
} }
} }
@@ -1,32 +1,141 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:core/utils/app_logger.dart';
import 'package:dio/dio.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 { 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')); _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; _token = newToken;
} }
@override @override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) { void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
if (_authorization != null) { switch(_authenticationType) {
options.headers[HttpHeaders.authorizationHeader] = _getAuthorizationAsBasicHeader(_authorization); case AuthenticationType.basic:
} else if (_token != null && _token?.isTokenValid() == true) { if (_authorization != null) {
options.headers[HttpHeaders.authorizationHeader] = _getTokenAsBearerHeader(_token!.token); 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); 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 _getAuthorizationAsBasicHeader(String? authorization) => 'Basic $authorization';
String _getTokenAsBearerHeader(String token) => 'Bearer $token'; String _getTokenAsBearerHeader(String token) => 'Bearer $token';
void clear() {
_authorization = null;
_token = null;
_configOIDC = null;
_authenticationType = AuthenticationType.none;
}
} }
@@ -1,14 +1,21 @@
import 'dart:convert'; import 'dart:convert';
import 'package:core/core.dart'; import 'package:core/data/model/query/query_parameter.dart';
import 'package:core/data/network/dio_client.dart';
import 'package:core/utils/app_logger.dart';
import 'package:flutter_appauth/flutter_appauth.dart'; import 'package:flutter_appauth/flutter_appauth.dart';
import 'package:model/model.dart'; import 'package:model/oidc/oidc_configuration.dart';
import 'package:model/oidc/request/oidc_request.dart';
import 'package:model/oidc/response/oidc_response.dart';
import 'package:model/oidc/token_oidc.dart';
import 'package:tmail_ui_user/features/login/data/extensions/authentication_token_extension.dart'; import 'package:tmail_ui_user/features/login/data/extensions/authentication_token_extension.dart';
import 'package:tmail_ui_user/features/login/data/extensions/service_path_extension.dart'; import 'package:tmail_ui_user/features/login/data/extensions/service_path_extension.dart';
import 'package:tmail_ui_user/features/login/data/extensions/token_response_extension.dart';
import 'package:tmail_ui_user/features/login/data/network/config/oidc_constant.dart'; import 'package:tmail_ui_user/features/login/data/network/config/oidc_constant.dart';
import 'package:tmail_ui_user/features/login/data/network/endpoint.dart'; import 'package:tmail_ui_user/features/login/data/network/endpoint.dart';
import 'package:tmail_ui_user/features/login/data/network/oidc_error.dart'; import 'package:tmail_ui_user/features/login/data/network/oidc_error.dart';
import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart';
class OIDCHttpClient { class OIDCHttpClient {
@@ -48,20 +55,47 @@ class OIDCHttpClient {
} }
Future<TokenOIDC> getTokenOIDC(String clientId, String redirectUrl, String discoveryUrl, List<String> scopes) async { Future<TokenOIDC> getTokenOIDC(String clientId, String redirectUrl, String discoveryUrl, List<String> scopes) async {
final tokenResponse = await _appAuth.authorizeAndExchangeCode(AuthorizationTokenRequest( final authorizationTokenResponse = await _appAuth.authorizeAndExchangeCode(AuthorizationTokenRequest(
clientId, clientId,
redirectUrl, redirectUrl,
discoveryUrl: discoveryUrl, discoveryUrl: discoveryUrl,
scopes: scopes, scopes: scopes,
preferEphemeralSession: true)); preferEphemeralSession: true));
log('OIDCHttpClient::getTokenOIDC(): token: ${tokenResponse?.accessToken}'); log('OIDCHttpClient::getTokenOIDC(): token: ${authorizationTokenResponse?.accessToken}');
if (authorizationTokenResponse != null) {
final tokenOIDC = authorizationTokenResponse.toTokenOIDC();
if (tokenOIDC.isTokenValid()) {
return tokenOIDC;
} else {
throw AccessTokenInvalidException();
}
} else {
throw NotFoundAccessTokenException();
}
}
Future<TokenOIDC> refreshingTokensOIDC(String clientId, String redirectUrl,
String discoveryUrl, List<String> scopes, String refreshToken) async {
final tokenResponse = await _appAuth.token(TokenRequest(
clientId,
redirectUrl,
discoveryUrl: discoveryUrl,
refreshToken: refreshToken,
scopes: scopes));
log('OIDCHttpClient::refreshingTokensOIDC(): refreshToken: ${tokenResponse?.accessToken}');
if (tokenResponse != null) { if (tokenResponse != null) {
final tokenOIDC = tokenResponse.toTokenOIDC(); final tokenOIDC = tokenResponse.toTokenOIDC();
return tokenOIDC.isTokenValid() ? tokenOIDC : TokenOIDC.empty(); if (tokenOIDC.isTokenValid()) {
return tokenOIDC;
} else {
throw AccessTokenInvalidException();
}
} else { } else {
return TokenOIDC.empty(); throw NotFoundAccessTokenException();
} }
} }
} }
@@ -27,4 +27,12 @@ class InvalidBaseUrl extends AuthenticationException {
@override @override
List<Object?> get props => []; List<Object?> get props => [];
}
class NotFoundAccessTokenException implements Exception {
NotFoundAccessTokenException();
}
class AccessTokenInvalidException implements Exception {
AccessTokenInvalidException();
} }
@@ -1,8 +1,12 @@
import 'package:core/core.dart'; import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:core/utils/app_logger.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:model/account/account.dart'; import 'package:model/account/account.dart';
import 'package:model/account/authentication_type.dart'; import 'package:model/account/authentication_type.dart';
import 'package:model/oidc/oidc_configuration.dart';
import 'package:model/oidc/token_oidc.dart';
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart'; import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart'; import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart'; import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
@@ -16,24 +20,19 @@ class GetTokenOIDCInteractor {
GetTokenOIDCInteractor(this._credentialRepository, this.authenticationOIDCRepository, this._accountRepository); GetTokenOIDCInteractor(this._credentialRepository, this.authenticationOIDCRepository, this._accountRepository);
Future<Either<Failure, Success>> execute( Future<Either<Failure, Success>> execute(Uri baseUrl, OIDCConfiguration config) async {
Uri baseUrl,
String clientId,
String redirectUrl,
String discoveryUrl,
List<String> scopes
) async {
try { try {
log('GetTokenOIDCInteractor::execute(): baseUrl: $baseUrl'); log('GetTokenOIDCInteractor::execute(): baseUrl: $baseUrl');
final tokenOIDC = await authenticationOIDCRepository final tokenOIDC = await authenticationOIDCRepository
.getTokenOIDC(clientId, redirectUrl, discoveryUrl, scopes); .getTokenOIDC(config.clientId, config.redirectUrl, config.discoveryUrl, config.scopes);
await Future.wait([ await Future.wait([
_credentialRepository.saveBaseUrl(baseUrl), _credentialRepository.saveBaseUrl(baseUrl),
_accountRepository.setCurrentAccount(Account( _accountRepository.setCurrentAccount(Account(
tokenOIDC.tokenId.hashCode.toString(), tokenOIDC.tokenIdHash,
AuthenticationType.oidc, AuthenticationType.oidc,
isSelected: true)), isSelected: true)),
authenticationOIDCRepository.persistTokenOIDC(tokenOIDC) authenticationOIDCRepository.persistTokenOIDC(tokenOIDC),
authenticationOIDCRepository.persistAuthorityOidc(config.authority),
]); ]);
return Right<Failure, Success>(GetTokenOIDCSuccess(tokenOIDC)); return Right<Failure, Success>(GetTokenOIDCSuccess(tokenOIDC));
} catch (e) { } catch (e) {
@@ -164,7 +164,7 @@ class LoginController extends GetxController {
final baseUri = kIsWeb ? _parseUri(AppConfig.baseUrl) : _parseUri(_urlText); final baseUri = kIsWeb ? _parseUri(AppConfig.baseUrl) : _parseUri(_urlText);
if (baseUri != null) { if (baseUri != null) {
await _getTokenOIDCInteractor await _getTokenOIDCInteractor
.execute(baseUri, config.clientId, config.redirectUrl, config.discoveryUrl, config.scopes) .execute(baseUri, config)
.then((response) => .then((response) =>
response.fold( response.fold(
(failure) { (failure) {
@@ -176,7 +176,7 @@ class LoginController extends GetxController {
}, },
(success) { (success) {
if (success is GetTokenOIDCSuccess) { if (success is GetTokenOIDCSuccess) {
_getTokenOIDCSuccess(success); _getTokenOIDCSuccess(success, config);
} else { } else {
loginState.value = LoginState(Left(LoginCanNotGetTokenAction())); loginState.value = LoginState(Left(LoginCanNotGetTokenAction()));
} }
@@ -186,11 +186,13 @@ class LoginController extends GetxController {
} }
} }
void _getTokenOIDCSuccess(GetTokenOIDCSuccess success) { void _getTokenOIDCSuccess(GetTokenOIDCSuccess success, OIDCConfiguration config) {
log('LoginController::_getTokenOIDCSuccess(): ${success.tokenOIDC.toString()}'); log('LoginController::_getTokenOIDCSuccess(): ${success.tokenOIDC.toString()}');
loginState.value = LoginState(Right(success)); loginState.value = LoginState(Right(success));
_dynamicUrlInterceptors.changeBaseUrl(kIsWeb ? AppConfig.baseUrl : _urlText); _dynamicUrlInterceptors.changeBaseUrl(kIsWeb ? AppConfig.baseUrl : _urlText);
_authorizationInterceptors.setToken(success.tokenOIDC.toToken()); _authorizationInterceptors.setTokenAndAuthorityOidc(
newToken: success.tokenOIDC.toToken(),
newConfig: config);
pushAndPop(AppRoutes.SESSION); pushAndPop(AppRoutes.SESSION);
} }
@@ -205,7 +207,7 @@ class LoginController extends GetxController {
void _loginSuccessAction(AuthenticationUserViewState success) { void _loginSuccessAction(AuthenticationUserViewState success) {
loginState.value = LoginState(Right(success)); loginState.value = LoginState(Right(success));
_dynamicUrlInterceptors.changeBaseUrl(kIsWeb ? AppConfig.baseUrl : _urlText); _dynamicUrlInterceptors.changeBaseUrl(kIsWeb ? AppConfig.baseUrl : _urlText);
_authorizationInterceptors.changeAuthorization(_userNameText, _passwordText); _authorizationInterceptors.setBasicAuthorization(_userNameText, _passwordText);
pushAndPop(AppRoutes.SESSION); pushAndPop(AppRoutes.SESSION);
} }
+1 -1
View File
@@ -9,8 +9,8 @@ class MainBindings extends Bindings {
@override @override
Future dependencies() async { Future dependencies() async {
await CoreBindings().dependencies(); await CoreBindings().dependencies();
NetworkBindings().dependencies();
LocalBindings().dependencies(); LocalBindings().dependencies();
NetworkBindings().dependencies();
CredentialBindings().dependencies(); CredentialBindings().dependencies();
SessionBindings().dependencies(); SessionBindings().dependencies();
} }
@@ -9,6 +9,8 @@ import 'package:get/get.dart';
import 'package:jmap_dart_client/http/http_client.dart' as JmapHttpClient; import 'package:jmap_dart_client/http/http_client.dart' as JmapHttpClient;
import 'package:tmail_ui_user/features/composer/data/network/composer_api.dart'; import 'package:tmail_ui_user/features/composer/data/network/composer_api.dart';
import 'package:tmail_ui_user/features/email/data/network/email_api.dart'; import 'package:tmail_ui_user/features/email/data/network/email_api.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/config/authorization_interceptors.dart'; import 'package:tmail_ui_user/features/login/data/network/config/authorization_interceptors.dart';
import 'package:tmail_ui_user/features/login/data/network/oidc_http_client.dart'; import 'package:tmail_ui_user/features/login/data/network/oidc_http_client.dart';
import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_api.dart'; import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_api.dart';
@@ -35,7 +37,20 @@ class NetworkBindings extends Bindings {
void _bindingDio() { void _bindingDio() {
_bindingBaseOption(); _bindingBaseOption();
Get.put(Dio(Get.find<BaseOptions>())); Get.put(Dio(Get.find<BaseOptions>()));
Get.put(DioClient(Get.find<Dio>()));
Get.put(const FlutterAppAuth());
Get.put(OIDCHttpClient(Get.find<DioClient>(), Get.find<FlutterAppAuth>()));
_bindingInterceptors(); _bindingInterceptors();
}
void _bindingInterceptors() {
Get.put(DynamicUrlInterceptors());
Get.put(AuthorizationInterceptors(
Get.find<Dio>(),
Get.find<OIDCHttpClient>(),
Get.find<TokenOidcCacheManager>(),
Get.find<AccountCacheManager>()
));
Get.find<Dio>().interceptors.add(Get.find<DynamicUrlInterceptors>()); Get.find<Dio>().interceptors.add(Get.find<DynamicUrlInterceptors>());
Get.find<Dio>().interceptors.add(Get.find<AuthorizationInterceptors>()); Get.find<Dio>().interceptors.add(Get.find<AuthorizationInterceptors>());
if (kDebugMode) { if (kDebugMode) {
@@ -43,13 +58,7 @@ class NetworkBindings extends Bindings {
} }
} }
void _bindingInterceptors() {
Get.put(DynamicUrlInterceptors());
Get.put(AuthorizationInterceptors());
}
void _bindingApi() { void _bindingApi() {
Get.put(DioClient(Get.find<Dio>()));
Get.put(JmapHttpClient.HttpClient(Get.find<Dio>())); Get.put(JmapHttpClient.HttpClient(Get.find<Dio>()));
Get.put(DownloadClient(Get.find<DioClient>())); Get.put(DownloadClient(Get.find<DioClient>()));
Get.put(DownloadManager(Get.find<DownloadClient>())); Get.put(DownloadManager(Get.find<DownloadClient>()));
@@ -60,8 +69,6 @@ class NetworkBindings extends Bindings {
Get.find<JmapHttpClient.HttpClient>(), Get.find<JmapHttpClient.HttpClient>(),
Get.find<DownloadManager>())); Get.find<DownloadManager>()));
Get.put(ComposerAPI(Get.find<DioClient>())); Get.put(ComposerAPI(Get.find<DioClient>()));
Get.put(const FlutterAppAuth());
Get.put(OIDCHttpClient(Get.find<DioClient>(), Get.find<FlutterAppAuth>()));
} }
void _bindingConnection() { void _bindingConnection() {
+20 -4
View File
@@ -1,17 +1,33 @@
import 'package:core/utils/app_logger.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:model/oidc/token_id.dart'; import 'package:model/oidc/token_id.dart';
class Token extends Equatable { class Token with EquatableMixin {
const Token(this.token, this.tokenId);
final String token; final String token;
final TokenId tokenId; final TokenId tokenId;
final String refreshToken;
final DateTime? expiredTime;
const Token(this.token, this.tokenId, this.refreshToken, {this.expiredTime});
@override @override
List<Object> get props => [token, tokenId]; List<Object?> get props => [token, tokenId, refreshToken, expiredTime];
} }
extension TokenExtension on Token { extension TokenExtension on Token {
bool isTokenValid() => token.isNotEmpty && tokenId.uuid.isNotEmpty; bool isTokenValid() => token.isNotEmpty && tokenId.uuid.isNotEmpty;
}
bool get isExpired {
if (expiredTime != null) {
final now = DateTime.now();
log('TokenExtension::isExpired(): TIME_NOW: $now');
log('TokenExtension::isExpired(): EXPIRED_DATE: $expiredTime');
return expiredTime!.isBefore(now);
}
return false;
}
String get tokenIdHash => tokenId.uuid.hashCode.toString();
}
+3 -5
View File
@@ -17,10 +17,6 @@ class TokenOIDC with EquatableMixin {
{this.expiredTime} {this.expiredTime}
); );
factory TokenOIDC.empty() {
return TokenOIDC('', TokenId(''), '');
}
@override @override
List<Object?> get props => [token, tokenId, expiredTime, refreshToken]; List<Object?> get props => [token, tokenId, expiredTime, refreshToken];
} }
@@ -30,6 +26,8 @@ extension TokenOIDCExtension on TokenOIDC {
bool isTokenValid() => token.isNotEmpty && tokenId.uuid.isNotEmpty; bool isTokenValid() => token.isNotEmpty && tokenId.uuid.isNotEmpty;
Token toToken() { Token toToken() {
return Token(token, tokenId); return Token(token, tokenId, refreshToken, expiredTime: expiredTime);
} }
String get tokenIdHash => tokenId.uuid.hashCode.toString();
} }