‫Instructor: En esta
‫lección, administraremos las contraseñas de nuestros usuarios en la base de datos.
‫Y con eso me refiero a validar
‫primero si la contraseña ingresada es igual a la contraseña confirmada
‫y luego también a cifrar la contraseña en la base de
‫datos para protegerla contra ataques.
‫Entonces, lo primero que
‫haremos es validar si las dos contraseñas ingresadas son iguales.
‫Y el mejor lugar para hacerlo
‫es aquí en la confirmación de contraseña, ¿de acuerdo?
‫Entonces, escriba nuestro validador personalizado para eso, ¿de acuerdo?
‫Así que recuerde, usamos la propiedad de validación y
‫luego, dado que queremos crear
‫una función y también un mensaje de error, abramos un
‫nuevo objeto aquí y luego creemos
‫un validador, que será
‫la función y comencemos con este.
‫Entonces, recuerde, todo lo que necesitamos aquí es especificar
‫una función de devolución de llamada simple que luego se llamará
‫cuando se cree el nuevo documento.
‫Entonces, función, y
‫aquí nuevamente, no podemos usar una función de flecha porque
‫en realidad necesitamos usar la palabra clave disk.
‫¿Okey?
‫Entonces, recuerde que de la función de
‫validación devolvemos verdadero o falso
‫y si el valor devuelto es falso,
‫entonces significa que obtendremos un error de validación, ¿de acuerdo?
‫Y, por supuesto, si es cierto, entonces no.
‫Entonces, lo que queremos aquí es decir que el elemento actual, la contraseña
‫de confirmación, es igual a esta contraseña de punto, entonces, la contraseña
‫de confirmación, es igual a esta contraseña de punto,
‫¡y eso es todo!
‫Entonces, por ejemplo, si la confirmación de contraseña es A-B-C, y
‫la contraseña también es A-B-C, entonces esto, por
‫supuesto, volverá a ser verdadero, ¿de acuerdo?
‫Entonces, se pasa la
‫validación y no se producirá ningún error.
‫Pero, si la contraseña inicial es, digamos, X-Y-Z, entonces, por
‫supuesto, esto devolverá falso y
‫tendremos un error de validación, ¿de acuerdo?
‫Entonces, muy simple, pero debemos tener
‫en cuenta que esto solo funcionará para guardar, ¿de acuerdo?
‫Así que hablé de eso
‫antes cuando usamos el validador personalizado en el modelo de gira, ¿verdad?
‫Pero te lo recuerdo aquí
‫de nuevo porque esto es absolutamente crucial aquí en este punto, ¿de acuerdo?
‫Así que déjame que te lo escriba aquí.
‫(clic
‫del teclado)
‫Al guardar.
‫¿Okey?
‫Y por ello, siempre que queramos actualizar un usuario,
‫siempre tendremos que usar también guardar y
‫no, por ejemplo, buscar uno y actualizar como
‫hicimos con nuestros tours, ¿de acuerdo?
‫Así que tengamos esto en cuenta
‫cuando escribamos el resto del código en el resto de
‫la sección y especialmente para la actualización, ¿de acuerdo?
‫Porque digamos que actualizamos la contraseña del usuario
‫simplemente con una actualización regular.
‫Entonces, en ese caso, esta contraseña confirma la
‫validación que tenemos aquí ya no funcionaría, ¿de acuerdo?
‫Y, por supuesto, eso no puede suceder, ¿de acuerdo?
‫Y así, nuevamente, tenga en cuenta que esto solo funcionará
‫cuando creamos un nuevo objeto, por lo tanto, al crear puntos o al guardar.
‫¿Okey?
‫Entonces, al crear y
‫guardar, al crear y guardar, ¿de
‫acuerdo?
‫Entonces creamos un nuevo objeto usando crear, ¿verdad?
‫Entonces, aquí mismo, usé un punto para crear Entonces,
‫aquí mismo, usé un punto
‫para crear, pero
‫recuerden que también les mostré que podemos usar un
‫usuario para guardar puntos, como este, ¿verdad?
‫Y de hecho, también podemos usar un punto de usuario
‫para guardar para actualizar al usuario, ¿de acuerdo?
‫Pero de nuevo, hablaremos de ello un poco más tarde.
‫¿Okey?
‫Así que probemos ahora esta validación aquí, ¿de acuerdo?
‫Entonces, en primer lugar, intentemos crear un
‫nuevo usuario con estos datos aquí,
‫lo que no debería funcionar porque ya tenemos
‫un usuario con esta dirección de correo electrónico y dijimos que
‫este debería ser único y, por lo tanto,
‫no debería funcionar.
‫Bien, y por supuesto nuestro error de clave duplicada, ¿verdad?
‫Ahora bien, si estuvieras en producción,
‫entonces, por supuesto, ya obtendríamos nuestro error de formato
‫agradable que creamos en la última sección, ¿verdad?
‫Pero ahora mismo estamos en desarrollo y ese es el error que
‫definimos que queremos ver.
‫¿Okey?
‫Entonces, simplemente usemos otro correo electrónico aquí y, dado
‫que estamos trabajando en el correo electrónico
‫aquí, también veamos cómo funciona la validación de la dirección de correo electrónico.
‫Entonces, digamos que especificamos esto como nuestro correo electrónico.
‫Entonces, vemos el error, "proporcione un correo electrónico válido. " ¿Okey?
‫Así que probémoslo así porque creo que esto
‫tampoco debería ser válido.
‫Quizás lo sea, pero veamos.
‫Y sí, en realidad no es
‫porque no haya nombres de dominio con una sola letra, ¿de acuerdo?
‫Entonces, este validador es bastante específico, por lo
‫que es realmente bueno.
‫Ahora bien, si lo hacemos así, por supuesto que debería funcionar.
‫Pero de todos modos, lo que
‫queríamos probar aquí son estas contraseñas diferentes, ¿de acuerdo?
‫Y ahora recuerdo que
‫en realidad no creamos un mensaje de error, creo.
‫Y sí, no lo hicimos.
‫Y entonces, agreguemos eso aquí también.
‫Entonces mensaje,
‫no es lo
‫mismo.
‫Bueno.
‫Así que agreguemos algo aquí, no importa.
‫Y ahora, las contraseñas no son las mismas, ¿de acuerdo?
‫Tan perfecto.
‫Y ahora, por supuesto, nuestra validación debería aprobarse.
‫Y de hecho, lo es y creamos nuestro nuevo usuario.
‫Vayamos a Compass aquí,
‫echemos un vistazo y luego elimínelo para
‫que luego pueda crear más usuarios con el mismo correo electrónico.
‫¿Está bien?
‫Y no queremos toda esta basura aquí de
‫todos modos, así que todos estos usuarios de prueba, ¿de acuerdo?
‫Pero ahora, el siguiente paso es cifrar estas contraseñas simples
‫que estamos almacenando en nuestra base
‫de datos en este momento.
‫Entonces, como mencioné en el último
‫video, cuando trabajamos con
‫autenticación, uno de los principios más
‫fundamentales es nunca almacenar contraseñas simples en una base de datos, ¿de acuerdo?
‫Entonces eso es algo que no es absolutamente aceptable, ¿de acuerdo?
‫Así que siempre deberíamos cifrar las contraseñas de los usuarios porque imagina
‫que, por alguna razón, un
‫pirata informático obtiene acceso a la base de datos.
‫Si luego las contraseñas se almacenan en texto sin formato, entonces
‫puede simplemente iniciar sesión como cualquier usuario y
‫luego hacer lo que realmente quiera
‫y causar mucho daño en algunos casos, ¿de acuerdo?
‫Y, por lo tanto, debemos evitarlo absolutamente.
‫Y entonces, sigamos adelante e implementemos esto.
‫Ahora bien, ¿cuál es el mejor lugar para hacer eso?
‫Bueno, yo diría que el modelo es siempre el mejor
‫lugar para hacer este tipo de funcionalidad.
‫Entonces, en este caso, el cifrado porque
‫realmente tiene que ver con los datos en sí, por
‫lo que debería estar en
‫el modelo y no en el controlador, ¿de acuerdo?
‫Así que, de nuevo, tenga en cuenta la filosofía de los
‫modelos gordos y los controladores delgados.
‫¿Está bien?
‫Entonces, ¿cómo vamos a implementar ahora este cifrado?
‫Bueno, este es otro caso de uso
‫perfecto para usar el middleware Mongoose.
‫Y el que
‫usaremos es un middleware pre-guardado.
‫Básicamente, documente el middleware, ¿de acuerdo?
‫Entonces, recuerde que lo definimos en el esquema, ¿de acuerdo?
‫Y en este caso, queremos establecer
‫un pre-hook, entonces un pre-middleware al guardar, ¿de acuerdo?
‫así que un pre-middleware para guardar, ¿de acuerdo?
‫Y la razón por la que lo
‫estamos haciendo así es
‫que la función de middleware que vamos a especificar aquí,
‫por lo que el cifrado, ocurrirá entre el
‫momento en que recibimos esos datos y el
‫momento en que realmente persisten en el base de datos, ¿de acuerdo?
‫Ahí es donde se ejecuta el middleware de pre-guardado.
‫Entre obtener los datos y guardarlos en la base de datos.
‫Y ese es el momento perfecto para manipular los datos.
‫¿Está bien?
‫Entonces,
‫una función, y luego recuerde que tenemos acceso
‫a la siguiente función para llamar al siguiente middleware.
‫Bien, ahora solo queremos cifrar la contraseña
‫si el campo de contraseña se ha actualizado, ¿de acuerdo?
‫Entonces, básicamente, solo cuando realmente se cambia la contraseña o también
‫cuando se crea una nueva, ¿de acuerdo?
‫Porque imagina que el usuario solo está actualizando el correo electrónico.
‫Entonces, en ese caso,
‫por supuesto, no queremos volver a cifrar la contraseña, ¿verdad?
‫Y entonces podemos hacer eso con Mongoose.
‫Y entonces vamos a decir, si y luego esto, que
‫se refiere al documento actual, ¿verdad?
‫Y así, en este caso, al usuario actual
‫y luego se modifica.
‫¿Okey?
‫Entonces tenemos un método en todos los documentos que podemos
‫usar si se ha modificado cierto campo.
‫Y aquí, necesitamos pasar el nombre del campo,
‫entonces "contraseña. " ¿Okey?
‫Básicamente, lo que queremos hacer aquí
‫es decir que si la contraseña no ha sido modificada,
‫entonces no, en ese caso, simplemente regresemos de esta
‫función y no ejecutemos ninguno de los otros códigos
‫que están aquí y luego
‫llamemos el próximo middleware.
‫¿Okey?
‫De nuevo, si la contraseña no se ha modificado,
‫salgamos de esta función
‫y llamemos al siguiente middleware.
‫De lo contrario, ejecutaremos el código
‫que voy a poner aquí.
‫Y ahora finalmente es el momento de
‫cifrar, o como también podemos decir, de hash la contraseña, ¿de acuerdo?
‫Entonces verá el término "hash" o "hash" todo
‫el tiempo y eso básicamente significa cifrado también, ¿de acuerdo?
‫Ahora vamos a hacer este cifrado, o
‫hash, utilizando un algoritmo hash
‫muy conocido, bien estudiado y muy popular llamado bcrypt.
‫¿Okey?
‫Entonces, este algoritmo primero saltará y luego codificará nuestra contraseña
‫para que sea realmente fuerte para protegerla contra
‫ataques de fuerza bruta, ¿de acuerdo?
‫Y esa es la razón
‫por la que el cifrado debe ser realmente sólido.
‫Porque los ataques de fuerza bruta
‫podrían intentar adivinar ciertas contraseñas si no están realmente cifradas.
‫Y recuerde cómo dije que bcrypt eliminará nuestra contraseña y
‫eso solo significa que agregará una cadena aleatoria
‫a la contraseña para que dos contraseñas iguales no
‫generen el mismo hash, ¿de acuerdo?
‫¿Tener sentido?
‫Ahora no voy a entrar en todos los detalles criptográficos
‫sobre cómo funciona esto realmente entre bastidores
‫y por qué necesitamos un sistema tan complejo, ¿de acuerdo?
‫Pero, por supuesto, puede leer todo lo que quiera sobre bcrypt en línea.
‫Realmente hay un montón de cosas interesantes
‫por descubrir allí, ¿de acuerdo?
‫De todos modos, sigamos adelante y usemos el paquete
‫bcrypt js para usar este algoritmo.
‫Entonces, entonces
‫npm install
‫entonces npm install
‫bcryptjs.
‫¿Okey?
‫Y esto básicamente es una implementación bcrypt
‫para Javascript.
‫¿Okey?
‫Regresemos a nuestra terminal principal y luego
‫sigamos adelante e importémoslo aquí.
‫Y este solo se llama por defecto bcrypt, ¿de acuerdo?
‫Y no bcryptjs.
‫(clic del teclado) Muy
‫bien.
‫Está bien.
‫Y ahora, usémoslo realmente.
‫Entonces, queremos decir que esta contraseña de punto, por lo
‫que la contraseña actual en este
‫documento debe ser igual a bcrypt dot hash
‫debe ser igual a bcrypt dot hash y
‫luego nuestra contraseña actual.
‫¿Okey?
‫Y luego aquí necesitamos especificar un parámetro de costo, ¿de acuerdo?
‫Y en realidad podríamos hacer esto de dos formas.
‫Entonces, la primera forma será generar manualmente la sal, de
‫modo que esa cadena aleatoria básicamente
‫se agregue a nuestra
‫contraseña y luego use esa sal aquí en esta función hash.
‫¿Está bien?
‫Pero en cambio, para hacerlo un poco
‫más fácil, también podemos simplemente pasar un parámetro de costo
‫a esta función aquí.
‫Y eso es básicamente una
‫medida de cuán intensiva será la CPU esta operación, ¿de acuerdo?
‫Y creo que el valor predeterminado aquí es 10, pero
‫ahora mismo es un poco mejor usar 12 porque las
‫computadoras se han vuelto cada vez más poderosas.
‫Entonces, como hace 20 años, podría haber usado ocho
‫aquí y luego un poco más tarde
‫que 10, pero ahora mismo, en este momento, es mejor usar 12.
‫Entonces, cuanto más alto
‫sea este costo aquí, básicamente, más CPU será
‫el proceso y mejor se cifrará la contraseña, ¿de acuerdo?
‫Y, por supuesto, podríamos ir
‫aún más alto, pero luego tomaría demasiado tiempo, ¿de acuerdo?
‫Y te lo mostraré en un segundo.
‫¿Okey?
‫Pero por ahora,
‫terminemos esto porque queda una cosa aquí.
‫Entonces, este hash aquí es en realidad la versión
‫asincrónica, pero también hay una versión sincrónica.
‫Pero como ya sabe, no queremos usar
‫la versión síncrona
‫porque eso bloqueará el bucle de eventos y luego evitará
‫que otros usuarios usen la aplicación.
‫Así como aprendimos al principio.
‫Y entonces, por supuesto,
‫queremos usar la versión asincrónica que es esta.
‫Y esto luego devolverá
‫una promesa y esa promesa, por supuesto, debemos esperar.
‫Entonces, necesitamos usar await y luego decir que esta función
‫es una función asíncrona, como esta.
‫Entonces, recapitulemos eso aquí.
‫Por lo tanto, queremos configurar nuestra contraseña
‫actual básicamente para cifrar esta versión de la contraseña original con un costo
‫de 12, no para que sea
‫demasiado fácil romper la contraseña, pero también para que la aplicación
‫no tarde demasiado en cifrar la contraseña. ¿está bien?
‫Entonces, con esto, encriptamos nuestra contraseña y
‫ahora, al final, lo que tenemos
‫que hacer es básicamente eliminar la contraseña de confirmación, ¿de acuerdo?
‫Porque en este momento,
‫solo tenemos la contraseña real hash, ¿verdad?
‫Entonces, esta contraseña de punto confirma,
‫Entonces, esta
‫contraseña de punto confirma, y cómo básicamente
‫eliminamos el campo, para que no persista en
‫la base de datos es establecerlo como indefinido.
‫¿Está bien?
‫Entonces, realmente solo necesitamos esta contraseña confirmada aquí
‫para la validación que implementamos antes.
‫Así que solo para asegurarse
‫de que el usuario haya ingresado dos
‫contraseñas iguales para que no cometa ningún error con su contraseña.
‫¿Derecha?
‫Entonces, después de que esta validación fue
‫exitosa, en realidad ya no necesitamos este campo, por
‫lo que realmente no queremos conservarlo en la base de datos.
‫Y es por eso que simplemente lo configuramos aquí como indefinido.
‫¿Está bien?
‫Ahora puede preguntarse por qué funciona
‫esto porque en realidad establecemos la confirmación de
‫contraseña como obligatoria, ¿verdad?
‫Pero eso simplemente significa que es una entrada requerida, no
‫que se requiera que se conserve en la base
‫de datos, ¿de acuerdo?
‫a la base de datos, ¿de acuerdo?
‫Ahora, solo para terminar, por supuesto, también debemos llamar a continuación.
‫¿Okey?
‫Vamos a salvarlo.
‫Y de hecho, voy a agregar algunos
‫comentarios aquí para que quede muy claro para ustedes.
‫Entonces, básicamente, lo que hace es ejecutar esta
‫función
‫solo si la
‫contraseña se modificó realmente.
‫Luego, aquí,
‫hash la contraseña con un costo de 12.
‫Y luego,
‫elimine el campo de confirmación de contraseña.
‫Bueno.
‫Y ahora, probemos esto.
‫Y ahora crearé un nuevo usuario con exactamente estos datos
‫y ahora echemos un vistazo al resultado.
‫Y de hecho, ahora obtenemos esta contraseña de aspecto muy extraño
‫que de hecho es la versión encriptada de pass1234.
‫Y también, como puede ver, la confirmación de contraseña ya no está aquí.
‫¿Okey?
‫Y así, así, ahora almacenamos a los usuarios de
‫forma segura en nuestra base de datos.
‫Permítanme ahora mostrarles cómo funcionará si, por
‫ejemplo, lo configuramos en 16 aquí.
‫Y necesito cambiar el correo electrónico aquí.
‫Y eso debería llevar mucho tiempo y no estoy
‫seguro de poder esperar.
‫Oh, en realidad tomó como cuatro segundos y medio.
‫Pero eso es demasiado, creo, ¿de acuerdo?
‫Entonces, volvamos a establecerlo
‫en 12
‫y eso debería ser mejor, ¿de acuerdo?
‫Y ahora, de nuevo, eliminemos
‫estos usuarios aquí que acabamos de crear.
‫Y, de hecho, necesito deshacerme de
‫este primero porque todavía tiene la contraseña en texto sin formato.
‫Por lo tanto, este usuario
‫no funcionará cuando comencemos a iniciar sesión
‫en usuarios en función de su contraseña.
‫¿Okey?
‫Así que deshagámonos de esto.
‫¿Okey?
‫Y también lo que quería mostrarles
‫aquí es que pusimos exactamente la misma
‫contraseña para estos dos usuarios que creamos, ¿verdad?
‫Pero ves que la
‫contraseña encriptada es realmente muy diferente, ¿verdad?
‫Y ese es el poder de agregar sal a
‫la contraseña antes de aplicarla.
‫¿Está bien?
‫Así que, de nuevo, implementamos una gestión de contraseñas
‫muy segura y buena.