140 lines
4.2 KiB
Dart
140 lines
4.2 KiB
Dart
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:equatable/equatable.dart';
|
|
import 'package:injectable/injectable.dart';
|
|
import '../../data/models/user.dart';
|
|
import '../../data/models/user_role.dart';
|
|
import '../../data/datasources/keycloak_auth_service.dart';
|
|
import '../../data/datasources/permission_engine.dart';
|
|
import '../../../../core/storage/dashboard_cache_manager.dart';
|
|
|
|
// === ÉVÉNEMENTS ===
|
|
abstract class AuthEvent extends Equatable {
|
|
const AuthEvent();
|
|
@override
|
|
List<Object?> get props => [];
|
|
}
|
|
|
|
class AuthLoginRequested extends AuthEvent {
|
|
final String email;
|
|
final String password;
|
|
const AuthLoginRequested(this.email, this.password);
|
|
@override
|
|
List<Object?> get props => [email, password];
|
|
}
|
|
|
|
class AuthLogoutRequested extends AuthEvent { const AuthLogoutRequested(); }
|
|
class AuthStatusChecked extends AuthEvent { const AuthStatusChecked(); }
|
|
class AuthTokenRefreshRequested extends AuthEvent { const AuthTokenRefreshRequested(); }
|
|
|
|
// === ÉTATS ===
|
|
abstract class AuthState extends Equatable {
|
|
const AuthState();
|
|
@override
|
|
List<Object?> get props => [];
|
|
}
|
|
|
|
class AuthInitial extends AuthState {}
|
|
class AuthLoading extends AuthState {}
|
|
class AuthUnauthenticated extends AuthState {}
|
|
|
|
class AuthAuthenticated extends AuthState {
|
|
final User user;
|
|
final UserRole effectiveRole;
|
|
final List<String> effectivePermissions;
|
|
final String accessToken;
|
|
|
|
const AuthAuthenticated({
|
|
required this.user,
|
|
required this.effectiveRole,
|
|
required this.effectivePermissions,
|
|
required this.accessToken,
|
|
});
|
|
|
|
@override
|
|
List<Object?> get props => [user, effectiveRole, effectivePermissions, accessToken];
|
|
}
|
|
|
|
class AuthError extends AuthState {
|
|
final String message;
|
|
const AuthError(this.message);
|
|
@override
|
|
List<Object?> get props => [message];
|
|
}
|
|
|
|
// === BLOC ===
|
|
@lazySingleton
|
|
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|
final KeycloakAuthService _authService;
|
|
|
|
AuthBloc(this._authService) : super(AuthInitial()) {
|
|
on<AuthLoginRequested>(_onLoginRequested);
|
|
on<AuthLogoutRequested>(_onLogoutRequested);
|
|
on<AuthStatusChecked>(_onStatusChecked);
|
|
on<AuthTokenRefreshRequested>(_onTokenRefreshRequested);
|
|
}
|
|
|
|
Future<void> _onLoginRequested(AuthLoginRequested event, Emitter<AuthState> emit) async {
|
|
emit(AuthLoading());
|
|
try {
|
|
final user = await _authService.login(event.email, event.password);
|
|
if (user != null) {
|
|
final permissions = await PermissionEngine.getEffectivePermissions(user);
|
|
final token = await _authService.getValidToken();
|
|
await DashboardCacheManager.invalidateForRole(user.primaryRole);
|
|
|
|
emit(AuthAuthenticated(
|
|
user: user,
|
|
effectiveRole: user.primaryRole,
|
|
effectivePermissions: permissions,
|
|
accessToken: token ?? '',
|
|
));
|
|
} else {
|
|
emit(const AuthError('Identifiants incorrects.'));
|
|
}
|
|
} catch (e) {
|
|
emit(AuthError('Erreur de connexion: $e'));
|
|
}
|
|
}
|
|
|
|
Future<void> _onLogoutRequested(AuthLogoutRequested event, Emitter<AuthState> emit) async {
|
|
emit(AuthLoading());
|
|
await _authService.logout();
|
|
await DashboardCacheManager.clear();
|
|
emit(AuthUnauthenticated());
|
|
}
|
|
|
|
Future<void> _onStatusChecked(AuthStatusChecked event, Emitter<AuthState> emit) async {
|
|
final tokenValid = await _authService.getValidToken();
|
|
final isAuth = tokenValid != null;
|
|
if (!isAuth) {
|
|
emit(AuthUnauthenticated());
|
|
return;
|
|
}
|
|
final user = await _authService.getCurrentUser();
|
|
if (user == null) {
|
|
emit(AuthUnauthenticated());
|
|
return;
|
|
}
|
|
final permissions = await PermissionEngine.getEffectivePermissions(user);
|
|
final token = await _authService.getValidToken();
|
|
emit(AuthAuthenticated(
|
|
user: user,
|
|
effectiveRole: user.primaryRole,
|
|
effectivePermissions: permissions,
|
|
accessToken: token ?? '',
|
|
));
|
|
}
|
|
|
|
Future<void> _onTokenRefreshRequested(AuthTokenRefreshRequested event, Emitter<AuthState> emit) async {
|
|
if (state is AuthAuthenticated) {
|
|
final newToken = await _authService.refreshToken();
|
|
final success = newToken != null;
|
|
if (success) {
|
|
add(AuthStatusChecked());
|
|
} else {
|
|
add(AuthLogoutRequested());
|
|
}
|
|
}
|
|
}
|
|
}
|