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:
@@ -1,14 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:intl/date_symbol_data_local.dart';
|
||||
|
||||
import 'core/auth/bloc/temp_auth_bloc.dart';
|
||||
import 'core/auth/bloc/auth_event.dart';
|
||||
import 'core/auth/services/temp_auth_service.dart';
|
||||
|
||||
import 'core/auth/presentation/auth_wrapper.dart';
|
||||
import 'core/di/injection.dart';
|
||||
import 'shared/theme/app_theme.dart';
|
||||
import 'app.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
@@ -19,6 +16,8 @@ void main() async {
|
||||
// Configuration de l'injection de dépendances
|
||||
await configureDependencies();
|
||||
|
||||
// Le service d'authentification WebView s'initialise automatiquement
|
||||
|
||||
// Configuration du système
|
||||
await _configureApp();
|
||||
|
||||
@@ -51,38 +50,30 @@ class UnionFlowApp extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider<TempAuthBloc>(
|
||||
create: (context) {
|
||||
final authService = TempAuthService();
|
||||
final authBloc = TempAuthBloc(authService);
|
||||
authBloc.add(const AuthInitializeRequested());
|
||||
return authBloc;
|
||||
return MaterialApp(
|
||||
title: 'UnionFlow',
|
||||
debugShowCheckedModeBanner: false,
|
||||
|
||||
// Configuration du thème
|
||||
theme: AppTheme.lightTheme,
|
||||
darkTheme: AppTheme.darkTheme,
|
||||
themeMode: ThemeMode.system,
|
||||
|
||||
// Configuration de la localisation
|
||||
locale: const Locale('fr', 'FR'),
|
||||
|
||||
// Application principale
|
||||
home: const AuthWrapper(),
|
||||
|
||||
// Builder global pour gérer les erreurs
|
||||
builder: (context, child) {
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaler: const TextScaler.linear(1.0),
|
||||
),
|
||||
child: child ?? const SizedBox(),
|
||||
);
|
||||
},
|
||||
child: MaterialApp(
|
||||
title: 'UnionFlow',
|
||||
debugShowCheckedModeBanner: false,
|
||||
|
||||
// Configuration du thème
|
||||
theme: AppTheme.lightTheme,
|
||||
darkTheme: AppTheme.darkTheme,
|
||||
themeMode: ThemeMode.system,
|
||||
|
||||
// Configuration de la localisation
|
||||
locale: const Locale('fr', 'FR'),
|
||||
|
||||
// Application principale
|
||||
home: const AppWrapper(),
|
||||
|
||||
// Builder global pour gérer les erreurs
|
||||
builder: (context, child) {
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaler: const TextScaler.linear(1.0),
|
||||
),
|
||||
child: child ?? const SizedBox(),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user