2013-04-08 16 views
6

Sto costruendo da a previous discussion I had with Jon Skeet.Perché non posso fidarmi di un GUID generato dal client? Trattare il PK come un composito di client-GUID e un GUID del server risolve qualcosa?

Il nocciolo del mio scenario è il seguente:

  • applicazione client ha la capacità di creare nuovi oggetti 'PlaylistItem' che devono essere persistito in una banca dati.
  • Il caso di utilizzo richiede che l'elemento Playlist venga creato in modo tale che il client non debba attendere una risposta dal server prima di visualizzare l'oggetto Playlist.
  • Il client genera un UUID per PlaylistItem, mostra l'oggetto Playlist nel client e quindi emette un comando di salvataggio sul server.

A questo punto, capisco che sarebbe una cattiva pratica utilizzare l'UUID generato dal client come PK dell'oggetto nel mio database. La ragione di ciò è che un utente malintenzionato potrebbe modificare l'UUID generato e forzare le collisioni PK sul mio DB.

Per mitigare eventuali danni che si sarebbero verificati dal forzare una collisione PK su PlaylistItem, ho scelto di definire il PK come un composto di due ID: l'UUID generato dal client e un GUID generato dal server. Il GUID generato dal server è l'ID della playlist di PlaylistItem.

Ora, ho utilizzato questa soluzione per un po ', ma non capisco perché/credo che la mia soluzione sia meglio che semplicemente affidarsi all'ID client. Se l'utente è in grado di forzare una collisione PK con oggetti PlaylistItem di un altro utente, penso che dovrei presumere che potrebbero fornire anche l'ID della playlist dell'utente. Potrebbero ancora forzare le collisioni.

Quindi ... sì. Qual è il modo corretto di fare qualcosa del genere? Permetti al client di creare un UUID, il server dà un pollice su/giù quando viene salvato con successo. Se viene trovata una collisione, ripristinare le modifiche del client e la notifica di collision rilevata?

risposta

2

Una bella soluzione sarebbe la seguente: Per citare di "Building Microservices" Sam Newman:

Il sistema di chiamata sarebbe inviare un BatchRequest, forse passando in una posizione cui un file può essere posizionato con tutti i dati. Il servizio del cliente restituirebbe un codice di risposta HTTP 202, che indica che la richiesta è stata accettata, ma non è ancora stata elaborata. Il sistema di chiamata potrebbe allora interrogare l'attesa di risorse fino a quando non recupera una 201 Creato che indica che la richiesta è stata soddisfatta

Quindi nel tuo caso, si potrebbe pubblicare al server, ma immediatamente ottenere una risposta del tipo "Io salverò la PlaylistItem e io prometto che il suo ID sarà questo ". Il client (e l'utente) possono continuare mentre il server (forse nemmeno l'API, ma qualche processore in background che ha ricevuto un messaggio dall'API) impiega tempo per elaborare, validare e fare altre logiche, possibilmente pesanti fino a quando non salva l'entità. Come precedentemente affermato, l'API può fornire un endpoint GET per lo stato di tale richiesta e il client può eseguirne il polling e agire di conseguenza in caso di errore.

1

È possibile attendersi un UUID generato dal client o un identificatore univoco globale simile sul server. Fallo in modo sensato

La maggior parte delle vostre tabelle/collezioni manterrà anche un ID utente o sarà in grado di associarsi a un ID utente tramite un FK.

Se si sta inserendo un inserto e un utente malintenzionato utilizza una chiave esistente, l'inserimento avrà esito negativo poiché il record/documento esiste già.

Se si sta eseguendo un aggiornamento, è necessario verificare che l'utente che ha effettuato l'accesso possegga quel record o sia autorizzato (ad es. Utente amministratore) ad aggiornarlo. Se viene applicata la proprietà pura (vale a dire nessuno scenario utente amministratore), la clausola where nella ricerca del record/documento includerà sia l'ID che l'ID utente. Ora tecnicamente l'ID utente è ridondante nella clausola where perché l'Id troverà in modo univoco un record/documento. Tuttavia aggiungendo userId si assicura che il record appartenga all'utente che sta facendo l'aggiornamento e non all'utente malintenzionato.

Suppongo che ci sia un token crittografato o una sessione di qualche tipo che il server sta decodificando per accertare l'ID utente e che questo non è fornito dal client altrimenti non è ovviamente sicuro.