Per le password, l'invio di una copia hash della password sembra essere la tua migliore alternativa. Nota che questo evita due dei problemi che stai considerando: l'hash della password nasconde il "segreto" che stai trasmettendo, e il risultato dell'hash può essere espresso in un set di caratteri ragionevole in modo da non doverti preoccupare su codifica / decodifica. (Nota: non abbiamo effettivamente aggiunto alcuna sicurezza in questo modo).
Sono sospettoso nell'usare l'url per comunicare le credenziali - perché non usare l'intestazione Authorization? Hai scritto:
Any other operation in the API will be passed the user name and password for authorization purposes
Ti aspettavi di incorporare le credenziali in ogni chiamata API?
the operation is not idempotent
Quindi l'operazione è un POST. La risposta più comune che ho visto è quella di esporre una risorsa "raccolta token" e aggiungere un nuovo token pubblicando la richiesta su quella risorsa. Il principio della sorpresa minima dovrebbe forse inclinarti in questa direzione.
Ma potresti riesaminare la tua ipotesi che l'operazione non sia idempotente. Chiaramente, non vuoi avere più token nella tua tabella, ma se il database rifiuta il comando di iniettare un token duplicato, hai il comportamento idempotenziale di cui hai bisogno. Dovrai essere coerente con la semantica HTTP put, il che significa che vorrai che la risorsa che stai PUTting sia univoca per il token.
Si noti che la risorsa token e l'entità token sono due cose diverse. È possibile "creare" prima la risorsa, quindi (se l'applicazione client segue quel collegamento) creare il token. REST non si cura - finché il client sta seguendo i collegamenti forniti nell'ipermedia, tutto è buono.
I'm struggling trying to force tokens into being a resource.
Non dovrebbe essere troppo difficile, le risorse sono economiche.
Ad esempio, se il tuo token è un analogo di un cookie HTTP (una delle parti del web che Fielding chiama non essere riposante), un flusso di richieste dal client potrebbe essere simile a
POST /A
-- the server does its magic here, generating and storing a new token, which
-- it wants the client to reference in its subsequent requests
redirect: /B?token=54321
GET /B?token=54321
-- Now the server knows that this is a request for resource /B within the
-- context of the specific token. The representation of this resource
-- includes links to things that are also in the context of the token
returns: [representation including link /C?token=54321]
GET /C?token=54321
-- Subsequent calls stay in token=54321 space, until the server expires the
-- token and redirects the caller to some other representation of state.
Un'altra alternativa sarebbe quella di separare la prenotazione dell'identificatore token dalla creazione del token
GET /A
-- here, the server generates a unique identifier for the token, without
-- doing any of the persistence work.
redirect: /B?token=54321
POST /B?token=54321
-- The client passes back to the server the id of the token, and the server
-- can choose to go create it and store it.
-- Notice: we aren't posting to the token resource, we are posting to
-- the resource identified by /B?token=12345; you get to decide what
-- that resource is. If the representations are suitable, and you can make
-- the operation idempotent now that the token identifier is fixed, you
-- might be able to use PUT rather than POST
returns: [representation including link /C?token=54321]
GET /C?token=54321
-- Subsequent calls stay in token=54321 space, until the server expires the
-- token and redirects the caller to some other representation of state.
Se si desidera essere più attenti, è possibile implementare risorse che distinguono un token riservato da un token persistito .
GET /A
-- here, the server generates a unique identifier for the token, without
-- doing any of the persistence work. We're not making any changes to
-- the server state right now, so this is a reserved token.
redirect: /A?reservedToken=54321
GET /A?reservedToken=54321
-- this resource knows the token identifier, so it can now produce the
-- hypermedia control(s) that constrain the client to the reservedToken=54321 space.
-- We still haven't changed anything; this GET request is safe.
-- It's also potentially cacheable.
returns: [representation including link /B?reservedToken=54321]
POST /B?reservedToken=54321
-- The client passes back to the server the id of the token, and the server
-- can choose to go create it and store it.
-- Notice: we aren't posting to the token resource, we are posting to
-- the resource identified by /B?reservedToken=12345; you get to decide what
-- that resource is. If the representations are suitable, and you can make
-- the operation idempotent now that the token identifier is fixed, you
-- might be able to use PUT rather than POST.
redirect: /B?persistedToken=54321
GET /B?persistedToken=54321
-- Now this resource knows that the token has already been reserved, and
-- can generate additional hypermedia controls that constrain the
-- client to the persistedToken=54321 space. Once again, this GET
-- request is safe and cacheable.
returns: [representation including link /C?persistedToken=54321]
GET /C?persistedToken=54321
-- Subsequent calls stay in persistedToken=54321 space, until the server expires the
-- token and redirects the caller to some other representation of state.
Il client sta semplicemente scegliendo tra i controlli hypermedia forniti dal server. Quindi, mentre questa storia sarebbe simile a
GET /A
GET /A?reservedToken=54321
POST /B?reservedToken=54321
GET /B?persistedToken=54321
GET /C?persistedToken=54321
In seguito puoi decidere che se questi identificatori di risorse non sono conformi agli standard di codifica, o che sono difficili da seguire, o semplicemente che sei annoiato da loro, puoi cambiarli tutti
GET /A
GET /W?reservedToken=54321
POST /X?reservedToken=54321
GET /Y?persistedToken=54321
GET /Z?persistedToken=54321