⚡ Optimized refresh credentials
This commit is contained in:
parent
22ee817676
commit
75c753ef63
@ -56,10 +56,10 @@ class AccountProvider extends GetxController {
|
|||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
await auth.ensureCredentials();
|
await auth.ensureCredentials();
|
||||||
|
|
||||||
if (globalCredentials == null) await auth.loadCredentials();
|
if (auth.credentials == null) await auth.loadCredentials();
|
||||||
|
|
||||||
final uri = Uri.parse(
|
final uri = Uri.parse(
|
||||||
'${ServiceFinder.services['passport']}/api/ws?tk=${globalCredentials!.accessToken}'
|
'${ServiceFinder.services['passport']}/api/ws?tk=${auth.credentials!.accessToken}'
|
||||||
.replaceFirst('http', 'ws'),
|
.replaceFirst('http', 'ws'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:get/get_connect/http/src/request/request.dart';
|
import 'package:get/get_connect/http/src/request/request.dart';
|
||||||
|
import 'package:mutex/mutex.dart';
|
||||||
import 'package:solian/controllers/chat_events_controller.dart';
|
import 'package:solian/controllers/chat_events_controller.dart';
|
||||||
import 'package:solian/providers/account.dart';
|
import 'package:solian/providers/account.dart';
|
||||||
import 'package:solian/providers/chat.dart';
|
import 'package:solian/providers/chat.dart';
|
||||||
@ -39,8 +40,6 @@ class TokenSet {
|
|||||||
bool get isExpired => expiredAt?.isBefore(DateTime.now()) ?? true;
|
bool get isExpired => expiredAt?.isBefore(DateTime.now()) ?? true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenSet? globalCredentials;
|
|
||||||
|
|
||||||
class RiskyAuthenticateException implements Exception {
|
class RiskyAuthenticateException implements Exception {
|
||||||
final int ticketId;
|
final int ticketId;
|
||||||
|
|
||||||
@ -56,6 +55,9 @@ class AuthProvider extends GetConnect {
|
|||||||
|
|
||||||
static const storage = FlutterSecureStorage();
|
static const storage = FlutterSecureStorage();
|
||||||
|
|
||||||
|
TokenSet? credentials;
|
||||||
|
Mutex credentialsRefreshMutex = Mutex();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
httpClient.baseUrl = ServiceFinder.services['passport'];
|
httpClient.baseUrl = ServiceFinder.services['passport'];
|
||||||
@ -63,28 +65,36 @@ class AuthProvider extends GetConnect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> refreshCredentials() async {
|
Future<void> refreshCredentials() async {
|
||||||
final resp = await post('/api/auth/token', {
|
try {
|
||||||
'refresh_token': globalCredentials!.refreshToken,
|
credentialsRefreshMutex.acquire();
|
||||||
'grant_type': 'refresh_token',
|
if (!credentials!.isExpired) return;
|
||||||
});
|
final resp = await post('/api/auth/token', {
|
||||||
if (resp.statusCode != 200) {
|
'refresh_token': credentials!.refreshToken,
|
||||||
throw Exception(resp.bodyString);
|
'grant_type': 'refresh_token',
|
||||||
|
});
|
||||||
|
if (resp.statusCode != 200) {
|
||||||
|
throw Exception(resp.bodyString);
|
||||||
|
}
|
||||||
|
credentials = TokenSet(
|
||||||
|
accessToken: resp.body['access_token'],
|
||||||
|
refreshToken: resp.body['refresh_token'],
|
||||||
|
expiredAt: DateTime.now().add(const Duration(minutes: 3)),
|
||||||
|
);
|
||||||
|
storage.write(
|
||||||
|
key: 'auth_credentials',
|
||||||
|
value: jsonEncode(credentials!.toJson()),
|
||||||
|
);
|
||||||
|
} catch (_) {
|
||||||
|
rethrow;
|
||||||
|
} finally {
|
||||||
|
credentialsRefreshMutex.release();
|
||||||
}
|
}
|
||||||
globalCredentials = TokenSet(
|
|
||||||
accessToken: resp.body['access_token'],
|
|
||||||
refreshToken: resp.body['refresh_token'],
|
|
||||||
expiredAt: DateTime.now().add(const Duration(minutes: 3)),
|
|
||||||
);
|
|
||||||
storage.write(
|
|
||||||
key: 'auth_credentials',
|
|
||||||
value: jsonEncode(globalCredentials!.toJson()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Request<T?>> requestAuthenticator<T>(Request<T?> request) async {
|
Future<Request<T?>> requestAuthenticator<T>(Request<T?> request) async {
|
||||||
try {
|
try {
|
||||||
await ensureCredentials();
|
await ensureCredentials();
|
||||||
request.headers['Authorization'] = 'Bearer ${globalCredentials!.accessToken}';
|
request.headers['Authorization'] = 'Bearer ${credentials!.accessToken}';
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
@ -108,9 +118,9 @@ class AuthProvider extends GetConnect {
|
|||||||
|
|
||||||
Future<void> ensureCredentials() async {
|
Future<void> ensureCredentials() async {
|
||||||
if (!await isAuthorized) throw Exception('unauthorized');
|
if (!await isAuthorized) throw Exception('unauthorized');
|
||||||
if (globalCredentials == null) await loadCredentials();
|
if (credentials == null) await loadCredentials();
|
||||||
|
|
||||||
if (globalCredentials!.isExpired) {
|
if (credentials!.isExpired) {
|
||||||
await refreshCredentials();
|
await refreshCredentials();
|
||||||
log('Refreshed credentials at ${DateTime.now()}');
|
log('Refreshed credentials at ${DateTime.now()}');
|
||||||
}
|
}
|
||||||
@ -119,7 +129,7 @@ class AuthProvider extends GetConnect {
|
|||||||
Future<void> loadCredentials() async {
|
Future<void> loadCredentials() async {
|
||||||
if (await isAuthorized) {
|
if (await isAuthorized) {
|
||||||
final content = await storage.read(key: 'auth_credentials');
|
final content = await storage.read(key: 'auth_credentials');
|
||||||
globalCredentials = TokenSet.fromJson(jsonDecode(content!));
|
credentials = TokenSet.fromJson(jsonDecode(content!));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +162,7 @@ class AuthProvider extends GetConnect {
|
|||||||
throw Exception(tokenResp.bodyString);
|
throw Exception(tokenResp.bodyString);
|
||||||
}
|
}
|
||||||
|
|
||||||
globalCredentials = TokenSet(
|
credentials = TokenSet(
|
||||||
accessToken: tokenResp.body['access_token'],
|
accessToken: tokenResp.body['access_token'],
|
||||||
refreshToken: tokenResp.body['refresh_token'],
|
refreshToken: tokenResp.body['refresh_token'],
|
||||||
expiredAt: DateTime.now().add(const Duration(minutes: 3)),
|
expiredAt: DateTime.now().add(const Duration(minutes: 3)),
|
||||||
@ -160,14 +170,14 @@ class AuthProvider extends GetConnect {
|
|||||||
|
|
||||||
storage.write(
|
storage.write(
|
||||||
key: 'auth_credentials',
|
key: 'auth_credentials',
|
||||||
value: jsonEncode(globalCredentials!.toJson()),
|
value: jsonEncode(credentials!.toJson()),
|
||||||
);
|
);
|
||||||
|
|
||||||
Get.find<AccountProvider>().connect();
|
Get.find<AccountProvider>().connect();
|
||||||
Get.find<AccountProvider>().notifyPrefetch();
|
Get.find<AccountProvider>().notifyPrefetch();
|
||||||
Get.find<ChatProvider>().connect();
|
Get.find<ChatProvider>().connect();
|
||||||
|
|
||||||
return globalCredentials!;
|
return credentials!;
|
||||||
}
|
}
|
||||||
|
|
||||||
void signout() {
|
void signout() {
|
||||||
|
@ -26,10 +26,10 @@ class ChatProvider extends GetxController {
|
|||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
await auth.ensureCredentials();
|
await auth.ensureCredentials();
|
||||||
|
|
||||||
if (globalCredentials == null) await auth.loadCredentials();
|
if (auth.credentials == null) await auth.loadCredentials();
|
||||||
|
|
||||||
final uri = Uri.parse(
|
final uri = Uri.parse(
|
||||||
'${ServiceFinder.services['messaging']}/api/ws?tk=${globalCredentials!.accessToken}'
|
'${ServiceFinder.services['messaging']}/api/ws?tk=${auth.credentials!.accessToken}'
|
||||||
.replaceFirst('http', 'ws'),
|
.replaceFirst('http', 'ws'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1008,6 +1008,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "1.0.5"
|
||||||
|
mutex:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: mutex
|
||||||
|
sha256: "8827da25de792088eb33e572115a5eb0d61d61a3c01acbc8bcbe76ed78f1a1f2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0"
|
||||||
nm:
|
nm:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -53,6 +53,7 @@ dependencies:
|
|||||||
media_kit_video: ^1.2.4
|
media_kit_video: ^1.2.4
|
||||||
media_kit_libs_video: ^1.0.4
|
media_kit_libs_video: ^1.0.4
|
||||||
textfield_tags: ^3.0.1
|
textfield_tags: ^3.0.1
|
||||||
|
mutex: ^3.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
Reference in New Issue
Block a user