Phase B: Keycloak OIDC (PKCE) statt Cookie-Session-Login
App-Code: - KeycloakOidcTokenProvider: PKCE-Login via flutter_appauth, Refresh via Refresh-Token aus flutter_secure_storage, Session-Restore beim App-Start, Logout. - AuthSessionEvent als Provider→Bloc-Brücke (LoggedIn/LoggedOut/ SessionExpired) auf einem Broadcast-Stream. - AuthBloc komplett umgebaut: nimmt jetzt den KeycloakOidcTokenProvider statt UserInfoService, mappt eingehende Provider-Events auf eigene Zustände. Authenticated.fromClaims() liest personalnummer + Name aus dem ID-Token-Payload. - LoginPage: kein Browser+Deep-Link mehr — Button feuert LoginRequested, der Provider übernimmt den restlichen Flow. - network_locator: produktiver KeycloakOidcTokenProvider, doppelt registriert (KeycloakOidcTokenProvider für AuthBloc, AuthTokenProvider für Interceptor). - Auth-State trägt zusätzlich personalnummer/displayName/email; das Legacy-User-Objekt + sessionId bleiben temporär drin, damit die alten ERPframe-Services (Phase D) noch kompilieren. Plattform-Setup: - Android: appAuthRedirectScheme=holzleitner in build.gradle.kts, NetworkSecurityConfig erlaubt HTTP zu localhost/10.0.2.2/127.0.0.1. - iOS: holzleitner als URL-Scheme im Info.plist, ATS-Ausnahme für localhost (HTTP-Keycloak im Dev-Setup). Out of scope: - Keine echte App-Run-Smoke — kommt mit dem User-Test. - iOS-pod-install läuft beim ersten 'flutter run ios' automatisch. - Old ERPframe-Services bleiben aktiv und werfen ab jetzt 401 (kein Cookie-Session-Token mehr) — wird in Phase D entfernt.
This commit is contained in:
26
lib/data/network/auth_session_event.dart
Normal file
26
lib/data/network/auth_session_event.dart
Normal file
@ -0,0 +1,26 @@
|
||||
/// Events, die der `KeycloakOidcTokenProvider` über seinen
|
||||
/// Broadcast-Stream auswirft. Der AuthBloc abonniert diesen Stream
|
||||
/// und reagiert mit eigenen Zustands-Übergängen.
|
||||
///
|
||||
/// Bewusst eigene Events (statt direkter Bloc-Aufrufe), damit der
|
||||
/// Token-Provider keine Abhängigkeit auf die Bloc-Schicht braucht.
|
||||
sealed class AuthSessionEvent {
|
||||
const AuthSessionEvent();
|
||||
}
|
||||
|
||||
/// Erfolgreicher Login (frisch oder restauriert).
|
||||
final class AuthLoggedIn extends AuthSessionEvent {
|
||||
const AuthLoggedIn(this.claims);
|
||||
final Map<String, dynamic> claims;
|
||||
}
|
||||
|
||||
/// Sauberer Logout durch den Nutzer.
|
||||
final class AuthLoggedOut extends AuthSessionEvent {
|
||||
const AuthLoggedOut();
|
||||
}
|
||||
|
||||
/// Refresh fehlgeschlagen oder Server lehnt Token ab — die App muss
|
||||
/// zurück zur Login-Page.
|
||||
final class AuthSessionExpired extends AuthSessionEvent {
|
||||
const AuthSessionExpired();
|
||||
}
|
||||
Reference in New Issue
Block a user