Quale design API ha più senso per cambiare la password di un utente?

1

Considera una pagina web in cui un utente cambia la sua password dopo aver fatto clic su un link di reimpostazione della password via email.

La pagina verrà implementata rispetto a un'API utilizzando ajax, piuttosto che come una normale sottomissione di modulo. Cioè, questa domanda riguarda la progettazione di un endpoint API per la modifica di una password.

Requisiti

Ogni volta che viene modificata una password, la modifica deve essere registrata nel database nella tabella password_changes :

password_changes
  - user_id
  - date_changed

Domanda specifica

Pensando a questo progetto dal punto di vista degli endpoint API che creano, aggiornano o eliminano "risorse" astratte, ha più senso pensare alla modifica della password come:

  1. Stiamo aggiornando la risorsa "utente", quindi dovrebbe PUT una nuova password su /user/{id} o forse /user/{id}/password ? In questo modello, registrare la modifica in password_changes è solo un dettaglio di implementazione irrilevante e non ha alcun impatto sul nostro concetto di risorsa "utente" o sul nome del nostro endpoint.

  2. Stiamo creando un "password_change". Quindi dovremmo essere POST a /user/{id}/password_change o qualcosa di simile. In questo modello, la modifica alla risorsa "utente" è solo un effetto collaterale della creazione di una "password_change".

In questo particolare esempio, penso che la maggior parte delle persone scelga l'opzione 1. E in effetti mi sembra anche più naturale. Compra perché? È solo una questione di giudizio, gusto o intuizione? O c'è qualche principio codificato di REST o anche i concetti di base delle risorse e delle azioni http che l'opzione 2. viola chiaramente?

Altre domande generali

Che cosa succede se forniamo una cronologia delle modifiche della password come nuovo enpoint: /user/{id}/password_changes ?

Sembra un servizio ragionevole.

Ma se ci atteniamo al design 1., ora apportiamo le modifiche della password apportando PUT s a /user ma visualizzandole con GET s su /user/{id}/password_changes . E poi limitiamo semplicemente altre azioni http a password_changes (PUT, POST, DELETE)? Sembra incoerente ... o forse no?

Ancora una volta, quali sono le regole (o anche le euristiche) che governano queste decisioni? Posso fare chiamate di giudizio, ma sto cercando qualcosa di più definitivo.

    
posta Jonah 02.07.2016 - 05:02
fonte

2 risposte

1

In this particular example, I think most people would choose option 1. And indeed it feels more natural to me too. Buy why?

Non sono certo che ci sarà una risposta definitiva a questo, ma la mia ipotesi: perché la password, l'entità, ha una rappresentazione relativamente diretta come un documento ; La ragion d'essere di HTTP è il trasferimento di documenti, dopo tutto. È abbastanza ben progettato per questo.

Inoltre, c'è una semplicità nella password: lo stato corrente è un tipo di valore semplice e di conseguenza non c'è confusione su cosa debba significare "modifica". Avere solo un singolo metodo disponibile per mutare lo stato della risorsa non causa alcun problema perché c'è solo un modo in cui si vorrebbe: sostituendo completamente una rappresentazione con un'altra, che è esattamente la semantica del metodo PUT in HTTP.

Generally speaking, a password change is not idempotent.

Sì, ma qui è un punto controverso; la scelta del metodo in questo caso è più motivata da cosa dovrebbe accadere se una richiesta non viene riconosciuta. Possiamo riprovare? Se il messaggio viaggia attraverso un intermediario, è esso autorizzato a ritentare il messaggio piuttosto che restituire immediatamente un errore al client?

(Certo, se stiamo gettando segreti in giro, dovremmo usare un canale criptato, il che significa che gli intermedi non possono vedere cosa sta succedendo)

Non inviamo la richiesta due volte perché vogliamo che la modifica venga applicata due volte, la inviamo due volte per assicurarci che venga consegnata almeno una volta.

Per garantire che l'effetto collaterale sul dominio non venga ripetuto, utilizzare un "put condizionale", in modo che il server possa distinguere tra due copie della stessa richiesta e due diverse richieste che contengono la stessa rappresentazione della password.

What if we provide a history of password changes as a new end point: /user/{id}/password_changes?

That seems like a reasonable service.

Yup. Probabilmente mi sporgo verso l'ortografia /user/{id}/password/history ; è naturale rendere il log di controllo subordinato alla risorsa password.

And then do we just disallow other http actions to password_changes (PUT, POST, DELETE)? That seems inconsistent... or maybe not?

Non vedo un problema di coerenza. Il tuo modello di dominio è il libro del record per le modifiche della password; che la cronologia non è soggetta a override da parte dei clienti - il dominio riserva questo privilegio per se stesso. Quindi la risorsa è di sola lettura. Ta-da?

tutto ciò che ho detto

We're creating a "password_change". Thus we should be POST to /user/{id}/password_change, or something similar. In this model, the change to the "user" resource is just a side effect of creating a "password_change".

Questo non è sbagliato neanche; se lo giri un po ', stai essenzialmente descrivendo AtomPub; stai pubblicando una voce (l'evento PasswordChanged) in un feed (la cronologia) e il nuovo "stato" della risorsa deriva dal guardare la cronologia. In altre parole, RESTful .

È un po 'storto; il solito idioma è che i comandi vengono inviati a aggregate nel modello di dominio e le modifiche di stato causate dal comando vengono pubblicate su un flusso, che viene esposto tramite un feed atom. In questo caso d'uso, lo giriamo, in qualche modo, dal fatto che l'essere umano, piuttosto che il dominio, è il libro dei record. Forse.

Jim Webber descrive i protocolli di applicazione REST come un analogo a un ufficio stile anni '50, in cui si ottengono risultati trasferendo i documenti in caselle di posta. Fornisci una ChangePasswordRequest al server e, come effetto collaterale, il modello di dominio si aggiorna da solo, il che ha l'effetto collaterale della modifica dello stato di altre risorse, come il log di controllo.

Forse è eccessivo per un semplice protocollo ReplacePassword, ma è utile tenerlo a mente quando le cose diventano più complicate.

    
risposta data 02.07.2016 - 06:47
fonte
2

Semanticamente, considererei una password cambiare un POST. Perché?

  1. Non stai aggiornando un'intera risorsa (cioè un utente), ma solo una proprietà su quella risorsa, una proprietà che non ha molto a che fare con le caratteristiche della risorsa (come il loro indirizzo o il colore dei capelli ), tranne nella misura in cui detta proprietà influenza la loro capacità di accedere al sistema. Poiché non è possibile recuperare una password con un oggetto USER, in altre parole non è una parte intrinseca di un USER ai fini CRUD.

  2. In generale, una modifica della password non è idempotente. Molti sistemi non ti permetteranno di riutilizzare le password precedenti, e una modifica della password di solito comporta una danza complessa di consegnare all'utente un URL magico attraverso il loro indirizzo email on-file e scadenza dopo un certo periodo di tempo. Nessuna di queste azioni è realmente coerente con la nozione di GET o PUT.

Verdetto: POST.

What if we provide a history of password changes...

Se il tuo sistema è progettato correttamente, né tu né nessun altro possiedi queste informazioni. I sistemi ben progettati memorizzano gli hash delle password, non le password effettive e non è possibile decodificare le password originali dagli hash.

    
risposta data 02.07.2016 - 05:31
fonte

Leggi altre domande sui tag