Transcripciones
1. Introducción: Bienvenido de nuevo al curso
Express Jazz, Modelo nueve, autenticación
y autorización. Mi nombre es ShenraRunhi, y seré tu instructor
para este A lo largo de los años, he tenido el privilegio de
crear sistemas backend seguros y
escalables para
una variedad de aplicaciones, y estoy aquí para compartir
mi experiencia con usted Uno de mis mejores proyectos
consistió en diseñar un sistema de autenticación de usuarios
para una plataforma de comercio electrónico, lo que mejoró significativamente
su seguridad y usabilidad. Hoy, aprenderás a construir algo
igual de impactante. En este módulo, estamos
profundizando en la autenticación
y autorización, dos aspectos críticos del desarrollo web
moderno. Así aprenderás a registrar usuarios de forma segura usando contraseñas
hash, autenticar usuarios
con webtkens JCN,
proteger
rutas sensibles con middleware
y, finalmente, implementar la autorización basada en
roles para administrar los permisos usuarios de forma segura usando contraseñas
hash,
autenticar usuarios
con webtkens JCN,
proteger
rutas sensibles con middleware
y, finalmente, implementar la autorización basada en
roles para administrar los permisos de usuario. Este conocimiento es crucial para asegurar cualquier aplicación
backend, y al final de este módulo, tendrá confianza en implementar estas
características en sus proyectos Por lo que este módulo está diseñado
para Bg en desarrolladores que quieran llevar sus
aplicaciones Express JS al siguiente nivel. Si has completado
los módulos anteriores, ya
estás listo para comenzar. conocimientos básicos de JavaScript, recomiendan conocimientos básicos de JavaScript,
no JS, y Monger
DB La autenticación y
autorización son las piedras angulares de cualquier aplicación web
segura Al dominar estos conceptos, no solo
construirás aplicaciones
más seguras,
sino que también aumentarás tu
valor como desarrollador Estos deben tener
habilidades para crear plataformas centradas en el
usuario
en el mundo tecnológico actual. Y por último, para el proyecto, integrarás
todo lo que hayas aprendido en la app
Fair Wheels. Entonces, más específicamente,
implementará funcionalidad de registro de
usuarios e
inicio de sesión, autenticará de
forma segura a los usuarios
usando tokens web JCN Aplicar autorización basada en roles para proteger rutas y recursos. Al final, tendrás un sistema de gestión de
usuarios seguro y escalable para la app Fair Wheels. Este módulo es un cambio de juego
para tu viaje de
desarrollo de Bend Así que construyamos
aplicaciones seguras juntas. Te veré en la primera
conferencia. Empecemos.
2. Autenticación y autorización: una introducción: Bien, así que volvamos a nuestra aplicación
Fair Wheels. Hasta ahora, hemos construido
estos endpoints de API. Así podemos administrar empresas, autos, clientes y alquileres. Ahora, casi todas
las aplicaciones que existen requieren algún tipo de
autenticación y autorización. Entonces en esta sección,
vamos a llevar esta
aplicación
al siguiente nivel e implementar la autenticación
y autorización. Entonces, antes de ir más lejos, quiero asegurarme de que
estamos en la misma página. Por lo que la autenticación
es el proceso de identificar si el usuario es
quien afirma ser. Ahí es cuando iniciamos sesión. Por lo que enviamos nuestro usuario y
contraseña al servidor, y el servidor nos autentica La autorización es determinar si el usuario tiene el permiso
adecuado para realizar la operación dada. Entonces, en nuestra aplicación Fair
Wheels, queremos asegurarnos de que
solo los usuarios autenticados
o solo los usuarios que hayan iniciado sesión
puedan realizar operaciones
que modifiquen los datos Entonces, si el usuario es anónimo, si no está conectado, solo puede leer datos
de estos endpoints Si quieren crear una nueva
compañía o actualizar un auto, primero
tienen que ser
autenticados Ahora como seguridad adicional, queremos asegurarnos de que solo los usuarios administradores
puedan eliminar datos. Entonces ese es un segundo
nivel de autorización. Estamos hablando de
permisos aquí. Entonces estos son los requisitos que vamos a implementar
en esta sección. Entonces, para hacer esto, necesitamos
agregar dos nuevos endpoints
a nuestra aplicación Primero, deberíamos
poder registrar usuarios. Para eso, vamos a
enviar una solicitud de post para que se corte
API slash USUARIOS porque publicamos, creamos nuevos recursos En este caso, un nuevo usuario. También deberíamos poder
iniciar sesión en un usuario, y eso se usa para la
autenticación. Ahora, aquí tienes una pregunta para ti. ¿Qué método SDDP debemos
usar para implementar el inicio de sesión? Porque con login,
no estamos creando un nuevo recurso. No estamos actualizando ni
eliminando uno existente. Entonces, ¿cómo podemos implementar
esto en términos de descanso? Este es uno de esos
escenarios que puedes encontrar frecuentemente en aplicaciones del mundo
real. A veces la operación con la que estás tratando no
tiene esa creación, lectura, actualización, eliminación semántica La forma en que modelizamos esto
en términos de descanso es refiriéndonos a esto
como petición o comando Entonces estás creando una nueva solicitud de inicio de
sesión o
un comando de inicio de sesión. En ese caso, usaremos post porque estamos
creando un nuevo recurso, así que barra barra API slash Logins Ahora en tu aplicación, tal vez quieras almacenar
todos los inicios de sesión en
la aplicación en una
colección separada en Mongo Así que puedes ver que usar post tiene mucho
sentido aquí. Pero incluso si no almacenas inicios de sesión
individuales y
solo quieres validar
el usuario y la contraseña, aún
puedes tratar
este recurso como recurso sesión y usar
post para crearlo Ahora, aquí tienes un ejercicio para ti. Quiero que implemente esta
API para registrar nuevos usuarios. Entonces para cada usuario, queremos tener
estas propiedades,
nombre, correo electrónico y contraseña. Además, al definir
su esquema para la propiedad email en
el objeto de tipo de esquema, establezca la propiedad unique en true. Entonces, cuando definimos el esquema, establecemos el tipo de correo electrónico a un objeto que es nuestro objeto de tipo de
esquema. Establecimos el tipo aquí en string y también establecemos unique a true. Entonces con esto, nos aseguramos de
que no almacenaremos dos documentos con el
mismo correo electrónico en Mongo Di B.
Bien. Así que adelante e implementa solo esta API
para registrar nuevos usuarios. Yo voy a hacer lo mismo
en la próxima conferencia.
3. Crea el modelo de usuario: Todo bien. Entonces primero, voy a definir
un nuevo modelo de usuario. Así que aquí en la carpeta de modelos
en un nuevo archivo usuario punto js. Ahora para ahorrar tiempo,
voy a ir a la compañía punto js y pedirme prestado
un código de aquí Así que copia de nuevo touserdtjs,
pegarlo aquí. Ahora en la parte superior, así
tenemos este esquema. Voy a definir esto mientras
llamo al método modelo. Realmente no hay necesidad en este caso de definir esto
como una constante separada. Entonces vamos a obtener este
objeto de esquema y agregarlo aquí. Y ahora podemos
deshacernos de este esquema. Bien, eso es mejor. Entonces ese es nuestro modelo. Deberíamos llamar a este usuario
constante. Y la colección correspondiente también
deben ser usuarios. Ahora aquí, tenemos la
propiedad name, que es una cadena. Se requiere, y es de
5 a 50 caracteres. Eso me
suena bien. A continuación, agreguemos el correo electrónico. Entonces voy a agarrar todo
esto bueno, duplicarlo. Y la segunda
propiedad es el correo electrónico. Entonces nuevamente, tenemos
estas propiedades. Me gustaría aumentar
la longitud máxima a 255 caracteres. Y además, como te dije
en la última conferencia, deberíamos agregar la
propiedad única para asegurarnos de que
no almacenamos dos usuarios con
el mismo correo electrónico en Manga Divi Y la última propiedad es Passwb. Entonces voy a copiar todo esto, duplicar y agregar esta propiedad de
contraseña. Ahora voy a establecer la longitud
máxima de las contraseñas a un valor mayor porque
vamos a hash
estas contraseñas. Y aquí no necesitamos
la propiedad única. Siguiente es nuestra función de validar. Entonces necesitamos renombrar
esto para validar usuario. Validar usuario que
toma un parámetro de usuario. Aquí tenemos nombre que es 5 a 50 caracteres,
y es obligatorio. Tenemos correo electrónico, que
debe tener 5-255 caracteres. Debe ser requerido.
Y aquí también llamamos al método de correo electrónico para
asegurarnos de que es un correo válido. Y por último, tenemos contraseña, que también es una cadena con mínimo cinco caracteres
y máximo, digamos, 255 según sea necesario. Entonces esta es la contraseña que el usuario envía en texto plano. Vamos a hash esto, que va a
ser una cadena más larga, y esa es la cuerda que
almacenaremos en Mongo TV Así que terminamos con nuestra función de usuario
válida. Ahora necesitamos exportar
nuestro modelo de usuario, así que no necesitamos la
primera declaración de exportación que sea para nuestro esquema delete. Aquí vamos a
exportar esto como usuario, y nuestra
función de validar también es buena. Hermoso. Así que terminamos
con nuestro modelo de usuario. En la próxima conferencia,
voy a agregar una ruta para registrar nuevos usuarios.
4. Registro de usuarios: Bien. Ahora vamos a crear una nueva ruta para
registrar nuevos usuarios. Entonces aquí en la carpeta rutas, voy a agregar un nuevo
archivo usuarios punto js. Ahora, una vez más, para ahorrar tiempo, voy a ir a
las empresas punto js y copiar estas
declaraciones requeridas así
como la segunda ruta
en nuestro nuevo módulo. Entonces copia, pégalo aquí. Nuevamente, copia la ruta del poste. Y pega aquí. Y por cierto, sólo
estoy haciendo esto porque no
quiero perder tu tiempo viéndome
escribir todo esto a mano. En el mundo real,
debes evitar enfoque de
copiar y pegar a menos que
seas muy cuidadoso y vayas a leer
cada línea
del código copiado para asegurarte de
que no cometiste un error. Siempre es mejor
escribir el código a mano. Ahora, hagamos cambios. Entonces, en la parte superior, necesitamos importar el
modelo de usuario en lugar de la compañía. Entonces a partir de modelos user, importamos la clase user, así
como la función
validate. También necesitamos Express y Router. Así que aquí está nuestra nueva ruta que se plantea para crear nuevos usuarios. Y por último, necesitamos
exportar este router. Así módulo dot Exportaciones. Ponemos esto a este router. Ahora, tenemos que volver a nuestro punto índice JS
y decirle a Express que para cualquier ruta que
comience con slash ABS SRS, deberíamos usar este router
que estamos exportando aquí Entonces vamos a Index o Js. En la parte superior, vamos a
importar este nuevo módulo. Usuarios tan constantes. Establecemos esto para requerir de
los usuarios de la carpeta rutas. Y entonces aquí llamamos
app que dan a nuestro path slash APAs Usuarios y nuestro
Router, es decir usuarios Bien, entonces hemos construido
el panorama general. Ahora, volvamos a nuestro
módulo de usuarios e implementemos
esta nueva ruta. Entonces aquí vamos a
validar la solicitud. Si no es válido,
vamos a devolver un error 400, que
es mala solicitud. De lo contrario,
vamos a crear un nuevo objeto de usuario y
guardarlo en la base de datos. Entonces vamos a mantener las dos primeras líneas
exactamente como están. Queremos validar la solicitud. Estamos utilizando nuestra función Joy
validate. Entonces, si las propiedades de nombre, correo electrónico o contraseña no
son válidas, vamos a devolver un error
400 al cliente. Ahora, a continuación, tenemos que hacer
otro tipo de validación. Quieres asegurarte de que este usuario no esté
ya registrado. Entonces llamamos usuario punto Fine one, pasar un objeto de consulta aquí. Estamos buscando usuario con un email dado que se
solicite dot body dot email. Así que tenga en cuenta que aquí, no
usé bien por
ID porque
no estamos buscando al
usuario por su ID. Los estamos buscando por
una de sus propiedades. Tan fino uno. Ahora esto
devuelve una promesa. Entonces lo esperamos y
obtenemos un objeto de usuario. Ahora bien, en este caso, estoy
definiendo una variable en lugar de una constante porque
vamos a restablecerla como
verás en un segundo. Entonces en este caso, si
tenemos este
objeto de usuario en la base de datos, debemos devolver un error de
solicitud incorrecta al cliente. Así que devuelve el estado del
punto de respuesta 400, que es mala solicitud punto ENVIAR y aquí está el mensaje
usuario ya registrado. Entonces en este punto, tenemos
un objeto de usuario válido. Este usuario no está registrado
en la base de datos, por lo que necesitamos guardar este
usuario en la base de datos. Entonces aquí, voy a restablecer este objeto de usuario porque en
este punto, debería ser no. Establecemos esto a un nuevo usuario, y aquí establecemos las propiedades. Entonces nombre establecemos esto para
solicitar cuerpo de punto, nombre de punto. Correo electrónico para solicitar
dot body dot email. Y contraseña para solicitar contraseña del cuerpo del
punto. Entonces este es nuestro objeto de usuario. Ahora lo guardamos. Así que espera, usuario punto guardar, y finalmente, devolver
esto al cliente. Entonces no necesitamos estas dos líneas para trabajar con la empresa. Eliminar. Y por último, devolver este nuevo usuario al cliente.
Ahora, vamos a probar esto. Así que de vuelta en Cartero, voy a enviar
una solicitud de correo a Local Host port 3,000
slash APAS Y luego en el cuerpo
de la solicitud, voy a establecer esto en Raw
y establecer el tipo en JSON. Aquí pasamos como objeto JSON
con tres propiedades, name, Shiv, luego configuramos email Voy a establecer
un correo electrónico no válido, y tampoco voy a establecer
la contraseña. Quiero asegurarme de que nuestra función
de
validación funcione correctamente. Así que envía. Bien,
tenemos un mal pedido. Eso es bueno. La longitud del nombre debe tener al menos cinco
caracteres. Así que déjame cambiar esto
a hewnder Bien. Ahora vamos a enviar otra solicitud. Tenemos otra mala solicitud. La longitud del correo electrónico debe tener
al menos cinco caracteres. Entonces cambiemos
esto a 12, tres, cuatro, cinco, seis, pero este no
es un correo válido. Entonces ahora deberíamos obtener
un error diferente. El correo electrónico debe ser un correo electrónico válido. Hermoso. Entonces cambiemos esto para probar 123 en regmil.com Et envía otra solicitud. Bien, ahora obtenemos
contraseña se requiere. Hermoso. Por último, agreguemos una contraseña que tenga al menos
cinco caracteres de largo. Entonces uno, dos, tres,
cuatro, cinco, Send. Esta vez obtuvimos una respuesta de 200. Hermoso. Y este es el objeto de usuario que
almacenaste en la base de datos. Por lo que tienes la propiedad de identificación
así como nombre, correo electrónico
y contraseña. Ahora, al registrar
un nuevo usuario, no
queremos devolver su
contraseña al cliente. Entonces eso es algo que
vamos a arreglar en la próxima conferencia. Pero enviemos otra solicitud con exactamente los mismos valores. Esta vez, deberíamos
obtener un error diferente, diciéndonos que el usuario ya
está registrado. Así que envía. Bien, tenemos
otra mala petición, y aquí está el mensaje. Usuario ya
registrado. Hermoso. Entonces en la próxima conferencia, vamos a modificar la
respuesta de esta API y punto.
5. Uso de Lodash: Así que de vuelta en nuestro método post, queremos modificar la
respuesta al cliente. Entonces aquí hay dos opciones. Un enfoque es devolver
un objeto personalizado como este, establecer el nombre en nombre
de punto de usuario y correo electrónico a correo electrónico de punto de usuario. Así que de esta manera, podemos excluir la contraseña y las propiedades de la
versión. Este enfoque está perfectamente
bien, pero en esta conferencia, voy a presentarte
una biblioteca útil que te
brinda muchas funciones de
utilidad para trabajar con objetos. Si eres un desarrollador experimentado de
JavaScript, probablemente sabrás de lo que estoy hablando. Esa es Lourdes. Así que dirígete a lodash.com. Esto es lodash, que es básicamente la
versión optimizada del guión bajo El subrayado ha
existido desde hace mucho tiempo. Tiene una gran cantidad de motores de utilidad
para trabajar con objetos, cadenas, matrices, y así sucesivamente. Entonces, si nos fijamos en
la documentación, aquí podemos ver todas
las funciones de utilidad que tenemos para trabajar
con varios tipos. Tenemos muchas funciones de
utilidad para trabajar con matrices, números, cadenas,
objetos, etc. Entonces lodash es extremadamente poderoso. Y en esta conferencia,
te
voy a mostrar cómo usarlo en
tu aplicación de nodo. Así que de vuelta en la terminal,
NPM instala lodash. Así que tenga en cuenta que la
versión actual estoy usando 4.17 0.21. Todo bien ahora de vuelta en el código. Entonces aquí en nuestro
modelo de usuario en la parte superior, voy a importar Lodash Por lo que requieren Lodash. Ahora por convención, almacenamos el resultado en una constante
llamada guión bajo esto se le puede llamar cualquier cosa, se puede llamar a esto Lodash, pero por convención, usamos subrayado porque
eso es corto y limpio Ahora bien, este
objeto de subrayado que
tenemos aquí tiene un método de
utilidad llamado pick so underscore dot Le damos un objeto a esto. En este caso, nuestro objeto de usuario, y luego pasar una matriz
de propiedades en este objeto de usuario que
queremos elegir. Y esto
devolverá un nuevo objeto con solo esas propiedades. Así que aquí en esta matriz, voy a pasar
nombre y correo electrónico. Entonces, cuando llamamos a
este método pick, obtendremos un nuevo objeto con estas dos propiedades,
name y email. Ahora en lugar de
repetir manualmente el punto de usuario, podemos usar este método Pi. Eso es más elegante. Entonces podemos reemplazar este objeto aquí con lo que obtenemos
del método PI. Tan simple como eso.
Ahora, quizás aquí, es posible que desee incluir también
la propiedad IR. Entonces así es como
usamos el método PIC. De igual manera, podemos
modificar este código, y en lugar de repetir
solicitar punto cuerpo punto, solicitar punto cuerpo punto, solicitar punto cuerpo punto
con guión bajo punto PIC Entonces voy a
reemplazar este objeto con guión bajo punto cerdo Le dimos solicitud punto py. Ahora aquí, podríamos
tener 50 propiedades. Un usuario malintencionado puede
enviarnos propiedades para ser
almacenadas en la base de datos. Sólo queremos
escoger a mano algunos de estos. Entonces pasamos una matriz. Solo nos interesa el
nombre, el correo electrónico y la contraseña. Bien, entonces creamos
el usuario y
lo guardamos y luego devolvemos este objeto
personalizado al cliente. Probemos esto una vez más para asegurarnos de que
todo está funcionando. Entonces terminal backend. Ejecutemos la aplicación. Hermoso. Ahora de vuelta
en el Cartero Voy a enviar una nueva solicitud
a través del servidor. Enviar. Bien, aquí está nuestro
nuevo objeto de usuario. Solo tenemos identificación,
nombre y correo electrónico. Ahora en todas estas
solicitudes hasta el momento, he enviado contraseñas realmente
simples. Si quieres hacer cumplir la complejidad de la
contraseña, hay un paquete NPM
construido sobre
Joy llamado Joi
password Complexity Joy llamado Joi
password Así que de vuelta en Google busca
Joy contraseña Complejidad. Ese es el paquete NPM. Entonces con esto, puedes
configurar un objeto que determine la
complejidad de la contraseña en tu aplicación. Número mínimo de
caracteres, máximo, cuántos más bajos como o
mayúsculas quieres tener, cuántos números, y así sucesivamente. Entonces el nombre del paquete
es Joy password complexity. En este curso, no vamos
a usar esto porque eso es algo que puedes
hacer por tu cuenta. Bien, nuestro nuevo
punto final API está en buena forma, pero estamos almacenando nuestras
contraseñas como texto plano, y esto es muy, muy malo. Entonces, en la próxima conferencia, voy a mostrarte
cómo hash estas contraseñas.
6. Cómo usar hash de contraseñas: En esta conferencia,
te
voy a mostrar cómo hacer hash de contraseñas. Para ello, vamos a utilizar una biblioteca muy popular
llamada B crypt. Entonces aquí en la terminal, vamos a instalar B crypt. Instalar. Tenga en cuenta la
versión que estoy usando. Esa es la versión 5.1 0.1. Ahora aquí, voy a
crear un archivo de playground, así aprenderás a trabajar
con esta biblioteca BCRP, y luego vamos a
tomar ese código y ponerlo en una ruta para hacer hash la
contraseña de los nuevos usuarios Así que vamos a crear un nuevo
archivo, hash dot js. En este archivo, primero, necesitamos cargar BCRP Esto conserva un objeto. Lo almacenamos aquí. Cripta B. Ahora para tener una contraseña, necesitamos una sal. ¿Qué es una sal? Bueno, imagina que nuestra contraseña
es uno, dos, tres, cuatro. Cuando lo hash,
imaginemos que obtendremos
una cadena como esta. Ahora bien, este
algoritmo hash es de una manera. Entonces si tenemos A, B, CD, no
podemos descifrar esto y
obtener uno, dos, tres, cuatro Entonces, desde el punto
de vista de la seguridad, eso es genial. Si un hacker
mira nuestra base de datos, no puede descifrar
estas contraseñas hash. Sin embargo, pueden
compilar una lista de contraseñas
populares y hash de ellas. Y luego podrán mirar la base de datos de nuestra aplicación. Encuentran esta contraseña hash, y saben que ABCD
representa uno, dos, tres, cuatro Entonces por eso necesitamos una SAL. Como SALT es básicamente una cadena aleatoria que se agrega antes o
después de esta contraseña. Por lo que la
contraseña hash resultante será diferente. Cada vez basado en
asalto que se utilice. Bien, déjame
mostrarte esto en acción. Entonces aquí llamamos punto
cripta B Gen SLT. Tenga en cuenta que este método
tiene dos versiones. El primero es asíncrono. El segundo es sincrónico. Como mejor práctica, siempre
debes usar métodos
asíncronos porque como te
dije al
inicio del curso, en aplicaciones de nodo,
tenemos un solo hilo No queremos mantener ocupado
ese hilo porque entonces no podemos
atender a otros clientes. Entonces llamamos a GensLT
como argumento. Pasamos el número de ceños fruncidos. Queremos ejecutar este algoritmo
para generar el SLT. Cuanto mayor sea
el número, más tiempo
va a tardar en
generar la sal. Y también el SOT
será más complejo y
más difícil de romper. Entonces el valor predeterminado es diez. Vamos a usar eso ahora porque se trata de un método
asíncrono. Podemos o bien pasar
callback aquí, y eso es lo que ves en
su documentación oficial, así
como una gran cantidad de
tutoriales en la web Pero este método también tiene una sobrecarga que
devuelve una promesa. Entonces, en lugar de
pasar una devolución de llamada, obtenemos una promesa, la esperamos y luego obtenemos la sal Entonces ahora necesitamos envolver esto en una función acing como run. Bien, entonces bloqueemos esta
sal en la consola. Y finalmente, llamemos a
esta función run. Ahora, de vuelta en el nodo
terminal tiene que Js. Entonces este es un ejemplo de sal. Se puede ver el número de rondas que utilizamos incluidas en la sal. Entonces, si usamos 20 aquí en vez
de diez, tendríamos 20. Así que aquí tenemos una
larga cadena aleatoria que se incluye como parte
del hash de nuestras contraseñas Y con esto, cada vez que hash nuestra contraseña
con un nuevo Salt, obtenemos resultados diferentes. Entonces ahora que tenemos un Salt, podemos usar esto para
hash nuestra contraseña. Tenemos otro método aquí en este objeto cripta B
que es hash. Entonces le damos nuestros datos. Imaginemos que nuestra
contraseña es uno, dos ,
tres, cuatro, y
dale la sal. Y nuevamente, mira, el tercer
argumento puede ser una devolución de llamada. No vamos a usar esto. En cambio, vamos a obtener la promesa que se
devuelve de este método. Entonces esperamos esa promesa y
obtenemos la contraseña hash. Así que ahora vamos a registrar esto
en la consola también. Hashed. Bien, de vuelta en el nodo
terminal, hashed o chase Bien, mira, en la primera
línea, tenemos nuestra sal. En la segunda línea, se puede
ver la sal aquí también. Por lo que el SALT está incluido
en la contraseña hash. La razón por la que esto se incluye es porque más adelante cuando queremos
autenticar al usuario, queremos validar su
nombre de usuario y contraseña Entonces ahí el usuario envía una
contraseña en texto plano. Necesitamos volver a hash, pero necesitamos tener
la sal original que se utilizó para
generar este hash. Entonces, al comparar la contraseña de
texto plano con la contraseña hash, B crypt necesita conocer la sal original que se
usó para hash la contraseña Entonces ahora que ya sabes
cómo funciona B Crypt, tomemos estas dos líneas
y las pongamos en
nuestro manejador de rutas Así que córtelos de aquí. Vamos a los usuarios punto js. Bien, aquí está nuestro objeto de usuario. Pasemos esas líneas aquí. Entonces generamos una sal, y luego necesitamos que
tenga la contraseña. En lugar de uno,
dos, tres, cuatro, vamos a usar la contraseña de punto de
usuario. Esa es una contraseña de texto sin formato. Entonces lo hash con una
sal y luego lo restablecemos. Entonces usuario punto contraseña. Ahora en la parte superior, también
necesitamos importar cripta B, tan constante cripta B. Establecemos esto para que requiera Bcrypt. Ahora, aquí en Compass, quiero eliminar la colección del
usuario porque todos los usuarios que
tenemos hasta ahora, tienen contraseña de texto plano. Así que borra. Todo bien. Ahora de vuelta en la terminal, ejecutemos Node mod. Y luego aquí en Cartero, vamos a
enviar una nueva solicitud S. Hermosa. Entonces aquí tenemos un nuevo usuario. Ahora de vuelta en Compass, vamos a refrescar la lista. Tenemos la colección del usuario, y aquí está nuestro nuevo usuario
con una contraseña hash Hermoso. Por lo que hemos implementado este punto final
para registrar nuevos usuarios. Ya terminamos aquí. A continuación, vamos a ver cómo
autenticar a los usuarios
7. Autenticación de usuarios: Bien, así que aquí en
la carpeta rutas, agreguemos un nuevo archivo. A esto lo llamamos
dojs de inicio de sesión o auth dot js. O funciona, pero la
auth es más común. Así auth Js. De nuevo, ahorras tiempo, voy a pedir prestado algún código Así que vayamos a los usuarios punto js. Voy a copiar todo el código que escribimos en esta sección, y luego pegaré en auth dot js Ahora antes de
entrar en los detalles, vamos al punto índice JS. En el grifo, importe
este nuevo módulo. Entonces Cs OT, configuramos esto
para requerir rutas OT. Entonces, si tenemos alguna solicitud
a este punto final, slash API OT o uno de
sus endpoints secundarios, vamos a delegar
esto al router OT Entonces el panorama general está hecho. Ahora veamos los detalles. Así que de vuelta en el módulo Auth, en la parte superior, primero, necesitamos validar el
cuerpo de la solicitud Pero esta
función validar la tenemos aquí, esta es la que
importamos de nuestro módulo de usuario. Entonces esto está validando eso. En el cuerpo de la solicitud, tenemos tres propiedades,
nombre, correo electrónico y contraseña. Y en la aplicación
del mundo real, es posible que tengas otras propiedades como parte del registro de un usuario. Por lo que esta función de validar es
para validar a un nuevo usuario. No es para validar
el correo electrónico y la contraseña que esperamos
en este punto final Entonces aquí necesitamos una función de
validación diferente. Así que voy a quitar esta función de
validar de aquí y definir una
función de validación separada en este módulo. Ahora para ahorrar tiempo,
voy a ir al módulo de
usuario y copiar
esa función de validar. Así que tenemos usuario validado. Vamos a copiar esto de nuevo
al módulo Auth, pegarlo aquí, y luego
cambiarlo para validar Ahora podemos cambiar el
parámetro a solicitar. Ahora para este objeto de esquema, solo
necesitamos dos propiedades,
correo electrónico y contraseña. Entonces, eliminemos el
nombre y ya terminamos. Así que volviendo a nuestro manejador de rutas, esta es nuestra primera validación A continuación, debemos asegurarnos que tenemos un usuario
con un correo electrónico determinado. Entonces cargamos al usuario. Si no tenemos el usuario, así que aquí aplicamos
el operador not. Si no tenemos el usuario, debemos enviar un
error 400 al cliente, lo que significa que esa solicitud
y el mensaje debe ser correo electrónico o contraseña no válidos. Tenga en cuenta que aquí, no estoy
enviando un cuatro o cuatro, lo que significa que no se encuentra
porque no queremos
decirle al cliente por qué falla la
autenticación. No queremos
decir si este correo electrónico es correcto o la contraseña. Entonces no queremos decir que
no tenemos un usuario
con un correo dado. Nosotros solo le decimos al cliente
que esta es una mala solicitud. No tiene los
datos correctos para ser procesados. Entonces esto es para validar el nombre de usuario y
correo electrónico en este caso A continuación, necesitamos
validar la contraseña. Para eso, necesitamos usar BCRP. Entonces, eliminemos todo este código. Este objeto cripta B que
tenemos tiene un método de comparación. Usamos esto para comparar una contraseña de texto sin formato
con una contraseña hash Entonces nuestra contraseña de texto plano está en la solicitud de contraseña de punto
cuerpo punto, y nuestra contraseña hash está
en el usuario esa contraseña. Entonces, como viste antes, esta contraseña hash
sí incluye el SLT Entonces cuando llamamos al método
compare, B crypt va
a obtener esa sal y usarla para descansar esta contraseña de
texto plano. Si son iguales, entonces
esto volverá cierto. Entonces aquí tenemos que esperar esta promesa y almacenar el
resultado aquí en contraseña válida. Ahora bien, si la contraseña no
es válida, nuevamente, vamos a
devolver un error 400 con ese mensaje vago, correo electrónico
no válido o contraseña Entonces solo voy a copiar
esto y pegarlo aquí. Y finalmente, si llegamos
esto a este punto, eso significa que este
es un login válido. Entonces por ahora, solo
quiero enviarle un valor simple, verdadero a la pelusa.
8. Prueba de la autenticación: Entonces, por ahora, probemos
esta ruta de autenticación. Antes de eso, así un de punto js. Aquí, olvidé
mencionar la alegría de carga. Entonces déjenme hacer esto rápidamente. Last Joy, establece esto
para que requiera de Joy. Bien. Y en la parte inferior
para validar la función, aquí necesitamos devolver
el esquema dot validate request. Bien, entonces ya estamos todo listo. Vamos a abrir postmin. Entonces aquí voy
a abrir una nueva pestaña. Seleccionemos post aquí. Déjame escribir el punto final. Es TP, host local OT, API OT. Y en el cuerpo de solicitud, voy a mandar a la GSN fuera. Entonces déjame seleccionar Json aquí. Y ahora tenemos dos parámetros. Entonces, el primero es el correo electrónico. El correo electrónico que
hemos utilizado es un 23, cuatro, cinco, seis, siete, a la tasa gmail.com Y nuestra contraseña es uno, dos, tres, cuatro, cinco. Entonces déjame enviar esta solicitud, SN. Hermoso. Tenemos
un estatus 200. Bien. Y aquí está nuestra respuesta a través de. Ahora, permítanme cambiar
la contraseña aquí a otra
cosa como 67 y
luego volver a enviar la solicitud. Ver, tenemos una solicitud 400 mala
y el comando genérico, que es
correo electrónico o contraseña inválidos. Ahora cambiemos el correo electrónico a otra
cosa con
la contraseña correcta. Entonces algo como esto. Y déjenme volver a enviar la
solicitud. Así que envía. Ver, nuevamente, tenemos
una solicitud 400 mala y el mensaje genérico que es
correo electrónico o contraseña no válidos. Entonces nuestro
punto final de autenticación está funcionando bien. En la siguiente conferencia, vamos a ver la respuesta
que estamos enviando aquí y cambiarla a algo lo que llamamos token web
adyacente.
9. Tokens web JSON: Entonces tenemos un punto final
para autenticar a los usuarios. Ahora, necesitamos modificar
la respuesta aquí, y en lugar de
devolver un valor verdadero, necesitamos devolver
un token web JCN AJCN webtoken es básicamente una cadena larga que
identifica a un usuario Como metáfora,
puedes pensarla
como tu licencia de conducir
o tu pasaporte Es muy similar a eso. Entonces cuando el usuario inicia sesión
en el servidor, tiramos esta web de JCN tooken, que es como una
licencia de conducir o pasaporte, se la
damos al cliente
y luego le decimos, Oye, próxima vez que quieras volver aquí
y llamar
a uno de
nuestros puntos finales de API,
necesitas mostrar tu Necesitas mostrar tu
licencia de conducir. Esta es tu identificación. Entonces en el cliente, necesitamos
almacenar este token web JCN, que es una cadena larga, podamos enviarlo de vuelta al servidor para futuras llamadas a la API Ahora, el cliente puede ser una aplicación web o
una aplicación móvil. Si se trata de una aplicación web, si estás construyendo una aplicación
con angular o react, puedes usar almacenamiento local. Ese es un lugar
de almacenamiento especial que está disponible en todos los
navegadores que existen. Si estás construyendo una aplicación móvil, tienes una opción similar dependiendo de qué
plataforma uses. Entonces ahora déjame mostrarte un
ejemplo de AjcnWbtken. Dirígete sobre tojwt dot IO. En este sitio web, aquí tenemos un depurador para trabajar
con JS y WebTkens Entonces aquí en la sección codificada, se
puede ver un ejemplo real
de AJCN Web tooken Esta cadena larga que ves en la
sección codificada representa un JCNoBr así que cuando decodificemos esto, obtendremos ¿Bien? Ahora podemos ver que
esta cadena tiene tres partes, y cada parte es código de color. Entonces la primera parte es roja, la segunda parte es morada, y la tercera parte es azul. En el lado derecho, se puede
ver esta cadena decodificada. Entonces la parte roja es lo que
llamamos el encabezado de
un token web JCN En esta cabecera,
tenemos dos propiedades. Uno es L, que es la
abreviatura de algoritmo que determina el algoritmo utilizado para codificar este token. El tipo es GWT, que es el token web JCN Ahora nunca tenemos que
preocuparnos por este encabezado. Es sólo un estándar. Lo que nos importa
es la segunda parte, la carga útil, que
es la parte morada. Entonces aquí tenemos un objeto JCN
con tres propiedades,
sub, que es como un
ID de usuario, nombre y Admin Ahora bien, la carga útil que ves es diferente a
la carga útil que tengo porque he modificado el fold JS y webtog y
está en este Entonces generé un token
web personalizado, póngalo aquí. Lo que quiero
señalar aquí es que esta carga útil incluye
propiedades públicas sobre el usuario. Al igual que en tu pasaporte, tienes algunas propiedades
sobre ti, como tu nombre,
tu fecha de nacimiento, tu lugar de nacimiento, y así. Así que tenemos exactamente el mismo
concepto ren adyacente web token. Puede incluir algunas
propiedades públicas básicas sobre el usuario. Y con esto, cada vez que enviamos un token del
cliente al servidor, podemos extraer fácilmente el ID de
usuario de la carga útil. Si necesitamos saber
el nombre del usuario, entonces simplemente podemos
extraerlo aquí también. No tenemos que
consultar la base de datos, enviar este ID para
obtener un objeto de usuario y luego extraer
la propiedad name. De la misma manera,
si quieres saber si el usuario es un usuario
administrador o no, podemos incluirlo aquí. Entonces nuevamente, no tenemos que
enviar una consulta extra a la base de datos para ver si el usuario con un
ID dado es admin o no. Ahora podría estar preocupado por este enfoque desde el punto de vista de la
seguridad, porque puede pensar que
cualquiera puede simplemente establecer esta propiedad admin
por sí mismos en true, y luego serán tratados
como admin en el servidor. Pero no es así como funcionan los ptocanos de
Jason. La tercera parte de
este token Web JCN, que está en azul, es
una firma digital Esta firma digital se
crea a partir del contenido de este JCN WebTKEN junto con
una clave secreta o privada La clave secreta o privada solo
está disponible en el servidor. Entonces, si un usuario malintencionado obtiene el JCN WebTKEN y modifica
la propiedad admin, la firma digital no
será válida porque se modifica el contenido del
JCN Ahora necesitamos una nueva firma
digital, pero el hacker no puede generar esta firma digital
porque necesitarán la clave privada, que solo está disponible
en el servidor. Entonces, si no tienen
acceso al servidor, no
pueden crear una firma digital
válida. Y cuando envíen este token Web JCN
templado al servidor, el servidor declinará eso El servidor dirá, este
no es un token web JCN válido. Entonces así es como funcionan los tokens
Web JCN.
10. Generación de tokens de autenticación: Entonces en esta página, si
miras las bibliotecas, aquí encontrarás
diferentes módulos o bibliotecas para
diferentes plataformas. Entonces, si te
desplazas hacia abajo, verás que tienes Tad net one C B, C, C plus, node, y así sucesivamente. Entonces abramos el terminal
e instalemos JCN webtook y BM e instalemos ASN Bien, si miras
el paquete un JSON, verás que la versión que
estamos usando es 9.0 0.2. Entonces vamos a cerrar esto. Tenemos la ruta para
autenticar a los usuarios. Ahora, necesitamos crear un JCN WebTKEN antes de enviar una
respuesta al cliente Entonces antes de eso, necesitas
cargar JCN WebTKEN. Entonces en la parte superior,
requieren Jason rep, estrangularlo y almacenarlo en
una constante llamada JWT Genial. Ahora aquí, usaremos el método
sinusoidal de JWT. Entonces JW punto seno por lo que
aceptará dos argumentos. primero es la carga útil y el segundo es el rey
secreto o privado. Entonces la carga útil podría
ser una cadena simple o podría ser un objeto como
el que ves aquí. Entonces hagamos nuestro objeto
con una sola propiedad. Incluiremos ID de subrayado, y lo enviaremos al ID de subrayado de punto de
usuario Ahora, según el segundo argumento, enviaremos esto a una cadena. Pero idealmente, no
deberías almacenar tu
clave secreta o privada en tu código fuente. Posteriormente, te mostraré cómo almacenar esto en un
ambiente donde o. pero por ahora,
pongamos esto en secreto de JWT No necesita
ser clave secreta JWT. Podría ser cualquier cosa,
cualquier cuerda. Pero por ahora, usemos esto. Entonces hemos utilizado un método de signo, y como resultado, obtenemos un token. Así que vamos a almacenarlo en constante
y lo llamaremos token. Y ahora regresaremos o enviaremos la respuesta
a nuestro cliente como gancho. Entonces hay esto de vuelta
a la terminal. Vamos a correr hacia abajo. Ahora, vamos a cartero. Aquí le enviaremos el correo electrónico y contraseña
correctos a esta
ruta de autenticación. Entonces vamos a mandar esto. Y aquí está nuestro token web JCN. Entonces déjame copiar esto. Y volvamos
al depurador. En esta sección codificada, solo
puedes eliminar esta y pegar la
que copiamos. Y aquí, en la sección
decodificada, puedes ver nuestro objeto
que enviamos como token así aquí
tenemos la propiedad ID,
que se establece en el ID del objeto en la base de
datos de Mongaim Y además,
tenemos IAT que es la hora actual y la hora en la que se crea este token Esto se utiliza para H el token. Por lo que hemos creado con éxito el token y lo enviamos
como respuesta a nuestro clima. En el siguiente video, te
mostraré cómo incluir esta clave secreta en
una variable de entorno.
11. Almacenamiento de secretos en variables de entorno: Anteriormente en el curso, cuando hablaba de temas avanzados
Express, te
presenté un
paquete de nodos llamado Config. Utilizamos este paquete para almacenar los
ajustes de configuración de nuestra aplicación en archivos JSON
o variables de entorno. Entonces en esta conferencia,
vamos a sacar
esta clave secreta y almacenarla en una variable de entorno
porque como te dije antes, nunca
debes almacenar tus
secretos en tu base de código. De lo contrario, estos secretos son visibles para cualquiera que tenga
acceso a tu fuente. Así que de vuelta en el terminal, vamos a instalar el módulo config. Puedo anotar el
número de versión que es 3.3 0.11. Ahora primero, necesitamos crear
una nueva carpeta que sea config. En esta carpeta, agregamos un archivo de configuración predeterminado
que es punto predeterminado JSM Así que un simple objeto SN. Podríamos tener varios
ajustes aquí. Pero por ahora, solo quiero
agregar una configuración. Esa es la clave secreta de JWT. Ahora en este archivo GSN predeterminado, vamos a establecer esto
en una cadena vacía El valor real no está aquí. Entonces aquí solo estamos definiendo una plantilla para todos los
ajustes en nuestra aplicación. Ahora necesitamos crear
otro archivo que sea personalizado
variables de entorno punto JS. Anote la ortografía,
asegúrese de hacerlo bien. De lo contrario, lo que les
voy a mostrar en esta conferencia no va
a funcionar en su máquina. Entonces como te dije
antes, en este archivo, especificamos el mapeo entre la configuración de
nuestra aplicación
y las variables de entorno. Entonces voy a volver
a nuestro punto predeterminado Son, copia todo esto, pegarlo aquí. Entonces esta es la estructura de nuestro objeto de configuración de aplicaciones. Ahora queremos mapear
esto a la configuración a una variable de entorno
llamada clave secreta JWT Pero como práctica recomendada, nuevo, como te dije antes, es mejor prefijar esto con el nombre de
nuestra aplicación para que no termines por una configuración de aplicación anulando otra
configuración de
aplicación Así que las ruedas justas alinean la clave secreta
JWT. Ahora con esto, podemos volver
a nuestro módulo Auth, así que Js. Entonces este es un lugar en
el que
hemos hecho referencia al secreto vamos a reemplazar esto con una llamada
al método Confic dot get Entonces primero en la parte superior, necesitamos
importar el objeto config. Entonces Cs config. Configuramos esto para que
requiera confit. Bien. Ahora, de vuelta en el método post, llamamos config dot cat y pasamos el nombre de la configuración de la
aplicación. En este caso, JWT secreto K.
Así que ahora, esto no es un secreto. Es un nombre de la configuración de nuestra
aplicación. El valor real,
el secreto real estará en una variable de
entorno. Un último cambio, tenemos que ir
a index dot js. Cuando se inicia la aplicación, desea asegurarse de que esta
variable de entorno esté establecida. De lo contrario, tenemos que
terminar la aplicación porque nuestro punto final de
autenticación no puede funcionar correctamente. Una vez más, en la parte superior, cargamos el módulo config. Config, configuramos esto
para que requiera config. Ahora, una vez más,
vamos a llamar a config dot get pass the name of
the application setting
JWT secret key Ahora bien, si esto no está definido, vamos a registrar
un error fatal. La clave secreta JWT no está definida. Y entonces tenemos que
salir del proceso. Anteriormente, se aprende sobre
este objeto de proceso. Este es uno de los objetos
globales en node. Aquí tenemos un
método llamado exit. Le damos un código, cero
indica éxito. Cualquier cosa menos cero significa fracaso. Muy a menudo, usamos exit one si quieres salir del
proceso en caso de error. Por lo que actualmente, no he establecido
esta variable de entorno. Ejecutemos la aplicación
y veamos qué pasa. Entonces Norman index dot JS, Bien, mira, tenemos
este error fatal. La aplicación se estrelló, esperando cambios en los
archivos antes de comenzar. Ahora se podría pensar que
la aplicación
sigue ejecutándose porque
Norman sigue ahí. No se termina. Pero si vas a
Cartero y envías una solicitud SDDP a
la aplicación, verás que nuestra
aplicación no responde Entonces, si la aplicación falla, Norman sigue funcionando. Norman sigue corriendo. Déjame mostrarte a lo que me refiero. Entonces si en lugar de no mod
ejecuto aplicación con nodo veo que la
aplicación se estrelló, y ahora estamos de vuelta
en la terminal Por lo que no estamos respondiendo a ninguna solicitud recibida
de los clientes. Ahora, vamos a establecer la variable de
entorno. Como te dije antes, en Mac, usas Exportar, en Windows, usas set para símbolo del sistema y columna
ENV dólar para Power Shell Columna dólar ENV, ruedas justas,
subrayado, clave JWT Secret.
Nosotros también establecemos esto. Digamos mi llave de seguridad. Ahora volvamos a ejecutar la
aplicación. Índice de nodos o Js.
Bien, hermosa. Lo conectamos a
Mongadib y si
volvemos a Cartero y enviamos
otra solicitud a Login, aquí está nuestro queso válido y token
web que está firmado
con nuestra clave secreta, cual se almacena en
12. Establecer encabezados de respuesta: Entonces en la
implementación actual, cuando el usuario inicia sesión, generamos un token web JCN y lo devolvemos en el
cuerpo de la respuesta Ahora llevemos esta
aplicación al siguiente nivel. Imaginemos cuando
el usuario se registre, queremos asumir
que está conectado, para que no tenga que iniciar
sesión por separado. Por supuesto, este requisito
no aplica a todas las solicitudes. En ocasiones se quiere exigir
al usuario que verifique
su dirección de correo electrónico. Entonces después de que se registren,
les envías un correo electrónico, ellos dan
clic en un enlace. Entonces el proceso es diferente. Pero en este curso,
imaginemos que Fair Wheels es una aplicación que se ejecuta
localmente en un alquiler de autos. Entonces las personas que usan esta aplicación son personas
que trabajan en este alquiler de autos. No necesitamos verificar
su dirección de correo electrónico. Entonces, el primer día
que se unen a la tienda, necesitan crear una cuenta, y boom, están logueado. Entonces vayamos al módulo de nuestro
usuario. Bien, aquí está el método post. Aquí es donde
registramos un nuevo usuario. Ahora bien, si nos fijamos en la
respuesta que estamos regresando aquí, estamos devolviendo un objeto
con estas tres propiedades. Ahora podemos agregar el
token web JCN como otra propiedad aquí, pero eso es un poco feo porque no es
propiedad de un usuario Un mejor enfoque es devolver el token web JCN
en un encabezado SDDP Así que al igual que tenemos
encabezados en nuestra solicitud, también
tenemos encabezados en
nuestro objeto de respuesta. Entonces voy a volver a nuestro módulo Auth y tomar prestada esta línea de código
para generar el token Así que copia esto ahora de nuevo
al módulo del usuario. Antes de enviar la
respuesta al cliente, generamos el token y luego llamamos a un encabezado de punto de
respuesta. Con esto, podemos establecer un encabezado. Ahora bien, para cualquier encabezado personalizado que definamos en
nuestra aplicación, debemos prefijar
estos encabezados con X. Ahora le damos un nombre arbitrario como autenticación o token. Este es el primer argumento, que es el nombre del encabezado. El segundo argumento
es el valor, que es en este
caso, nuestro token. Entonces con este simple cambio, establecemos este encabezado y luego enviamos esta respuesta
al cliente. ¿Bien? Ahora en la línea 20, estamos usando JWT así
como el módulo confit Entonces necesitamos importar
estos en la parte superior. Tan constante TWT configuramos esto
para requerir JCN web tooken. Y de manera similar, constant config, configuramos esto para requerir confit Ahora vamos a probar esto. Entonces
en la última conferencia, ejecuté la aplicación con
nodo en lugar de ni modo. Entonces mis cambios no son visibles. Entonces necesitamos detener la
aplicación y ejecutarla con modo
nodo. Bien, hermosa. Ahora, de vuelta en Cartero aquí en esta pestaña para
registrar un usuario, voy a cambiar este correo electrónico a un correo que
no he registrado antes Enviados. Bien, échale un vistazo. Entonces aquí está el cuerpo de la
respuesta exactamente como antes. Ahora en el Look Headertab, tenemos este nuevo
encabezado, X token Y esto está configurado para
nuestro JCN WebTKEN. Así que en nuestra app cliente, cuando registramos un usuario, podemos leer este encabezado. Podemos almacenar este JCN
WebTGen en el cliente. Y la próxima vez que vamos
a hacer una llamada API, enviaremos esta al servidor.
13. Encapsulación de lógica en modelos de manguesa: Ahora, hay un problema en
nuestra implementación actual. En el módulo del usuario en la línea 22, así es como generamos
un token web JCN Tenemos exactamente el mismo núcleo
en el módulo Auth en la línea 20. Ahora mira la carga útil
de este token web JCN. En esta carga útil, actualmente, solo
tenemos la propiedad ID. Lo más probable es
que mañana vamos a agregar otra propiedad en este pago
tal vez el nombre del usuario, tal vez su dirección de correo electrónico,
tal vez su rol. Queremos saber si
hay un usuario admin o no. Con la implementación actual, cada vez que queremos
cambiar esta carga útil, tenemos
que recordar que tenemos que ir a otro módulo y hacer exactamente
el mismo cambio. Y a la larga,
vas a olvidarte de
estos requisitos. Entonces en esta conferencia,
voy a mostrarles cómo encapsular esta
lógica en un solo lugar Ahora bien, ¿a dónde debemos
mover esta lógica? Un programador aficionado
puede pensar, Bien, voy a crear una función como generar token de
autenticación, poner esta función en algún lugar
que podamos reutilizar, tal vez en otro
módulo que podamos importar tanto en la Tierra
como en los módulos de usuario. Y con esto, tenemos la
lógica en un solo lugar. Bueno, eso es cierto. Eso funciona. Pero con este enfoque, terminarás con un montón de funciones colgando por
todo el lugar. En la programación orientada a objetos, tenemos un principio llamado principio de experto de
información. Eso significa un objeto que tiene suficiente información y es
un experto en un área determinada. Ese objeto debe
ser responsable tomar
decisiones y
realizar tareas. Como ejemplo del mundo real,
piensa en un chef. Un chef tiene un
conocimiento de cocina. Por eso el acto de cocinar en un restaurante lo realiza un
chef y no por un mesero El mesero no tiene
el conocimiento adecuado, la información correcta sobre
cocinar en un restaurante Entonces, si el chef es un objeto, debemos darle el acto
de cocinar al chef. Ahora, toma este principio
y aplícalo en este código. Entonces aquí, como parte de crear
este Chase y token web, ¿qué necesitamos en la carga útil? Necesitamos el ID del usuario. Mañana, es posible que
necesitemos el nombre del usuario
o su correo electrónico. Entonces toda esta información se encapsula aquí
en el objeto user. Entonces es el
objeto de usuario el que debería ser responsable de generar
este token de autenticación. Entonces la función
que escribí aquí, generar token de autenticación, esa función no debería estar colgada
en algún lugar de un módulo. Ese debería ser un método
en el objeto de usuario. Entonces aquí tenemos un objeto de usuario que cargamos desde la base de datos. Necesitamos agregar un método en
este objeto de usuario como este. Usuario que genera token
de autenticación. Y esto nos va a dar una
ficha, simple como eso. Ahora bien, ¿cómo podemos agregar esto? Tenemos que ir a nuestro
módulo de usuario donde definimos el modelo de usuario y hacer un
simple cambio ahí. Todo bien. Entonces aquí en nuestro modelo de usuario, necesitamos extraer la definición
de este esquema y
ponerlo en una constante separada porque vamos a
trabajar con ese separado. Entonces voy a
seleccionar todo este coe. Entonces, al crear el
modelo de usuario como segundo argumento, pasamos el esquema de usuario, y aún no lo hemos
creado. Eso lo vamos a hacer ahora. Así esquema de usuario constante, y establecemos esto a esta
expresión así. Bien. Así que aquí está nuestro esquema de usuario. Ahora, desea agregar un
método en este esquema. Así esquema de usuario que
tenemos una propiedad, métodos, esto devuelve un objeto. Podemos agregar pares de
valores clave adicionales en este objeto. Así podemos agregar una clave, generar
autenticación o token. Ponemos esto a una función.
Así par de valor clave. Cuando hacemos esto, entonces nuestro objeto de
usuario tendrá un método llamado generar token de
autenticación. Ahora aquí, en esta función, podemos tener parámetros. Entonces si tenemos un parámetro aquí, entonces al llamar a este método, podemos pasar argumentos. En este caso, no
necesitamos ningún parámetro, así que solo necesito agarrar esta lógica para
generar el token, obtenerlo de aquí y
moverlo dentro de este nuevo método. Entonces aquí en la carga útil, necesitamos la D del
usuario. ¿Cómo conseguimos eso? Bueno, este método será
parte del objeto de usuario. Entonces para hacer referencia
al objeto en sí, reemplazamos usuario con esto. Y esto significa que aquí debes usar la sintaxis de la
función regular. No se puede reemplazar esto
con una función de flecha. Porque como te dije antes, las funciones de
flecha no
tienen su en esto. Esto en una
función de flecha hace referencia a
la función de llamada. Por lo general, usamos funciones de
flecha para funciones
independientes. Si desea crear un método
que sea parte de un objeto, no
debe usar
una función de flecha. Ahora, vamos a revertir esto. Entonces aquí tenemos la ficha, y finalmente, la devolvemos
tan simple como eso. Aquí estamos haciendo referencia a los módulos
JWT y conflicto. Entonces necesitamos importar
esto en la parte superior. Entonces voy a volver a
nuestro módulo Auth en la parte superior. Ya no necesitamos estas declaraciones
requeridas. Entonces voy a conseguir
estos de aquí. Y ponlos encima
del módulo de usuario. Ahora, de vuelta en el módulo de
autenticación, así generamos el token y
luego lo enviamos al cliente. Necesitamos hacer los mismos
cambios en el módulo de nuestro usuario. Módulo del usuario,
eliminamos esta línea y establecemos el token al usuario
que genera AuthToken Entonces, finalmente, probemos esto y asegurémonos de que
todo esté funcionando. Entonces voy a registrar
un nuevo usuario aquí. Enviar, hermosa. Y aquí está nuestro token
de autenticación.
14. Middleware de autorización: Por lo que al inicio
de esta sección, decidimos proteger
las operaciones, que modifican los datos y los ponen a
disposición únicamente de los usuarios
autenticados Entonces vamos a nuestras empresas punto CHASE Piers el método post
para crear una nueva empresa Este punto final de API solo debe ser llamado por un usuario
autenticado Entonces, ¿cómo podemos hacer cumplir esto? Bueno, aquí, hicimos
alguna lógica como esta. Necesitamos leer los encabezados de las
solicitudes. Entonces este objeto request tiene
un método llamado header. Aquí, especificamos el
nombre del encabezado, es
decir X token. Esperamos un token web JCN
almacenado en este encabezado. Entonces almacenamos esto
como token constante. Ahora, queremos validar esto. Si esto es válido, entonces
damos acceso a
este punto final de API. De lo contrario, devolveremos
una respuesta como esta. Respuesta para el
código de estado de cuatro oh uno, lo que significa que el
cliente no tiene las credenciales de autenticación
para acceder a este recurso. Entonces este es el panorama general. Ahora no queremos
repetir esta lógica al inicio de cada
manejador de rutas que modifique Entonces necesitamos poner esta lógica
en una función de middleware. Recuerda,
funciones de middleware, hablamos ellas en la sección llamada Temas avanzados
Express Entonces ponemos esta lógica en
una función de middleware, y luego podemos aplicar
esa función en manejadores de
ruta que necesitan modificar
datos. Déjame mostrarte. Así que vamos a sacar esto de aquí. Bien, aquí queremos agregar una nueva carpeta llamada middleware Así que ponemos aquí todas nuestras funciones de
middleware. En esta carpeta, teníamos
un nuevo archivo t punto tiene. Ahora aquí queremos
definir una función llamada OT que toma tres parámetros,
request response, y next, que usamos para pasar el control a la siguiente función de middleware
en la canalización de
procesamiento de solicitudes Si este concepto te suena
desconocido,
necesitas volver
a la sección llamada Temas Avanzados
Express porque ahí exploramos
las funciones de middleware Entonces aquí en esta función, debemos implementar esta
lógica. Obtenemos la ficha. Lo más probable es que no
tengamos una ficha en absoluto. En este caso, devolvemos una respuesta 41 con un
mensaje como este. Acceso denegado. No se proporcionó ningún token. Entonces esto ayuda al
cliente a
averiguar por qué no puede
acceder a este recurso. Ahora bien, de lo contrario,
hay una ficha. Tenemos que verificar que se
trata de un token válido. Entonces aquí necesitamos usar
nuestro módulo de token web JCN. Entonces, en la parte superior, requeramos el
token web JCN y lo almacenemos en JW Ahora aquí llamamos a jwt punto Verifi. Como primer argumento,
pasamos el token, y como segundo argumento, pasamos la clave secreta
para decodificar este token. Así que almacenamos esa clave secreta
en una variable de entorno. Necesitamos usar un
módulo de configuración para leerlos. Así que requiere config
y guárdala aquí. Así que al igual que antes,
llamamos config dot g JWT Ccret key Ahora, este método de verificación
verificará nuestro Si es válido, lo decodificará y
devolverá la carga útil. Entonces aquí obtenemos la carga útil
descifrada. No obstante, si este
token no es válido, lanzará una excepción. Así que necesitamos envolver esta línea
con un bloque try cache. Así que prueba Cache,
obtenemos una excepción. Si llegamos hasta aquí, queremos decirle
al cliente que
se trata de un token no válido. Establecemos este estado a
lo 400 porque hay una mala solicitud porque lo que nos envía
el cliente no
tiene los datos correctos. Así que envía token no válido. Nuevamente, con este mensaje de error, podemos solucionar los problemas de
autenticación Entonces, si en el cliente, no podemos acceder a un punto final de API dado, veremos el mensaje de error. Nos damos cuenta de que enviamos
un token no válido. Después veremos la lógica en el cliente donde obtenemos el token y
lo enviaremos al servidor. Entonces este es nuestro bloque de caché. Ahora, de vuelta al tri bloque, aquí tenemos la nómina. Entonces podemos poner eso
en la solicitud. Entonces nuestro objeto request, le agregamos la propiedad user,
y lo configuramos a esta decodificación Entonces antes, colocamos solo el ID del
usuario en la carga útil. Déjame mostrarte. Así que
vayamos a nuestro módulo de usuario. Aquí está nuestro esquema de usuario. Agregamos este método de generar token de
autenticación. Creamos el JCN WebTKEN
y esta es nuestra carga útil. Entonces cuando descodificamos este JWT, este es el objeto que obtendremos Y pondremos esto en la
solicitud como objeto de usuario. Así que en nuestro manejador de rutas, podemos acceder a request dot
user dot underline
dot ID y ¿Bien? Entonces, en el bloque tri, establecemos request dot user, y luego necesitamos pasar el control
a la siguiente función de middleware
en la canalización de
procesamiento de solicitudes En este caso, ese es nuestro
manejador de rutas. Entonces llamamos siguiente. Entonces como te dije antes,
en las funciones de middleware, o
terminamos el
ciclo
request response sl o pasamos el control a la
siguiente función de middleware Ahora, solo un pequeño
problema en este código, en caso de que no tengamos un token, vamos a enviar esta
respuesta al cliente. Pero quiero asegurarme de que
salgamos de esta función. Bien, hemos terminado con
nuestra función de middleware. Ahora al final, establecemos las exportaciones de punto de
módulo a OTO un atajo para eso
es configurarlo aquí mismo. Entonces establecemos las exportaciones de punto del módulo, lo
configuramos en una función. No necesitamos un em aquí. Y entonces podremos
deshacernos de la línea 17. Hecho.
15. Protección de rutas: Entonces ahora que tenemos una función de
middleware, podemos ir al index dot JS,
mira, aquí estamos aplicando funciones de
middleware Entonces podemos agregar eso aquí, y luego se ejecutará
antes de cada manejador de ruta Pero no queremos
hacer esto porque no todos los endpoints API
deben estar protegidos Algunos de nuestros endpoints API
deben ser públicos, como registrar
un usuario o iniciar
sesión u obtener la lista de
empresas o clientes Entonces, en este caso,
queremos aplicar esta función de middleware selectivamente a
ciertos Así que volvamos al módulo de la compañía, aquí está nuestro manejador de rutas de correos El primer argumento es una ruta. El segundo es
opcionalmente middleware, y el tercero será el controlador de ruta
real Así que vamos a ir en la parte superior, impartir esta función de middleware
. Por lo tanto requieren. Ahora necesitamos subir un
nivel y luego ir a la carpeta middleware y
cargar el módulo Earth Lo conseguimos y lo ponemos aquí. Y finalmente, aquí
en el método post, pasamos OT como una función de middleware para ser
ejecutada antes que esta otra función de
middleware,
que es en este caso, que es en este caso, Entonces ahora vamos a probar
esto de nuevo en Cartero. Voy a abrir una nueva pestaña, enviar una solicitud de publicación al punto final de
la compañía. Así STDP host local,
API Empresas. Ahora, en este caso, no me preocupa el
cuerpo de la solicitud. Solo quiero saber si podemos llamar a este punto final API o no. Así que envía Bien, mira, tenemos este 401 o error
no autorizado. Y aquí está el mensaje de error. Acceso denegado, Noto puede proporcionar. Ahora vamos a proporcionar
un token no válido. Entonces vamos a la pestaña de encabezados, establecemos la clave que es X token. Pongo un token no válido, envío, nos dieron 400 o mal
pedido con este mensaje. Token no válido.
Hermoso. Ahora por fin, volvamos a nuestro
registro, usa una pestaña. Obtuvimos un token de
autenticación válido. Entonces copiemos esto de
nuevo a la tercera pestaña. Póngalo aquí y luego envíelo. Bien, ahora tenemos una mala solicitud, pero esto no es por
la autenticación. Esto se debe a que esperábamos el nombre propiedad en
el cuerpo de solicitud. Entonces, si agrego un
objeto JSON aquí en el cuerpo, nombre nueva compañía. Ahora, deberíamos ser buenos. Enviar.
Entonces obtuvimos una respuesta de 200, y esta es la nueva compañía. Entonces, como ejercicio, quiero que apliquen esta función de
middleware a otros manejadores de ruta
que
16. Conoce al usuario actual: En muchas aplicaciones, hay veces
que necesitamos obtener información sobre el usuario
actualmente conectado. Entonces en esta conferencia,
vamos a agregar un nuevo punto final de API para
obtener el usuario actual. Entonces vayamos a nuestro módulo de usuarios. Actualmente, solo tenemos
un manejador de rutas. Eso es para crear un nuevo usuario. Ahora necesitamos agregar otro
manejador para los métodos get. Ahora aquí, agrega un camino o ruta. Podemos pasar un parámetro, pero esto significa que el cliente debe enviar el
ID al servidor. Si bien este enfoque
está perfectamente bien, hay veces que quizás
por razones de seguridad, no
quieres
tener un endpoint como este porque entonces
puedo enviar el ID de otro usuario y mirar su
cuenta donde podría
haber alguna información que quizás no debería
ser visible para mí. Entonces el enfoque que usamos con
bastante frecuencia para obtener
información sobre el usuario actual es tener
un punto final API como yo. Con esto, el cliente no
va a enviar el ID de usuario. Lo conseguimos de la Web de JCN tomó. Entonces no puedo forjar JCN WebTKEN de otra
persona porque te dije que
para poder hacerlo, necesito crear una
nueva firma digital para ese Entonces agreguemos el manejador de ruta, solicitud
asíncrona y respuesta
va a este bloque de código Ahora, este punto final de API
solo debería estar disponible para usuarios
autenticados Entonces aquí necesitamos agregar
nuestro middleware OT. En la parte superior, carguemos
OT desde middleware Auth. Solo para aclarar, aquí, el autor
representa la autorización, no la autenticación
porque la autenticación se trata de validar
la contraseña del nombre de usuario Aquí, queremos ver si el usuario tiene permiso para acceder a
un recurso o no, y esa es autorización. Agregamos nuestro middleware aquí. Ahora con este middleware, si un cliente no envía un token web JCN
válido, nunca
llegaremos a
este No obstante, si llegas hasta aquí, como viste en la
implementación de esta función de middleware aquí, tendremos request
dot user object Para que podamos acceder a la propiedad
ID aquí. Entonces, en lugar de pasar la propiedad ID en la
ruta o en la ruta, obtenemos de request
dot user dot ID, que en realidad
proviene de nuestro token web JSON. Entonces este es un enfoque más seguro. Ahora, queremos encontrar un
usuario por el ID dado. Entonces llamamos usuario punto fino por ID. Pre pasar este valor, luego esperar la promesa y
obtener el objeto de usuario aquí. Ahora, no queremos devolver la contraseña del usuario
al cliente. Entonces aquí, llamemos a Select y excluyamos la propiedad de
contraseña. En tu aplicación, tal vez quieras excluir otras
propiedades también. Tal vez dirección,
tal vez número de teléfono. Entonces aquí tenemos un objeto de usuario. Por último, enviamos
esto al cliente. Así que envía usuario tan simple como
eso. Ahora, vamos a probar esto. Entonces aquí en Cartero, voy a agregar una nueva pestaña, enviar una solicitud Get a Local
host para 3,000 usuarios de API me. Ahora, inicialmente, no
quiero enviar un JCN WebTKEN. Por lo que enviar Xs negó ningún token,
siempre. Hermoso. Ahora vamos a la pestaña de encabezados. Agrega X o token aquí, y luego pasa una ficha de
queso y web SN. Esta es mi cuenta de usuario. Podemos ver que la contraseña está excluida.
17. Cerrar sesión de usuarios: Entonces en nuestro módulo Auth, definimos esta ruta para
autenticar ¿Qué pasa con cerrar la sesión de los usuarios? ¿Necesitamos una
ruta separada para eso? No, porque no estamos almacenando este token en
ningún lugar del servidor. Por lo tanto, no necesitamos un controlador de ruta
separado para eliminar este token Entonces, técnicamente,
necesita implementar la función de cierre de sesión en el
cliente, no en el servidor. Entonces en la aplicación cliente, cuando el usuario quiere cerrar sesión, simplemente borra ese
token del cliente. Ahora, he visto cursos
y tutoriales que te
enseñan a almacenar este token en el servidor en la base de datos. Esta es una muy mala práctica
porque estos tokens son como claves que dan a un cliente acceso a endpoints API protegidos Si un hacker puede
acceder a tu base de datos, puede ver todos estos tokens
para usuarios autenticados Ni siquiera necesitan saber
la contraseña de un usuario. Simplemente pueden obtener
su
token de autenticación y enviarlo al servidor para ejecutar
la
solicitud en nombre de un usuario. No debes almacenar
tokens en tu base de datos. Y si sabes
lo que estás haciendo y realmente quieres almacenar
el token en la base de datos, asegúrate de cifrarlo.
Asegúrate de hash. Al igual que las contraseñas. Almacenar un token en
un texto plano en base de datos es como obtener el pasaporte o
licencia de conducir de todos los usuarios, ponerlos en un
lugar central, y luego cualquiera, cualquier usuario malicioso que tenga
acceso a ese lugar central, simplemente puede obtener
estos pasaportes Pueden obtener esta licencia de
conducir e imitar a otros
usuarios, otros clientes Entonces una vez más, no almacene
los tokens en el servidor, los
almacene en el cliente. Y como mejor práctica de seguridad, siempre que estés
enviando el token del cliente al servidor, asegúrate de usar HTTPS. Entonces un hacker sentado en el
medio oliendo tráfico, no puede leer el token
enviado desde el cliente
al servidor, por lo que los datos se cifran entre el cliente
y el
18. Autorización basada en roles: Hasta el momento, hemos implementado la autenticación y autorización con éxito. Ahora llevemos esta
aplicación al siguiente nivel. Imaginemos que ciertas
operaciones como eliminación de datos solo pueden
ser realizadas por Administradores. Entonces déjame mostrarte cómo
implementar una autorización
basada en roles. Primero, tenemos que ir
a nuestro modelo de usuario. Entonces este es nuestro esquema de usuario. Actualmente, contamos con
tres propiedades, nombre, correo electrónico y contraseña. Ahora, necesitamos agregar
otra propiedad para ver si un usuario determinado
es un administrador o no. Así que vamos a agregar una nueva propiedad
es admin de tipo Boolean. Entonces ese es el primer paso. Ahora voy a ir
en Mongo DB Compass, agarrar a uno de estos usuarios y
convertirlos en un administrador. Así que edita. Voy a agregar un
campo después de la contraseña, y el pedido
realmente no importa. Así es admin y por defecto, se
puede ver el tipo
de esto es cadena. Vamos a cambiar
eso a booleano. Entonces digamos esto a true y luego finalmente apliquemos la actualización. Entonces aquí tengo un usuario
que es administrador. Ahora, cuando el inicio de sesión,
quiero incluir esta propiedad en nuestra carga útil
JSON Web Token. Así que la próxima vez que envíen este
JCN WebTken al servidor, podemos extraer esta propiedad
directamente del token No tenemos que obtener el ID, entrar en la base de datos y ver
si son admin o no. Y nuevamente, como te dije antes, con la firma digital
incluida en un webtken de JCN,
un usuario malintencionado no puede cambiar el valor de su administrador
para su cuenta de Si hacen algún cambio, tienen que regenerar
la firma digital, y esto requiere
conocer la clave privada que almacenamos en una
variable de entorno en el servidor Ahora, de vuelta en nuestro módulo de usuario, cuando generemos el token de
autenticación, queremos agregar esta
propiedad en la carga útil. Así que aquí está nuestra carga útil. Vamos a agregar una nueva propiedad
es admin. Ponemos esto a. Este dt es Admin. Entonces este es el beneficio de encapsular esta lógica
dentro del objeto de usuario Entonces hay un solo lugar
que necesitamos modificar. Anteriormente, teníamos esto
en dos lugares diferentes. Y con este cambio de símbolo, tuvimos que recordar aplicar este cambio en dos
lugares diferentes en el código. Entonces esta es nuestra ficha de rodilla. Ahora en el servidor, necesitamos una nueva
función de middleware para verificar si el usuario actual es
administrador o Entonces aquí en la carpeta
middleware, voy a agregar un
nuevo archivo, admin Entonces aquí establecemos el módulo que exporta a una función de
middleware Y toma una solicitud, una respuesta y una referencia a la
siguiente función de middleware en la canalización de
procesamiento de solicitudes Entonces aquí estamos asumiendo que
esta función de middleware se
ejecutará después de
nuestra función se
ejecutará después de
middleware de autorización Así que nuestros conjuntos de funciones de
middleware de autorización solicitan no usuario, por lo que podemos acceder a eso
en esta Entonces solicito a ese
usuario que sea admin, o digamos que si no
están en admin, vamos a devolver el estado de
respuesta. Establecemos el estado 24 oh
tres, lo cual está prohibido. Esta es una de las áreas en las que muchos desarrolladores se equivocan. Entonces tenemos 41, lo que significa no autorizado, y
tenemos cuatro oh tres,
lo que significa prohibido. Usamos no autorizado cuando el usuario intenta acceder a
un recurso protegido, pero no suministra
un JSN WebTKEN válido Entonces les damos la oportunidad de
reintentar y enviar un JCN WebTKEN válido ahora si envían un token web GSN
válido y todavía no se les permite acceder
al recurso de destino, ahí es cuando usamos
cuatro oh tres, lo
que significa prohibido, lo que significa que no lo intentes de nuevo, simplemente no podemos Así que de vuelta aquí, establecemos el estado y enviamos un
mensaje como acceso denegado. Ahora, de lo contrario, si
el usuario es admin, pasamos el control a la
siguiente función de middleware,
que es, en este caso,
el manejador de ruta Ahora vamos a aplicar esta función de ware intermedio
en una de nuestras rutas. Así que volvamos a las empresas punto JS, veamos el método delete. Entonces, aquí está nuestro método de eliminación. Aquí queremos aplicar dos funciones de
middleware. Así que tenemos que pasar array. El primero es OT y
el segundo es admin. Por lo que estas funciones de middleware ejecutarán en secuencia Primero arte si el cliente
envía un Jas variado en webtken y luego
llegaremos a la segunda función
milware El usuario es un administrador, entonces se ejecutará la tercera función de
middleware o manejador
de ruta Ahora, tenemos que importar
esto en el TA. Tan constante admin,
configuramos esto para que requiera ir a la carpeta
middleware y cargar el módulo admin Ahora, vamos a probar esto.
De vuelta en Cartero. Voy a abrir
una nueva pestaña y enviar una solicitud de eliminación
a este endpoint, host local
STDP para
3,000 empresas API Ahora déjeme tomar una identificación para una empresa de la base de datos de
Mongo IV Así que ve a Companies
Collection, aquí, copia este ID y ponlo en
nuestro endpoint así. No olvides
incluir el token de probabilidades. De lo contrario, obtendrá
el error de autorización. Exceso denegado, ningún
token lo proporciona. Entonces vamos a poner el token
y ahora mandar esto. Hermoso. Tenemos
una respuesta de 200, y aquí está la compañía
que fue eliminada.