feat(features): refontes adhesions/admin/auth/backup/contributions/dashboard/epargne/events
- adhesions : bloc complet avec events/states/model, dialogs paiement/rejet - admin : users bloc, user management list/detail pages - authentication : bloc + keycloak auth service + webview - backup : bloc complet, repository, models - contributions : bloc + widgets + export - dashboard : widgets connectés (activities, events, notifications, search) + charts + monitoring + shortcuts - epargne : repository, transactions, dialogs - events : bloc complet, pages (detail, connected, wrapper), models
This commit is contained in:
@@ -167,9 +167,56 @@ class KeycloakAuthService {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Logout : révoque la session SSO côté Keycloak via le back-channel
|
||||
/// (POST /logout silencieux, sans navigateur), puis purge le stockage local.
|
||||
///
|
||||
/// Conforme OIDC RP-Initiated Logout. Ne lève jamais d'exception : la purge
|
||||
/// locale est garantie même si Keycloak est injoignable. Le statut du
|
||||
/// back-channel est tracé dans les logs pour diagnostic.
|
||||
Future<void> logout() async {
|
||||
final refresh = await _storage.read(key: _refreshK);
|
||||
|
||||
if (refresh == null || refresh.isEmpty) {
|
||||
AppLogger.info('KeycloakAuthService: no refresh token, skipping backchannel logout');
|
||||
} else {
|
||||
try {
|
||||
final response = await _dio.post(
|
||||
KeycloakConfig.logoutEndpoint,
|
||||
data: {
|
||||
'client_id': KeycloakConfig.clientId,
|
||||
'refresh_token': refresh,
|
||||
},
|
||||
options: Options(
|
||||
contentType: Headers.formUrlEncodedContentType,
|
||||
// Accepte tout statut < 600 — on interprète nous-mêmes ci-dessous.
|
||||
validateStatus: (_) => true,
|
||||
),
|
||||
);
|
||||
final code = response.statusCode ?? 0;
|
||||
if (code == 200 || code == 204) {
|
||||
AppLogger.info('KeycloakAuthService: SSO session revoked at Keycloak (HTTP $code)');
|
||||
} else if (code == 400) {
|
||||
// Refresh token déjà invalide côté Keycloak → idempotent, OK.
|
||||
AppLogger.info('KeycloakAuthService: refresh token already invalid (HTTP 400) — session considered revoked');
|
||||
} else {
|
||||
AppLogger.error(
|
||||
'KeycloakAuthService: backchannel logout returned HTTP $code — '
|
||||
'SSO session may still be active. Body: ${response.data}',
|
||||
);
|
||||
}
|
||||
} catch (e, st) {
|
||||
AppLogger.error(
|
||||
'KeycloakAuthService: backchannel logout network error — local logout will still proceed',
|
||||
error: e,
|
||||
stackTrace: st,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Purge locale toujours effectuée — l'utilisateur "se sent" déconnecté
|
||||
// immédiatement même si le serveur n'a pas pu être notifié.
|
||||
await _storage.deleteAll();
|
||||
AppLogger.info('KeycloakAuthService: session cleared');
|
||||
AppLogger.info('KeycloakAuthService: local session cleared');
|
||||
}
|
||||
|
||||
Future<void> _saveTokens(Map<String, dynamic> data) async {
|
||||
|
||||
Reference in New Issue
Block a user