aves_mio1/lib/remote/new-boh/auth_client.dart
FabioMich66 507c131502
Some checks are pending
Quality check / Flutter analysis (push) Waiting to run
Quality check / CodeQL analysis (java-kotlin) (push) Waiting to run
ok2
2026-03-07 23:53:27 +01:00

96 lines
No EOL
3 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// lib/remote/auth_client.dart
import 'dart:convert';
import 'package:http/http.dart' as http;
/// Gestisce autenticazione remota e caching del Bearer token.
/// - [baseUrl]: URL base del server (con o senza '/')
/// - [email]/[password]: credenziali
/// - [loginPath]: path dell'endpoint di login (default 'auth/login')
/// - [timeout]: timeout per le richieste (default 20s)
class RemoteAuth {
final Uri base;
final String email;
final String password;
final String loginPath;
final Duration timeout;
String? _token;
RemoteAuth({
required String baseUrl,
required this.email,
required this.password,
this.loginPath = 'auth/login',
this.timeout = const Duration(seconds: 20),
}) : base = Uri.parse(baseUrl.endsWith('/') ? baseUrl : '$baseUrl/');
Uri get _loginUri => base.resolve(loginPath);
/// Esegue il login e memorizza il token.
/// Lancia eccezione con messaggio chiaro in caso di errore HTTP, rete o JSON.
Future<String> login() async {
final uri = _loginUri;
final headers = {'Content-Type': 'application/json'};
final bodyStr = json.encode({'email': email, 'password': password});
http.Response res;
try {
res = await http
.post(uri, headers: headers, body: bodyStr)
.timeout(timeout);
} catch (e) {
throw Exception('Login fallito: errore di rete verso $uri: $e');
}
// Follow esplicito per redirect POST moderni (307/308) mantenendo metodo e body
if ({307, 308}.contains(res.statusCode) && res.headers['location'] != null) {
final redirectUri = uri.resolve(res.headers['location']!);
try {
res = await http
.post(redirectUri, headers: headers, body: bodyStr)
.timeout(timeout);
} catch (e) {
throw Exception('Login fallito: errore di rete verso $redirectUri: $e');
}
}
if (res.statusCode != 200) {
final snippet = utf8.decode(res.bodyBytes.take(200).toList());
throw Exception(
'Login fallito: HTTP ${res.statusCode} ${res.reasonPhrase} $snippet',
);
}
// Parsing JSON robusto
Map<String, dynamic> map;
try {
map = json.decode(utf8.decode(res.bodyBytes)) as Map<String, dynamic>;
} catch (_) {
throw Exception('Login fallito: risposta non è un JSON valido');
}
// Supporto sia 'token' sia 'access_token'
final token = (map['token'] ?? map['access_token']) as String?;
if (token == null || token.isEmpty) {
throw Exception('Login fallito: token assente nella risposta');
}
_token = token;
return token;
}
/// Ritorna gli header con Bearer; se non hai token, esegue login.
Future<Map<String, String>> authHeaders() async {
_token ??= await login();
return {'Authorization': 'Bearer $_token'};
}
/// Forza il rinnovo del token (es. dopo 401) e ritorna i nuovi header.
Future<Map<String, String>> refreshAndHeaders() async {
_token = null;
return await authHeaders();
}
/// Accesso in sola lettura al token corrente (può essere null).
String? get token => _token;
}