Qual é a maneira adequada de estruturar um recurso RESTful para redefinir uma senha?
Este recurso deve ser uma redefinição de senha para alguém que perdeu ou esqueceu sua senha. Isso invalida a senha antiga e envia uma senha por e-mail.
As duas opções que tenho são:
POST /reset_password/{user_name}
ou...
POST /reset_password
-Username passed through request body
Tenho certeza de que a solicitação deve ser um POST. Estou menos confiante de que selecionei um nome apropriado. E não tenho certeza se o user_name deve ser passado pelo URL ou corpo da solicitação.
fonte
Usuários não autenticados
Fazemos uma
PUT
solicitação em umapi/v1/account/password
endpoint e exigimos um parâmetro com o e-mail da conta correspondente para identificar a conta para a qual o usuário deseja redefinir (atualizar) a senha:Nota: Como @DougDomeny mencionou em seu comentário, passar o e-mail como uma string de consulta no url é um risco de segurança. Os parâmetros GET não são expostos durante o uso
https
(e você deve sempre usar umahttps
conexão adequada para essas solicitações), mas há outros riscos de segurança envolvidos. Você pode ler mais sobre este tópico nesta postagem do blog aqui .Passar o e-mail no corpo da solicitação seria uma alternativa mais segura do que passá-lo como um parâmetro GET:
Corpo da solicitação:
A resposta tem um significado de resposta
202
aceito :O usuário receberá um e-mail em
[email protected]
e o processamento da solicitação de atualização depende das ações realizadas com o link do e-mail.Abrir o link deste e-mail direcionará para um formulário de redefinição de senha no aplicativo front end que usa o token de redefinição de senha do link como entrada para um campo de entrada oculto (o token faz parte do link como uma string de consulta). Outro campo de entrada permite que o usuário defina uma nova senha. Uma segunda entrada para confirmar a nova senha será usada para validação no front-end (para evitar erros de digitação).
Nota: No email também poderíamos mencionar que caso o usuário não inicialize nenhuma redefinição de senha ele pode ignorar o email e continuar usando o aplicativo normalmente com sua senha atual
Quando o formulário é enviado com a nova senha e o token como entradas, o processo de redefinição da senha ocorrerá. Os dados do formulário serão enviados com uma
PUT
solicitação novamente, mas desta vez incluindo o token e substituiremos a senha do recurso por um novo valor:Corpo da solicitação:
A resposta será uma resposta
204
sem conteúdoUsuários autenticados
Para usuários autenticados que desejam alterar sua senha, a
PUT
solicitação pode ser realizada imediatamente sem o e-mail (a conta para a qual estamos atualizando a senha é conhecida pelo servidor). Nesse caso, o formulário apresentará dois campos:Corpo da solicitação:
fonte
Vamos usar o uber-RESTful por um segundo. Por que não usar a ação DELETE para a senha para acionar uma redefinição? Faz sentido, não é? Afinal, você está efetivamente descartando a senha existente em favor de outra.
Isso significa que você faria:
Agora, duas grandes advertências:
HTTP DELETE deve ser idempotente (uma palavra chique para dizer "não é grande coisa se você fizer isso várias vezes"). Se estiver fazendo as coisas padrão, como enviar um e-mail de "Redefinição de senha", você terá problemas. Você poderia contornar isso marcando o usuário / senha com um sinalizador booleano "Is Reset". Em cada exclusão, você verifica este sinalizador; se não estiver definido , você pode redefinir a senha e enviar seu e-mail. (Observe que esse sinalizador pode ter outros usos também.)
Você não pode usar HTTP DELETE através de um formulário , então você terá que fazer uma chamada AJAX e / ou tunelar o DELETE através do POST.
fonte
DELETE
encaixe bem aqui. Você estaria substituindo a senha por uma gerada aleatoriamente, eu acho, entãoDELETE
pode ser enganoso. Eu prefiro oCreate (POST) new reset_password action
, onde o substantivo (recurso) em que você estaria agindo é a "ação reset_password". Isso se encaixa bem para enviar e-mails também, uma vez que a ação encapsula todos esses detalhes de nível inferior.POST
não é idempotente.Freqüentemente, você não deseja excluir ou destruir a senha existente do usuário na solicitação inicial, pois isso pode ter sido acionado (não intencionalmente ou intencionalmente) por um usuário que não tem acesso ao e-mail. Em vez disso, atualize um token de redefinição de senha no registro do usuário e envie-o em um link incluído em um e-mail. Clicar no link confirma que o usuário recebeu o token e deseja atualizar sua senha. Idealmente, isso seria sensível ao tempo também.
A ação RESTful neste caso seria um POST: acionando a ação de criação no controlador PasswordResets. A própria ação atualizaria o token e enviaria um e-mail.
fonte
Na verdade, estou procurando uma resposta, sem querer fornecer uma - mas "reset_password" parece errado para mim em um contexto REST porque é um verbo, não um substantivo. Mesmo se você disser que está fazendo um substantivo de "ação de redefinição" - usando essa justificativa, todos os verbos são substantivos.
Além disso, pode não ter ocorrido a alguém que procurava a mesma resposta que você pudesse obter o nome de usuário por meio do contexto de segurança e não precisar enviá-lo por meio da url ou do corpo, o que me deixa nervoso.
fonte
reset-password
soe como um verbo, mas você pode facilmente invertê-lo (password-reset
) para torná-lo um substantivo. E se você modelou seu aplicativo usando Event Sourcing ou mesmo se você apenas tem qualquer tipo de auditoria, faz sentido que você realmente tenha uma entidade real com este nome e pode até permitir GETs nela para usuários ou administradores verem histórico (obviamente mascarando o texto da senha). Não me deixa nem um pouco nervoso. E quanto a pegar o nome de usuário automaticamente no servidor - você pode, mas então como você lida com coisas como administração / personificação?reset-password
consigo descrever bem seus efeitos.Acho que a melhor ideia seria:
Em relação ao fornecimento dos dados:
Para redefinir a senha atual
Para criar uma nova senha (após redefinir)
Para atualizar a senha (para usuário conectado)
fonte
Existem algumas considerações a serem feitas:
Redefinições de senha não são idempotentes
Uma alteração de senha afeta os dados usados como credenciais para executá-la, o que, como resultado, pode invalidar tentativas futuras se a solicitação for simplesmente repetida literalmente enquanto as credenciais armazenadas são alteradas. Por exemplo, se um token de reconfiguração temporário for usado para permitir a mudança, como é comum em uma situação de senha esquecida, esse token deve expirar após a mudança de senha bem-sucedida, o que novamente anula outras tentativas de replicação da solicitação. Portanto, uma abordagem RESTful para uma alteração de senha parece ser uma tarefa mais adequada do
POST
quePUT
.ID ou e-mail na carga de dados é provavelmente redundante
Embora isso não seja contra REST e possa ter algum propósito especial, geralmente é desnecessário especificar um ID ou endereço de e-mail para uma redefinição de senha. Pense nisso, por que você forneceria o endereço de e-mail como parte dos dados para uma solicitação que deveria passar por autenticação de uma forma ou de outra? Se o usuário estiver simplesmente alterando sua senha, ele precisa se autenticar para fazer isso (por meio de nome de usuário: senha, e-mail: senha ou token de acesso fornecido por cabeçalhos). Portanto, temos acesso à conta deles a partir dessa etapa. Se eles tivessem esquecido a senha, eles teriam recebido um token de redefinição temporário (via e-mail) que eles poderiam usar especificamente como credenciais para realizar a alteração. E neste caso a autenticação via token deve ser suficiente para identificar sua conta.
Levando todos os itens acima em consideração, aqui está o que acredito ser o esquema adequado para uma alteração de senha RESTful:
fonte
POST
relação aoPUT
RFC 7231 especifica que uma atualização parcial pode ser alcançada por meio da sobreposição de dados de dois recursos, mas é questionável se algo como/v1/account/password
realmente compensa um bom recurso. AssimPOST
como o canalha do exército suíço da Web, que pode ser usado se nenhum dos outros métodos for viável, considerarPATCH
também pode ser uma opção para definir a nova senha.Eu não teria algo que mudasse a senha e enviasse uma nova se você decidir usar o método / users / {id} / password e se ater à sua ideia de que a solicitação é um recurso próprio. ou seja, / solicitação de senha de usuário / é o recurso, e é usado PUT, as informações do usuário devem estar no corpo. Eu não mudaria a senha, porém, vou enviar um e-mail para o usuário que contém um link para uma página que contém um request_guid, que pode ser passado junto com uma solicitação para POST / user / {id} / password /? Request_guid = xxxxx
Isso mudaria a senha e não permitiria que alguém enviasse uma mangueira a um usuário solicitando uma mudança de senha.
Além disso, o PUT inicial pode falhar se houver uma solicitação pendente.
fonte
Nós atualizamos a senha do usuário registrado PUT / v1 / users / password - identifique o ID do usuário usando AccessToken.
Não é seguro trocar o ID do usuário. A API Restful deve identificar o usuário usando AccessToken recebido no cabeçalho HTTP.
Exemplo em bota de mola
fonte