# Validación de usuario (Login)
A continuación se muestra el código de la validación de usuario, en el cual se verifica que el usuario exista en la base de datos y que la contraseña sea correcta dentro de la API.
Para lograr esto necesitamos tener 3 endpoints en la API:
- `create` para crear/modificar un nuevo usuario
- `assignPassword` para asignarle una constraseña a un usuario
- `validate` para validar que el usuario y contraseña ingresados son válidos
En primera instancia, necesitamos registrar una la librería `bcrypt`:
```typescript
yarn add bcrypt
```
Luego creamos el router `user.ts` con los 3 endpoints antes mencionados (dentro de la carpeta `/src/routes`):
```typescript
import { Router } from "express";
import {
create,
assignPassword,
validate,
} from "../controllers/user";
const UserRouter = Router();
UserRouter.post("/create", create);
UserRouter.put("/assignPassword/:id", assignPassword);
UserRouter.post("/validate", validate);
export default UserRouter;
```
Posteriormente creamos el controlador `user.ts` (dentro de la carpeta `/src/controllers`):
```typescript
import createLogger from "../utils/logger";
import * as User from "../models/user";
import * as Person from "../models/person";
const create = async (req: any, res: any) => {
try {
const {
rut,
name,
paternal_lastname,
maternal_lastname,
address,
district_id,
email,
phone,
} = req.body;
const personByRutResponse = await Person.getByRut(rut);
if (personByRutResponse.success) {
return res.status(500).json({ error: "Error searching person" });
}
let personResponse;
if (personByRutResponse.data) {
const { id: person_id } = personByRutResponse.data;
personResponse = await Person.updateById(
person_id,
name,
paternal_lastname,
maternal_lastname,
address,
district_id,
email,
phone
);
} else {
personResponse = await Person.insert(
rut,
name,
paternal_lastname,
maternal_lastname,
address,
district_id,
email,
phone
);
}
if (!personResponse.success) {
return res.status(500).json({ error: "Error registering person" });
}
const { id: person_id } = personResponse.data;
const userResponse = await User.insert(person_id);
if (!userResponse.success) {
return res.status(500).json({ error: "Error creating user" });
}
createLogger.info({
controller: "user/insert",
data: personResponse.data,
});
return res.status(200).json(personResponse);
} catch (e) {
createLogger.error({
controller: "user/insert",
error: (e as Error).message,
});
return res.status(500).json({ error: "Error creating user" });
}
}
};
const assignPassword = async (req: any, res: any) => {
try {
const { id } = req.params;
const { password } = req.body;
const result = await User.assignPassword(id, password);
if (!result.success) {
createLogger.error({
model: "user/assignPassword",
method: "POST",
error: result.error,
});
return res.status(500).json({ error: "Error inesperado" });
}
res.status(200).json(result.data);
} catch (e) {
createLogger.error({
model: "user/assignPassword",
method: "POST",
error: (e as Error).message,
});
return res.status(500).json({ error: "Error inesperado" });
}
};
const validate = async (req: any, res: any) => {
try {
const { email, password } = req.body;
const result = await User.validate(email, password);
if (!result.success) {
createLogger.error({
model: "user/validate",
method: "POST",
error: result.error,
});
return res.status(500).json({ error: "Error inesperado" });
}
if (result.success) {
if (result.data.isValid) {
res.status(200).json(result.data);
} else {
res.status(403).json({ error: "User not valid" });
}
}
} catch (e) {
createLogger.error({
controller: "user/validate",
method: "POST",
error: (e as Error).message,
});
return res.status(500).json({ error: "Error inesperado" });
}
};
export {
create,
assignPassword,
validate,
};
```
Finalmente el modelo sería como sigue:
```typescript
import db from "../utils/db";
import createLogger from "../utils/logger";
import bcrypt from "bcrypt";
import { RowDataPacket } from "mysql2/promise";
import {
_insert,
_asisgnPassword,
_validate,
} from "../queries/user";
const create: any = async (values: any) => {
try {
createLogger.info({
model: "user/create",
input: { values },
});
const { person_id } = values;
const [result] = await db.query(_insert, [ person_id ]);
return {
success: true,
data: { id: result["insertId"] },
error: null,
};
} catch (e) {
return { success: false, data: null, error: (e as Error).message };
}
};
const assignPassword: any = async (id: string, password: string) => {
try {
createLogger.info({
model: "user/assignPassword",
input: { id, password },
});
const saltRounds = 10;
const hash = await bcrypt.hash(password, saltRounds);
const [rows] = await db.query(_asisgnPassword, [hash, id, id]);
return { success: true, data: (<RowDataPacket>rows)[1][0], error: null };
} catch (e) {
return { success: false, data: null, error: (e as Error).message };
}
};
const validate: any = async (login: string, password: string) => {
try {
createLogger.info({
model: "user/validate",
input: { login, password },
});
const [rows] = await db.query(_validate, [login]);
const {
id,
person_id,
rut,
name,
paternalLastName,
maternalLastName,
address,
district_id,
email,
phone,
hash,
} = (<RowDataPacket>rows)[0];
const isValid = await bcrypt.compare(password, hash);
return {
success: true,
data: {
id,
person_id,
rut,
name,
paternalLastName,
maternalLastName,
address,
district_id,
email,
phone
},
error: null,
};
} catch (e) {
return { success: false, data: null, error: (e as Error).message };
}
};
export { insert, assignPassword, validate };
```