Files
Holzleitner-Lieferservice-App/lib/data/network/network_locator.dart
Dennis Nemec 6d7e58fc0f 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.
2026-05-14 22:59:36 +02:00

42 lines
1.4 KiB
Dart

import 'package:get_it/get_it.dart';
import 'package:holzleitner_api/holzleitner_api.dart';
import 'auth_token_provider.dart';
import 'backend_config.dart';
import 'holzleitner_api_factory.dart';
import 'keycloak_oidc_token_provider.dart';
/// Registriert das HTTP-/API-Subsystem im globalen GetIt-Locator.
///
/// Aufruf bewusst nicht im AppBloc-Lifecycle, sondern in `main()` vor
/// dem `runApp` — die API-Klassen sind über die gesamte App-Lebensdauer
/// stabil.
///
/// Phase B: produktiver `KeycloakOidcTokenProvider`. Die alte
/// `DevPasswordGrantTokenProvider`-Implementation bleibt im Code (für
/// das reine dart-Smoke-Tool, siehe `tool/smoke_test_api.dart`).
void registerNetworking({
required GetIt locator,
BackendConfig config = BackendConfig.localDev,
}) {
locator.registerSingleton<BackendConfig>(config);
final provider = KeycloakOidcTokenProvider(
config: config,
issuerUrl: config.keycloakIssuerUrl,
redirectUrl: config.keycloakRedirectUrl,
);
// Doppelt registrieren: einmal unter der konkreten Klasse (für
// den AuthBloc, der Login/Logout/Restore aufruft) und einmal hinter
// dem Interface (für den HTTP-Interceptor).
locator.registerSingleton<KeycloakOidcTokenProvider>(provider);
locator.registerSingleton<AuthTokenProvider>(provider);
locator.registerSingleton<HolzleitnerApi>(
buildHolzleitnerApi(
config: config,
tokenProvider: locator<AuthTokenProvider>(),
),
);
}