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:
@@ -7,6 +7,8 @@ import '../../../../core/models/membre_model.dart';
|
||||
import '../../../../shared/theme/app_theme.dart';
|
||||
import '../../../../shared/widgets/custom_text_field.dart';
|
||||
import '../../../../shared/widgets/buttons/buttons.dart';
|
||||
import '../../../../core/auth/services/permission_service.dart';
|
||||
import '../../../../shared/widgets/permission_widget.dart';
|
||||
import '../bloc/membres_bloc.dart';
|
||||
import '../bloc/membres_event.dart';
|
||||
import '../bloc/membres_state.dart';
|
||||
@@ -25,7 +27,7 @@ class MembreEditPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MembreEditPageState extends State<MembreEditPage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
with SingleTickerProviderStateMixin, PermissionMixin {
|
||||
late MembresBloc _membresBloc;
|
||||
late TabController _tabController;
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
@@ -53,12 +55,22 @@ class _MembreEditPageState extends State<MembreEditPage>
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// Vérification des permissions d'accès
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!permissionService.canEditMembers) {
|
||||
showPermissionError(context, 'Vous n\'avez pas les permissions pour modifier les membres');
|
||||
Navigator.of(context).pop();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
_membresBloc = getIt<MembresBloc>();
|
||||
_tabController = TabController(length: 3, vsync: this);
|
||||
|
||||
|
||||
// Pré-remplir les champs avec les données existantes
|
||||
_populateFields();
|
||||
|
||||
|
||||
// Écouter les changements pour détecter les modifications
|
||||
_setupChangeListeners();
|
||||
}
|
||||
@@ -184,10 +196,12 @@ class _MembreEditPageState extends State<MembreEditPage>
|
||||
),
|
||||
actions: [
|
||||
if (_hasChanges)
|
||||
IconButton(
|
||||
PermissionIconButton(
|
||||
permission: () => permissionService.canEditMembers,
|
||||
icon: const Icon(Icons.save),
|
||||
onPressed: _submitForm,
|
||||
tooltip: 'Sauvegarder',
|
||||
disabledMessage: 'Vous n\'avez pas les permissions pour modifier ce membre',
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.help_outline),
|
||||
@@ -939,6 +953,12 @@ class _MembreEditPageState extends State<MembreEditPage>
|
||||
}
|
||||
|
||||
void _submitForm() {
|
||||
// Vérification des permissions
|
||||
if (!permissionService.canEditMembers) {
|
||||
showPermissionError(context, 'Vous n\'avez pas les permissions pour modifier ce membre');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_formKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
@@ -948,6 +968,12 @@ class _MembreEditPageState extends State<MembreEditPage>
|
||||
return;
|
||||
}
|
||||
|
||||
// Log de l'action pour audit
|
||||
permissionService.logAction('Modification membre', details: {
|
||||
'membreId': widget.membre.id,
|
||||
'nom': '${widget.membre.prenom} ${widget.membre.nom}',
|
||||
});
|
||||
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user