didvan-app/lib/services/auth/auth_interceptor.dart

49 lines
2.2 KiB
Dart

// lib/services/auth/auth_interceptor.dart
//
// یک wrapper کوچک که قبل/بعد از هر درخواست API:
// - مطمئن می‌شود `RequestService.token` با access token جاری همگام است.
// - اگر access token در آستانه‌ی انقضا است، قبل از درخواست refresh می‌کند.
// - در صورت دریافت 401 برای یک درخواست، یک‌بار refresh کرده و درخواست را
// مجددا اجرا می‌کند.
//
// این فایل عمدا lightweight است و به ساختار فعلی RequestService وابسته است
// تا کمترین تغییر در سرویس‌های دیگر اعمال شود.
import 'package:didvan/services/auth/keycloak_auth_service.dart';
import 'package:didvan/services/auth/token_storage.dart';
import 'package:didvan/services/network/request.dart';
class AuthInterceptor {
AuthInterceptor._();
/// قبل از هر درخواست شبکه‌ی نیازمند احراز هویت اجرا می‌شود.
///
/// اگر access token در دسترس نیست یا نزدیک به انقضاست، تلاش می‌کنیم
/// با refresh token تمدید کنیم.
static Future<void> ensureFreshToken() async {
if (TokenStorage.isAccessTokenValid) {
// فقط RequestService.token را sync می‌کنیم.
RequestService.token = TokenStorage.accessToken;
return;
}
// ignore: avoid_print
print('🔐 ensureFreshToken: access invalid -> attempting refresh '
'(hasRefresh=${TokenStorage.refreshToken != null})');
if (TokenStorage.refreshToken != null) {
await KeycloakAuthService.instance.refresh();
}
RequestService.token = TokenStorage.accessToken;
}
/// در صورت دریافت 401، یک‌بار تلاش به refresh می‌کنیم.
/// اگر موفق شد true برمی‌گرداند تا فراخواننده درخواست را retry کند.
static Future<bool> handleUnauthorized() async {
if (TokenStorage.refreshToken == null) return false;
final ok = await KeycloakAuthService.instance.refresh();
if (ok) {
RequestService.token = TokenStorage.accessToken;
}
return ok;
}
}