4.8 KiB
4.8 KiB
Slip It In – Architektur-Updates (Phase 2b & 3b)
Dieses Dokument fasst die Sicherheits- und Stabilitäts-Erweiterungen zusammen, die dem ProjectPlan.md hinzugefügt wurden.
🔒 Backend-Sicherheit (Phase 2b)
1. JWT-Claims Validation im GameHub
- Problem: Clients könnten falsche PlayerId-Claims senden (Spoofing)
- Lösung:
GetAuthenticatedUserId()extrahiert User-ID aus JWT-Claims - Implementierung: Jede Hub-Methode validiert
Context.User?.FindFirst(ClaimTypes.NameIdentifier)
2. IDbContextFactory statt Scoped DbContext
- Problem: Bei parallelen SignalR-Aufrufen kann es zu Race Conditions kommen
- Lösung:
IDbContextFactory<SlipItInDbContext>erzeugt isolierte Sessions pro Aufruf - Vorteil: Phrase-Transfer ist thread-safe, keine Conflicts bei 2 gleichzeitigen Challenges
3. Serverseitige Validierung
- Regel: Clients senden nur "Ich möchte X machen", Server prüft ALLES
- Beispiel:
SubmitSlipAsync()prüft auf dem Server:- ✅ Gehört die Phrase dem Spieler?
- ✅ Ist die Runde aktiv?
- ✅ Ist der Spieler noch im Spiel?
4. Daten-Isolation (GameStateDto vs. PlayerHandDto)
- GameStateDto: Öffentliche Daten (Username, Score, CardCount) → für ALLE sichtbar
- PlayerHandDto: Private Daten (Text der eigenen Karten) → nur für den Spieler selbst
- Ergebnis: Gegner sehen nicht, welche Phrasen ich habe!
📱 Client-Stabilität (Phase 3b)
1. WeakReferenceMessenger für Event-Entkopplung
- Problem: Services rufen ViewModels direkt auf → Memory Leaks wenn VM disposed
- Lösung: Services senden Messages via
WeakReferenceMessenger.Default.Send() - Vorteil: ViewModels können sich abmelden ohne zirkuläre Abhängigkeiten
Beispiel:
// Service sendet Event
WeakReferenceMessenger.Default.Send(new GameStateChangedMessage(newState));
// ViewModel empfängt (mit auto-cleanup beim Dispose)
WeakReferenceMessenger.Default.Register<GameStateChangedMessage>(this, (r, m) =>
{
CurrentGameState = m.Value;
});
2. Automatischer Reconnect
- Strategie: Exponential Backoff (0s → 2s → 10s → 30s)
- Pufferung: Offline-Aktionen werden in lokale Queue geschrieben
- Resync: Nach Reconnect wird
ResyncAsync()aufgerufen
Flow:
- SignalR-Verbindung getrennt
- Client speichert "Slip zu Phrase X" in lokale Queue
- Nach 2s Automatischer Reconnect-Versuch
- Nach erfolgreichem Reconnect: Queued Actions werden abgesendet
3. State Restoration
- App-Pause:
GameStateServicespeichert aktuellen State inSecureStorage - App-Resume:
ResyncAsync()wird aufgerufen- ✅ Holt aktuellen GameState vom Server
- ✅ Sendet gepufferte Offline-Aktionen erneut
- ✅ UI zeigt "Syncing..." bis fertig
4. Dual-Layer Storage
- In-Memory Layer:
GameStateServicehalten aktuellen State - Persistent Layer:
SecureStorage/Preferencesspeichern Backup - Fehler-Handling: Nach App-Crash kann State aus Persistent Layer wiederhergestellt werden
📊 Schnellreferenz: Neue Components
Backend
GameHub
├─ GetAuthenticatedUserId() → JWT-Validierung
├─ ValidatePlayerAccessAsync() → Authorization Check
└─ Alle Methoden nutzen IDbContextFactory
Program.cs
├─ AddDbContextFactory<SlipItInDbContext>()
├─ AddAuthentication(JwtBearerDefaults)
└─ AddSignalR() mit JWT-Filter
DTOs
├─ GameStateDto (öffentlich)
├─ PlayerHandDto (privat)
└─ Keine CardText in GameStateDto!
Client
GameStateService
├─ CurrentGameState (in-memory)
├─ CurrentPlayerHand (in-memory)
├─ UpdateGameStateAsync() → speichert + sendet Message
└─ ResyncAsync() → bei App-Resume
SignalRService
├─ ConnectAsync(token) mit Auto-Reconnect
├─ RequestGameStateAsync()
└─ On<> Handler senden Messages
Messages (WeakReferenceMessenger)
├─ GameStateChangedMessage
├─ PlayerHandChangedMessage
└─ ChallengeReceivedMessage
🧪 Wichtigste Tests
| Test | Ziel |
|---|---|
| JWT-Auth | Hub lehnt Requests ohne gültiges Token ab |
| Player-Access | User A kann nicht auf Players von User B zugreifen |
| Race Condition | Phrase-Transfer ist thread-safe bei 2 gleichzeitigen Challenges |
| Offline-Queue | Aktionen während Netzwerk-Ausfall werden gepuffert und später gesendet |
| Memory Leaks | Keine Leaks wenn ViewModels disposed werden (WeakReference) |
| State-Sync | App-Resume synct korrekt mit Server-State |
🚀 Implementierungs-Reihenfolge
- Backend zuerst: JWT-Auth + IDbContextFactory konfigurieren
- GameService erweitern: Serverseitige Validierung in alle Methoden
- Client-Services: GameStateService + SignalRService implementieren
- Messaging: WeakReferenceMessenger in ViewModels integrieren
- Tests: Integrationstest-Suite schreiben
- UI: Views an neue Message-Events binden