Files
kent_logistics_app/lib/services/token_interceptor.dart

131 lines
4.2 KiB
Dart
Raw Normal View History

2025-12-19 10:48:19 +05:30
import 'dart:async';
2025-12-03 11:57:05 +05:30
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
2025-12-19 10:48:19 +05:30
import 'package:shared_preferences/shared_preferences.dart';
import '../config/api_config.dart';
2025-12-03 11:57:05 +05:30
import '../providers/auth_provider.dart';
class TokenInterceptor extends Interceptor {
2025-12-19 10:48:19 +05:30
final AuthProvider authProvider;
2025-12-03 11:57:05 +05:30
final BuildContext context;
final Dio dio;
2025-12-19 10:48:19 +05:30
Completer<bool>? _refreshCompleter;
2025-12-03 11:57:05 +05:30
2025-12-19 10:48:19 +05:30
TokenInterceptor(this.authProvider, this.context, this.dio);
// 🔐 Attach token to every request
2025-12-03 11:57:05 +05:30
@override
2025-12-19 10:48:19 +05:30
void onRequest(
RequestOptions options, RequestInterceptorHandler handler) async {
final prefs = await SharedPreferences.getInstance();
final token = prefs.getString('token');
if (token != null && token.isNotEmpty) {
options.headers['Authorization'] = 'Bearer $token';
debugPrint('🔐🔐🔐🔐🔐🔐 [REQUEST] Token attached → ${options.uri}');
} else {
debugPrint('⚠️⚠️⚠️⚠️⚠️⚠️ [REQUEST] No token found → ${options.uri}');
2025-12-03 11:57:05 +05:30
}
2025-12-19 10:48:19 +05:30
2025-12-03 11:57:05 +05:30
handler.next(options);
}
2025-12-19 10:48:19 +05:30
// 🔄 Handle 401 & refresh token
2025-12-03 11:57:05 +05:30
@override
void onError(DioException err, ErrorInterceptorHandler handler) async {
2025-12-19 10:48:19 +05:30
debugPrint(
'❌❌❌❌❌ [ERROR] ${err.response?.statusCode} on ${err.requestOptions.uri}');
if (err.response?.statusCode == 401) {
debugPrint('🔄🔄🔄🔄🔄🔄🔄 [AUTH] 401 detected, attempting refresh…');
2025-12-03 11:57:05 +05:30
2025-12-19 10:48:19 +05:30
// If refresh already running, wait
if (_refreshCompleter != null) {
debugPrint('⏳⏳⏳⏳⏳⏳⏳⏳⏳ [REFRESH] Waiting for ongoing refresh to complete…');
final success = await _refreshCompleter!.future;
if (success) {
debugPrint('✅✅✅✅✅✅✅✅ [REFRESH] Token refreshed, retrying request');
final prefs = await SharedPreferences.getInstance();
err.requestOptions.headers['Authorization'] =
'Bearer ${prefs.getString('token')}';
final response = await dio.fetch(err.requestOptions);
return handler.resolve(response);
} else {
debugPrint('❌❌❌❌❌❌ [REFRESH] Refresh failed while waiting');
}
}
_refreshCompleter = Completer<bool>();
debugPrint('🚀🚀🚀🚀🚀🚀🚀🚀 [REFRESH] Starting new refresh request');
final refreshed = await _refreshToken();
_refreshCompleter!.complete(refreshed);
_refreshCompleter = null;
2025-12-03 11:57:05 +05:30
if (refreshed) {
2025-12-19 10:48:19 +05:30
debugPrint('✅✅✅✅✅✅✅✅✅ [REFRESH] Refresh successful, retrying original request');
final prefs = await SharedPreferences.getInstance();
err.requestOptions.headers['Authorization'] =
'Bearer ${prefs.getString('token')}';
final response = await dio.fetch(err.requestOptions);
return handler.resolve(response);
2025-12-03 11:57:05 +05:30
}
2025-12-19 10:48:19 +05:30
debugPrint('🚪🚪🚪🚪🚪🚪 [AUTH] Refresh failed → logging out user');
await authProvider.logout(context);
//await authProvider.forceLogout(context);
2025-12-03 11:57:05 +05:30
}
handler.next(err);
}
2025-12-19 10:48:19 +05:30
// 🔁 Call refresh API using SEPARATE Dio
Future<bool> _refreshToken() async {
try {
final prefs = await SharedPreferences.getInstance();
final oldToken = prefs.getString('token');
if (oldToken == null) {
debugPrint('❌❌❌❌❌❌❌ [REFRESH] No old token found');
return false;
}
debugPrint('📤📤📤📤📤 [REFRESH] Calling /auth/refresh');
final refreshDio = Dio(
BaseOptions(
baseUrl: ApiConfig.baseUrl,
headers: {
'Authorization': 'Bearer $oldToken',
'Accept': 'application/json',
},
),
);
final res = await refreshDio.post('/auth/refresh');
if (res.data['success'] == true && res.data['token'] != null) {
await prefs.setString('token', res.data['token']);
debugPrint('💾💾💾💾💾💾💾 [REFRESH] New token saved to SharedPreferences');
return true;
}
debugPrint('❌❌❌❌❌❌ [REFRESH] API responded but refresh not allowed');
return false;
} catch (e) {
debugPrint('🔥🔥🔥🔥🔥🔥 [REFRESH] Exception occurred: $e');
return false;
}
}
}