AgendaTasks/lib/features/auth/data/datasources/auth_local_datasource.dart
m3mo d8164be49a Add user authentication to Flutter frontend
- Create auth feature with Clean Architecture (domain/data/presentation)
- Add login and register pages with form validation
- Implement secure token storage with flutter_secure_storage
- Create AuthenticatedClient for automatic Bearer token headers
- Add AuthViewModel for global auth state management
- Update router with auth guards (redirect to login if not authenticated)
- Add logout option to settings page
- Update TaskRemoteDataSource to use authenticated client
- Add auth-related localization strings (EN/DE)
2026-02-02 22:58:07 +01:00

104 lines
2.8 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import '../models/token_model.dart';
import '../models/user_model.dart';
abstract class AuthLocalDataSource {
Future<void> saveTokens(TokenModel tokens);
Future<TokenModel?> getTokens();
Future<void> deleteTokens();
Future<void> saveUser(UserModel user);
Future<UserModel?> getUser();
Future<void> deleteUser();
Future<void> clearAll();
Stream<bool> get authStateChanges;
void notifyAuthStateChanged(bool isAuthenticated);
}
class AuthLocalDataSourceImpl implements AuthLocalDataSource {
final FlutterSecureStorage _storage;
final _authStateController = StreamController<bool>.broadcast();
static const String _accessTokenKey = 'access_token';
static const String _refreshTokenKey = 'refresh_token';
static const String _tokenTypeKey = 'token_type';
static const String _userKey = 'current_user';
AuthLocalDataSourceImpl({required FlutterSecureStorage storage})
: _storage = storage;
@override
Future<void> saveTokens(TokenModel tokens) async {
await Future.wait([
_storage.write(key: _accessTokenKey, value: tokens.accessToken),
_storage.write(key: _refreshTokenKey, value: tokens.refreshToken),
_storage.write(key: _tokenTypeKey, value: tokens.tokenType),
]);
}
@override
Future<TokenModel?> getTokens() async {
final accessToken = await _storage.read(key: _accessTokenKey);
final refreshToken = await _storage.read(key: _refreshTokenKey);
final tokenType = await _storage.read(key: _tokenTypeKey);
if (accessToken == null || refreshToken == null) {
return null;
}
return TokenModel(
accessToken: accessToken,
refreshToken: refreshToken,
tokenType: tokenType ?? 'bearer',
);
}
@override
Future<void> deleteTokens() async {
await Future.wait([
_storage.delete(key: _accessTokenKey),
_storage.delete(key: _refreshTokenKey),
_storage.delete(key: _tokenTypeKey),
]);
}
@override
Future<void> saveUser(UserModel user) async {
await _storage.write(key: _userKey, value: json.encode(user.toJson()));
}
@override
Future<UserModel?> getUser() async {
final userJson = await _storage.read(key: _userKey);
if (userJson == null) {
return null;
}
return UserModel.fromJson(json.decode(userJson));
}
@override
Future<void> deleteUser() async {
await _storage.delete(key: _userKey);
}
@override
Future<void> clearAll() async {
await Future.wait([
deleteTokens(),
deleteUser(),
]);
notifyAuthStateChanged(false);
}
@override
Stream<bool> get authStateChanges => _authStateController.stream;
@override
void notifyAuthStateChanged(bool isAuthenticated) {
_authStateController.add(isAuthenticated);
}
}