✨ Servicio de Cambio de Contraseña en Vertical por Medio de API
La API update-password fue diseñada para permitir a los usuarios autenticados modificar la contraseña de una vertical de manera segura.
Esta API está protegida por autenticación JWT-> Se obtiene con la nueva API de Login, lo que garantiza que solo los usuarios autenticados puedan modificar su información.
🔐 Autenticación
El acceso a esta API requiere un token JWT válido. Este token debe enviarse en el encabezado de la solicitud como:
Authorization: Bearer TU_TOKEN_JWTSi el token es inválido o no se proporciona, la API rechazará la solicitud.
🧠 Controlador
Este archivo contiene la lógica principal para el manejo de la actualización de la contraseña de una vertical.
Ruta del archivo
src/api/user-endpoints/controllers/update-password.ts
⚙️ Funcionamiento interno de la API
El componente completo del registro es el siguiente:
export default { async updatePassword(ctx) { try { const { vertical, currentPassword, newPassword } = ctx.request.body;
validateKeys(ctx.request.body, VALID_NEW_PASSWORD_KEYS, FIELD_ROOT); validateRequiredFields(ctx.request.body, VALID_NEW_PASSWORD_KEYS);
const recivedUser = ctx.state.user; if (!recivedUser) { return ctx.unauthorized(ERROR_UNAUTHORIZED); } const { email } = recivedUser;
const user = await findOne( USER, FIELDS_USER, { email: email }, COMPONENT_NAME_USER_PASSWORDS );
if (!user) return ctx.notFound(ERROR_USER_NOT_FOUND);
if (currentPassword === newPassword) { return ctx.badRequest(ERROR_SAME_PASSWORD); }
const passwordComponent = user.verticalsUserPasswords?.find( (item) => item.vertical === vertical );
if (!passwordComponent) { return ctx.badRequest(ERROR_VERTICAL_PASSWORD_NOT_FOUND); }
const match = await bcrypt.compare( currentPassword, passwordComponent.verticalPassword ); if (!match) { return ctx.unauthorized(ERROR_INVALID_PASSWORD); }
await updateVerticalPassword(email, vertical, newPassword);
return ctx.send({ message: user }); } catch (error) { return ctx.badRequest(error, ERROR_UPDATE); } },};Cuando se realiza una solicitud a esta API, el primer paso es la validación del cuerpo para garantizar que no se estén enviando campos inesperados o mal estructurados.
- Se valida tanto que existan las claves obligatorias (
vertical,currentPassword,newPassword) mediante el util:validateRequiredFields(body, requiredUserKeys);
asegurandose contengan únicamente las propiedades válidas.
🧾 Datos esperados en el cuerpo de la solicitud (body)
El cuerpo debe enviarse en formato JSON y puede incluir los siguientes campos:
vertical(obligatorio): nombre de la vertical para la cual se está cambiando la contraseña.currentPassword(obligatorio): contraseña antigua de la vertical.newPassword(obligatorio): nueva contraseña que se asociará a la vertical.
Antes de procesar cualquier operación, el controlador valida que solo se estén enviando las claves permitidas, tanto a nivel raíz como en las direcciones anidadas.
validateKeys(ctx.request.body, VALID_NEW_PASSWORD_KEYS, FIELD_ROOT);validateRequiredFields(ctx.request.body, VALID_NEW_PASSWORD_KEYS);Luego, el sistema intenta localizar un usuario existente con el correo electrónico proporcionado por el token.
const recivedUser = ctx.state.user;if (!recivedUser) { return ctx.unauthorized(ERROR_UNAUTHORIZED);}const { email } = recivedUser;
const user = await findOne( USER, FIELDS_USER, { email: email }, COMPONENT_NAME_USER_PASSWORDS);Se comprueba que las contraseñas antigua y nueva no sean la misma. Y q la contraseña antigua coincida con la pasada por el body.
if (currentPassword === newPassword) { return ctx.badRequest(ERROR_SAME_PASSWORD);}
const passwordComponent = user.verticalsUserPasswords?.find( (item) => item.vertical === vertical);
if (!passwordComponent) { return ctx.badRequest(ERROR_VERTICAL_PASSWORD_NOT_FOUND);}
const match = await bcrypt.compare( currentPassword, passwordComponent.verticalPassword);if (!match) { return ctx.unauthorized(ERROR_INVALID_PASSWORD);}Finalmente se llama a la funcion para actualizr la contraseña 👍
await updateVerticalPassword(email, vertical, newPassword);🔐 ¿Qué hace exactamente updateVerticalPassword?
- Vease su funcionamiento Aquí.
📤 Ejemplo de solicitud
URL: /api/user-endpoints/updatee-password
Método: POST
Body ejemplo:
{ "vertical": "Emergencias", "currentPassword": "1234", "newPassword": "123456"}✅ Respuestas esperadas
✔️ Registro exitoso
{ "message": { "id": 22, "documentId": "p800i3wc6h36p6jnghtbhv8c", "username": "Marti", "email": "example@example.com", "confirmed": false, "phone": null, "origin": "local", "identificationNumber": "01234567X", "nameLastName": "Marta Quiros", "verticalsUserPasswords": [ { "id": 18, "vertical": "Emergencias", "verticalPassword": "$2a$10$xxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxx.xxxxxxxxxxx" } ] }}❌ Campos inválidos o faltantes
{ "data": null, "error": { "status": 400, "name": "Error", "message": "Missing required parameters: vertical", "details": "Error on update " }}{ "data": null, "error": { "status": 400, "name": "Error", "message": "Not Allowed fields at root: email", "details": "Error on update " }}❌ La nueva contraseña es igual que la antigua
{ "data": null, "error": { "status": 400, "name": "BadRequestError", "message": "New password can not be the same as the old one", "details": {} }}🔗 Funciones auxiliares
-
validateKeys,validateRequiredFields: validación de la estructura del body. -
validateFieldPatterns: asegura que contraseñas cumplan con las reglas.🐿️ -> Veanse aqui validaciones de campos.
-
findOne,updateDocument: funciones de acceso a la base de datos. -
sendEmail: abstracta el envío de correos con plantillas multilenguaje.🐿️ -> Veanse aqui strapi queries.
-
updateVerticalPassword: actualiza la contraseña cifrada de la vertical correspondiente.🐿️ -> Veanse aqui strapi passwords.