50fe9a9d36
App móvil para validar pases QR contra base-admin-web con login Cognito, escáner en tiempo real, feedback auditivo/háptico y README completo.
104 lines
2.9 KiB
Dart
104 lines
2.9 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:qrscanner/config/api_config.dart';
|
|
import 'package:qrscanner/models/auth_session.dart';
|
|
import 'package:qrscanner/models/login_response.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
class AuthService {
|
|
static const _sessionKey = 'auth_session';
|
|
|
|
AuthSession? _currentSession;
|
|
|
|
AuthSession? get currentSession => _currentSession;
|
|
|
|
Future<LoginResponse> login({
|
|
required String username,
|
|
required String password,
|
|
bool rememberMe = false,
|
|
}) async {
|
|
final response = await http.post(
|
|
Uri.parse(ApiConfig.loginUrl),
|
|
headers: const {'Content-Type': 'application/json'},
|
|
body: jsonEncode({
|
|
'username': username,
|
|
'password': password,
|
|
}),
|
|
);
|
|
|
|
final Map<String, dynamic> body =
|
|
jsonDecode(response.body) as Map<String, dynamic>;
|
|
final loginResponse = LoginResponse.fromJson(body);
|
|
|
|
final accessToken = loginResponse.accessToken?.trim();
|
|
if (response.statusCode == 200 &&
|
|
loginResponse.success &&
|
|
accessToken != null &&
|
|
accessToken.isNotEmpty) {
|
|
final session = AuthSession.fromLoginResponse(
|
|
loginResponse.copyWith(
|
|
username: loginResponse.username ?? username,
|
|
accessToken: accessToken,
|
|
),
|
|
);
|
|
|
|
if (!session.isScanner) {
|
|
_currentSession = null;
|
|
await _clearStoredSession();
|
|
return const LoginResponse(
|
|
success: false,
|
|
message: 'El usuario no tiene permisos para escanear.',
|
|
);
|
|
}
|
|
|
|
_currentSession = session;
|
|
|
|
if (rememberMe) {
|
|
await _saveSession(session);
|
|
} else {
|
|
await _clearStoredSession();
|
|
}
|
|
|
|
return loginResponse.copyWith(accessToken: accessToken);
|
|
}
|
|
|
|
return LoginResponse(
|
|
success: false,
|
|
message: loginResponse.message ??
|
|
'No se pudo iniciar sesión (${response.statusCode})',
|
|
);
|
|
}
|
|
|
|
Future<void> _saveSession(AuthSession session) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setString(_sessionKey, jsonEncode(session.toJson()));
|
|
}
|
|
|
|
Future<void> _clearStoredSession() async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.remove(_sessionKey);
|
|
}
|
|
|
|
Future<void> clearSession() async {
|
|
_currentSession = null;
|
|
await _clearStoredSession();
|
|
}
|
|
|
|
Future<AuthSession?> loadStoredSession() async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final raw = prefs.getString(_sessionKey);
|
|
if (raw == null || raw.isEmpty) return null;
|
|
|
|
final session = AuthSession.fromJson(
|
|
jsonDecode(raw) as Map<String, dynamic>,
|
|
);
|
|
_currentSession = session;
|
|
return session;
|
|
}
|
|
|
|
Future<bool> hasStoredSession() async {
|
|
final session = await loadStoredSession();
|
|
return session != null && session.accessToken.isNotEmpty;
|
|
}
|
|
} |