¿Cuál es la forma correcta de estructurar un recurso RESTful para restablecer una contraseña?
Este recurso está destinado a restablecer la contraseña para alguien que ha perdido u olvidado su contraseña. Invalida su contraseña anterior y les envía una contraseña por correo electrónico.
Las dos opciones que tengo son:
POST /reset_password/{user_name}
o...
POST /reset_password
-Username passed through request body
Estoy bastante seguro de que la solicitud debe ser POST. Tengo menos confianza en haber seleccionado un nombre apropiado. Y no estoy seguro de si el nombre de usuario debe pasarse a través de la URL o el cuerpo de la solicitud.
fuente
Usuarios no autenticados
Hacemos una
PUT
solicitud en unapi/v1/account/password
endpoint y requerimos un parámetro con el correo electrónico de la cuenta correspondiente para identificar la cuenta para la cual el usuario desea restablecer (actualizar) la contraseña:Nota: Como @DougDomeny mencionó en su comentario, pasar el correo electrónico como una cadena de consulta en la URL es un riesgo de seguridad. Los parámetros GET no se exponen al usarlos
https
(y siempre debe usar unahttps
conexión adecuada para tales solicitudes), pero existen otros riesgos de seguridad involucrados. Puede leer más sobre este tema en esta publicación de blog aquí .Pasar el correo electrónico en el cuerpo de la solicitud sería una alternativa más segura que pasarlo como un parámetro GET:
Cuerpo de la solicitud:
La respuesta tiene un significado de respuesta
202
aceptado :El usuario recibirá un correo electrónico en
[email protected]
y el procesamiento de la solicitud de actualización depende de las acciones tomadas con el enlace del correo electrónico.Al abrir el enlace de este correo electrónico, se dirigirá a un formulario de restablecimiento de contraseña en la aplicación de interfaz que utiliza el token de restablecimiento de contraseña del enlace como entrada para un campo de entrada oculto (el token es parte del enlace como una cadena de consulta). Otro campo de entrada permite al usuario establecer una nueva contraseña. Una segunda entrada para confirmar la nueva contraseña se utilizará para la validación en el front-end (para evitar errores tipográficos).
Nota: En el correo electrónico también podríamos mencionar que en caso de que el usuario no haya inicializado ningún restablecimiento de contraseña, puede ignorar el correo electrónico y seguir usando la aplicación normalmente con su contraseña actual.
Cuando el formulario se envía con la nueva contraseña y el token como entradas, se llevará a cabo el proceso de restablecimiento de contraseña. Los datos del formulario se enviarán con una
PUT
solicitud nuevamente, pero esta vez incluyendo el token y reemplazaremos la contraseña del recurso con un nuevo valor:Cuerpo de la solicitud:
La respuesta será una respuesta
204
sin contenido.Usuarios autenticados
Para los usuarios autenticados que desean cambiar su contraseña, la
PUT
solicitud se puede realizar de inmediato sin el correo electrónico (el servidor conoce la cuenta para la que estamos actualizando la contraseña). En tal caso, el formulario enviará dos campos:Cuerpo de la solicitud:
fuente
Consigamos súper RESTful por un segundo. ¿Por qué no utilizar la acción DELETE para que la contraseña active un restablecimiento? Tiene sentido, ¿no? Después de todo, efectivamente está descartando la contraseña existente en favor de otra.
Eso significa que harías:
Ahora, dos grandes advertencias:
Se supone que HTTP DELETE es idempotente (una palabra elegante para decir "no es gran cosa si lo haces varias veces"). Si está haciendo cosas estándar como enviar un correo electrónico de "Restablecimiento de contraseña", entonces tendrá problemas. Puede solucionar esto etiquetando el usuario / contraseña con un indicador booleano "Se restablece". En cada eliminación, marca esta bandera; Si no se establece a continuación, puede restablecer la contraseña y envía su correo electrónico. (Tenga en cuenta que tener esta bandera también puede tener otros usos).
No puede usar HTTP DELETE a través de un formulario , por lo que tendrá que hacer una llamada AJAX y / o tunelizar el DELETE a través del POST.
fuente
DELETE
encaje bien aquí. Estaría sustituyendo la contraseña por una generada al azar, supongo, por lo queDELETE
podría ser engañoso. Prefiero elCreate (POST) new reset_password action
, donde el sustantivo (recurso) sobre el que actuarías es "reset_password action". Esto también se ajusta bien para enviar correos electrónicos, ya que la acción encapsula todos estos detalles de nivel inferior.POST
no es idempotente.A menudo, no desea eliminar o destruir la contraseña existente del usuario en la solicitud inicial, ya que esto puede haber sido activado (involuntaria o intencionalmente) por un usuario que no tiene acceso al correo electrónico. En su lugar, actualice un token de restablecimiento de contraseña en el registro de usuario y envíelo en un enlace incluido en un correo electrónico. Hacer clic en el enlace confirmaría que el usuario recibió el token y deseaba actualizar su contraseña. Idealmente, esto también sería sensible al tiempo.
La acción RESTful en este caso sería una POST: desencadenando la acción de creación en el controlador PasswordResets. La acción en sí misma actualizaría el token y enviaría un correo electrónico.
fuente
En realidad, estoy buscando una respuesta, no es mi intención proporcionar una, pero "reset_password" me suena mal en un contexto REST porque es un verbo, no un sustantivo. Incluso si dices que estás haciendo un sustantivo de "acción de restablecimiento", usando esta justificación, todos los verbos son sustantivos.
Además, es posible que a alguien que busque la misma respuesta no se le haya ocurrido que puede obtener el nombre de usuario a través del contexto de seguridad y no tener que enviarlo a través de la URL o el cuerpo, lo que me pone nervioso.
fuente
reset-password
suene como un verbo, pero puedes revertirlo fácilmente (password-reset
) para convertirlo en un sustantivo. Y si ha modelado su aplicación utilizando Event Sourcing o incluso si solo tiene algún tipo de auditoría, tiene sentido que realmente tenga una entidad real con este nombre e incluso podría permitir GET para que los usuarios o administradores vean historial (obviamente enmascarando el texto de la contraseña). No me pone nervioso en absoluto. Y en cuanto a elegir el nombre de usuario automáticamente en el lado del servidor, puede hacerlo, pero entonces, ¿cómo maneja cosas como la administración / suplantación?reset-password
para describir bien sus efectos.Creo que una mejor idea sería:
Respecto al suministro de datos:
Para restablecer la contraseña actual
Para crear una nueva contraseña (después de restablecer)
Para actualizar la contraseña (para usuarios registrados)
fuente
Hay algunas consideraciones a tener en cuenta:
Los restablecimientos de contraseña no son idempotentes
Un cambio de contraseña afecta los datos utilizados como credenciales para realizarlo, lo que, como resultado, podría invalidar futuros intentos si la solicitud simplemente se repite literalmente mientras las credenciales almacenadas han cambiado. Por ejemplo, si se usa un token de restablecimiento temporal para permitir el cambio, como es habitual en una situación de contraseña olvidada, ese token debe caducar tras un cambio de contraseña exitoso, lo que nuevamente anula los intentos adicionales de replicar la solicitud. Por lo tanto un enfoque REST a un cambio de contraseña parece ser un trabajo más adecuado para
POST
quePUT
.La identificación o el correo electrónico en la carga de datos probablemente sea redundante
Aunque eso no está en contra de REST y puede tener algún propósito especial, a menudo no es necesario especificar una identificación o dirección de correo electrónico para restablecer la contraseña. Piénselo, ¿por qué proporcionaría la dirección de correo electrónico como parte de los datos a una solicitud que se supone que debe pasar por la autenticación de una forma u otra? Si el usuario simplemente está cambiando su contraseña, debe autenticarse para poder hacerlo (a través de nombre de usuario: contraseña, correo electrónico: contraseña o token de acceso proporcionado a través de encabezados). Por lo tanto, tenemos acceso a su cuenta desde ese paso. Si hubieran olvidado su contraseña, se les habría proporcionado un token de restablecimiento temporal (por correo electrónico) que pueden usar específicamente como credenciales para realizar el cambio. Y en este caso, la autenticación mediante token debería ser suficiente para identificar su cuenta.
Teniendo todo lo anterior en consideración, aquí está lo que creo que es el esquema adecuado para un cambio de contraseña RESTful:
fuente
POST
vs.PUT
RFC 7231 especifica que se puede lograr una actualización parcial a través de datos superpuestos de dos recursos, pero es cuestionable si algo como/v1/account/password
realmente compensa un buen recurso. Al igualPOST
que el swiss-army-kniff de la Web que se puede utilizar si ninguno de los otros métodos es factible, considerarPATCH
también podría ser una opción para establecer la nueva contraseña.No tendría algo que cambie la contraseña y les envíe una nueva si decide usar el método / users / {id} / password y se adhiere a su idea de que la solicitud es un recurso en sí mismo. es decir, / user-password-request / es el recurso, y se usa PUT, la información del usuario debe estar en el cuerpo. Sin embargo, no cambiaría la contraseña, enviaría un correo electrónico al usuario que contiene un enlace a una página que contiene un request_guid, que podría pasar junto con una solicitud a POST / user / {id} / password /? Request_guid = xxxxx
Eso cambiaría la contraseña y no permite que alguien mande a un usuario solicitando un cambio de contraseña.
Además, el PUT inicial podría fallar si hay una solicitud pendiente.
fuente
Actualizamos la contraseña del usuario registrado PUT / v1 / users / password: identifique la identificación del usuario mediante AccessToken.
No es seguro intercambiar la identificación de usuario. La API Restful debe identificar al usuario que usa AccessToken recibido en el encabezado HTTP.
Ejemplo en spring-boot
fuente