TF-606 Implement refresh token when access token expired
This commit is contained in:
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,3 +28,11 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user