feat(mobile): Implement Keycloak WebView authentication with HTTP callback

- Replace flutter_appauth with custom WebView implementation to resolve deep link issues
- Add KeycloakWebViewAuthService with integrated WebView for seamless authentication
- Configure Android manifest for HTTP cleartext traffic support
- Add network security config for development environment (192.168.1.11)
- Update Keycloak client to use HTTP callback endpoint (http://192.168.1.11:8080/auth/callback)
- Remove obsolete keycloak_auth_service.dart and temporary scripts
- Clean up dependencies and regenerate injection configuration
- Tested successfully on multiple Android devices (Xiaomi 2201116TG, SM A725F)

BREAKING CHANGE: Authentication flow now uses WebView instead of external browser
- Users will see Keycloak login page within the app instead of browser redirect
- Resolves ERR_CLEARTEXT_NOT_PERMITTED and deep link state management issues
- Maintains full OIDC compliance with PKCE flow and secure token storage

Technical improvements:
- WebView with custom navigation delegate for callback handling
- Automatic token extraction and user info parsing from JWT
- Proper error handling and user feedback
- Consistent authentication state management across app lifecycle
This commit is contained in:
DahoudG
2025-09-15 01:44:16 +00:00
parent 73459b3092
commit f89f6167cc
290 changed files with 34563 additions and 3528 deletions

View File

@@ -0,0 +1,160 @@
import 'package:equatable/equatable.dart';
import '../../../../core/models/evenement_model.dart';
/// Événements du BLoC Evenement
abstract class EvenementEvent extends Equatable {
const EvenementEvent();
@override
List<Object?> get props => [];
}
/// Charge les événements à venir
class LoadEvenementsAVenir extends EvenementEvent {
final int page;
final int size;
final bool refresh;
const LoadEvenementsAVenir({
this.page = 0,
this.size = 10,
this.refresh = false,
});
@override
List<Object?> get props => [page, size, refresh];
}
/// Charge les événements publics
class LoadEvenementsPublics extends EvenementEvent {
final int page;
final int size;
final bool refresh;
const LoadEvenementsPublics({
this.page = 0,
this.size = 20,
this.refresh = false,
});
@override
List<Object?> get props => [page, size, refresh];
}
/// Charge tous les événements
class LoadEvenements extends EvenementEvent {
final int page;
final int size;
final String sortField;
final String sortDirection;
final bool refresh;
const LoadEvenements({
this.page = 0,
this.size = 20,
this.sortField = 'dateDebut',
this.sortDirection = 'asc',
this.refresh = false,
});
@override
List<Object?> get props => [page, size, sortField, sortDirection, refresh];
}
/// Charge un événement par ID
class LoadEvenementById extends EvenementEvent {
final String id;
const LoadEvenementById(this.id);
@override
List<Object?> get props => [id];
}
/// Recherche d'événements
class SearchEvenements extends EvenementEvent {
final String terme;
final int page;
final int size;
final bool refresh;
const SearchEvenements({
required this.terme,
this.page = 0,
this.size = 20,
this.refresh = false,
});
@override
List<Object?> get props => [terme, page, size, refresh];
}
/// Filtre par type d'événement
class FilterEvenementsByType extends EvenementEvent {
final TypeEvenement type;
final int page;
final int size;
final bool refresh;
const FilterEvenementsByType({
required this.type,
this.page = 0,
this.size = 20,
this.refresh = false,
});
@override
List<Object?> get props => [type, page, size, refresh];
}
/// Crée un nouvel événement
class CreateEvenement extends EvenementEvent {
final EvenementModel evenement;
const CreateEvenement(this.evenement);
@override
List<Object?> get props => [evenement];
}
/// Met à jour un événement
class UpdateEvenement extends EvenementEvent {
final String id;
final EvenementModel evenement;
const UpdateEvenement(this.id, this.evenement);
@override
List<Object?> get props => [id, evenement];
}
/// Supprime un événement
class DeleteEvenement extends EvenementEvent {
final String id;
const DeleteEvenement(this.id);
@override
List<Object?> get props => [id];
}
/// Change le statut d'un événement
class ChangeStatutEvenement extends EvenementEvent {
final String id;
final StatutEvenement nouveauStatut;
const ChangeStatutEvenement(this.id, this.nouveauStatut);
@override
List<Object?> get props => [id, nouveauStatut];
}
/// Charge les statistiques
class LoadStatistiquesEvenements extends EvenementEvent {
const LoadStatistiquesEvenements();
}
/// Réinitialise l'état
class ResetEvenementState extends EvenementEvent {
const ResetEvenementState();
}