logo

midulive


Transcribed podcasts: 605
Time transcribed: 13d 3h 7m 36s

This graph shows how many times the word ______ has been mentioned throughout the history of the program.

Muy buenas tardes, ¿qué tal? Bienvenido, bienvenida, espero que estés fantásticamente en este miércoles 12 de junio
que hoy tenemos clase del curso de Node.js porque es verdad y con razón hay gente que me decía
oye, ¿qué ha pasado con el curso de Node.js? Que se te ha olvidado ya totalmente y es que tenés toda la razón.
La gente está bien pila. Teníamos de hecho, os voy a enseñar una cosa, voy a enseñar una cosa
porque no sé si es curso o aprende Node.js. Habíamos hecho este curso práctico de Node.js desde cero
que se podía conseguir certificado porque teníamos gente que estaba haciendo ejercicios, que los tengo, los tengo ahí
los ejercicios y los he estado revisando. Tenemos un montón de gente que está haciendo ejercicios, que le enviamos ejercicios
los miramos, las PRs, a ver si los han hecho bien y todo, le damos un check y todavía hay que enviarle más ejercicios.
Ahora ya no se puede pedir certificado, ya está el cupo, el cupo está completo. Hostia, por cierto, he dejado aquí la cámara
voy a moverla un momento y me voy a hacer más grande. Entonces, entre todos los temas ya hemos tocado un montón
porque hay un montón de temas que ya hemos hecho. Si vais a midu.link barra Node, midu.link barra Node, ¿vale?
Pues tenemos diferentes clases del curso de Node.js completo. Es totalmente gratuito, no tenéis que pagar nada, ¿vale?
Tenéis el curso disponible para que lo veáis y lo reveáis cuando queráis, ¿vale? Todo el contenido lo tenéis gratuito.
E hicimos la introducción en los primeros pasos, desarrollo de una API con Express desde cero,
la solución de Cores, ¿vale? El temido Cores, la API Rescon Express, el poder de arquitectura,
porque miramos MVC, el patrón de diseño tan interesante MVC, aunque es un patrón de arquitectura, ¿eh?
Mucha gente, el otro día una persona, patrón en el diseño común utilizado, a ver si os entiendo aquí la Wikipedia.
Hay mucha gente, y esto es una polémica que yo sinceramente no me parece tampoco tan polémica, ¿eh?
Pero la modelo visto del controlador, hay gente que se cabrea, que dice que es un modelo, un patrón de diseño.
Pero si os fijáis, cuando veis la descripción veréis que pone patrón de arquitectura de software.
También lo podéis mirar en inglés, ¿eh? Pero bueno, esto es lo típico que siempre pasa.
¿Ves? Aquí dicen Design Pattern. Bueno, o sea que aquí cada uno que lo entienda como quiera, ¿eh?
Pero hay gente que se enfada mucho con estas cosas. ¿Qué más da? ¿Qué más da?
Lo importante es que te permite hacer que tu aplicación sea más mantenible. Eso es lo importante, ¿eh?
Entonces, también tenemos el crear una base de datos MySQL y evitar los hackers, buenas prácticas.
Y Sockets, chats en tiempo real con Node.js, Sockets, SQL, HTML y CSS.
Entonces, aquí tenéis todas las clases, midu.link barra note.
Y hoy vamos a hacer también tema de usuarios. Registro de usuario, inicio de sesión, cerrar sesión, cookies, JSON Web Tokens y tal.
Ahora, yo sé que ahí fuera hay un montón de servicios de terceros o bibliotecas que te lo solucionan todo, ¿vale?
Que te lo solucionan todo, que tú con dos cosas te lo solucionan.
Pero eso, que está muy bien y que yo te recomiendo mucho porque gestionar un sistema de autentificación de usuarios es bastante complejo.
Eso está muy bien, pero es importante que conozcáis el porqué de las cosas.
Si queréis aprender cómo funciona algo y por qué y cuando tengáis un error, por qué esto y tal, está bien que vayáis viendo un poco los pasos y cómo funciona todo por detrás.
Y yo sí que os recomiendo que es una práctica muy interesante, que le echéis un vistazo a esto, que lo hagáis paso a paso y entendáis.
Ah, por esto se hace esto. Esto funciona así, por esto, pla, pla, pla, pla.
Así que, y quién sabe, porque a veces incluso para aplicaciones bastante o muy pequeñas o lo suficientemente grandes, puede valer la pena que hagáis vuestro sistema de autentificación, ¿vale?
Autentificación o autenticación.
Yo sé que me van a estar luego quemando la cabeza con esto, pero tanto autenticación como autentificación, que yo sepa, es lo mismo en la RAE, ¿vale?
O sea que si os molesta uno, lo podéis, podemos mirar aquí, autenticar, bueno, autenticar.
Yo utilizo autentificación, autenticación, ¿ves? Autenticación y pone autentificación.
Que no seáis tan pejigueros con el lenguaje, porque ya veis que muchas veces significan lo mismo.
Vamos a crear ya nuestro proyecto. Muy fácil, ¿eh? Muy fácil. Lo vamos a hacer desde cero.
Ya sabéis que a mí me gusta hacerlo todo, todo desde cero.
Y en este caso, aunque sea no.js, pues lo vamos a hacer desde cero.
Entonces vamos a hacer user out. No.js, no.js, user out.
Y como lo vamos a hacer desde cero, gracias a todos los que habéis reventado el tren del hype hasta el nivel 5, ¿eh?
Javier Angosto, Botero, muchas gracias a todos. Gracias, amigos.
Pues vamos a inicializar nuestro proyecto con un npm init menos i.
Esto lo que haría es crear ya el package.json y tal.
Pero yo no utilizo npm. Utilizo pnpm, que es una alternativa a npm.
Pero los comandos que voy a utilizar con pnpm serían los mismos de npm.
Utilizad el que queráis.
Pero pnpm es más rápido.
Además hay una persona que es de la comunidad que trabaja en pnpm.
Que es el señor Draps, que trabaja ahí.
Pues vamos a crear ahora un archivo index.js.
Y aquí es donde va a ocurrir toda la magia.
Antes de ponerme, si os parece, a codear, os voy a poner lo que vamos a ver hoy.
Lo que vamos a ver hoy es todo esto, ¿vale?
¿Qué vamos a ver hoy?
Instalación del proyecto.
Usuarios en base de datos.
Vamos a crear, utilizar una base de datos muy sencilla.
Porque la clase de hoy no es tan importante la base de datos.
Entonces no vamos a utilizar MySQL ni nada.
Y lo interesante es que vais a ver que lo que utilicemos lo podéis cambiar por la base de datos que queráis.
¿Vale?
O sea, que lo que queráis lo vais a poder utilizar.
Vamos a ver también registro de usuarios.
Autenticación o autentificación básica con login y password.
De hecho, vamos a utilizar, ahora que me he acordado,
vamos a utilizar esta aplicación que es una alternativa a Postman.
Y así podremos probar rápidamente nuestros endpoints para ver si funcionan correctamente.
¿Vale?
Dice uno, usa Prisma.
No tiene sentido usar Prisma.
Es que no tiene sentido.
Porque si yo uso Prisma, me tengo que poner a perder tiempo a explicar Prisma.
Entonces, un día puede ser que hagamos Prisma directamente.
Pero si te pones a mezclar, no, autentificación de usuarios, pero también Prisma, pero también TypeScript, pero también...
Y al final te queda algo que no te enteras de nada, ¿sabes?
Entonces, si te pones a mezclar, no te enfocas y queda un poco raro.
Bueno, vamos a utilizar Jack, ¿vale?
Que es como una alternativa directamente a Postman.
Y aquí, pues ahora veréis cómo se puede utilizar.
Pero podéis utilizar lo que queráis, ¿eh?
O Insomnia, Postman, lo que queráis.
Vamos a ver qué más.
La autentificación más básica con login y password.
Vamos a ver los problemas que tiene esto.
Verificación de autentificación.
Porque habrá que verificar.
Más que verificar, le voy a llamar usando hashes y salts, ¿vale?
La sesión de usuarios con cookies.
Vamos a ver esto porque hay un tema muy polémico.
Y es que muchas veces la gente utiliza local storage.
Yo os voy a explicar por qué local storage no sería recomendable.
Por qué yo lo evitaría siempre a muerte.
Y vamos a ver por qué.
Saludito, mano, con señal de victoria.
Ojo, saludito.
Así que yo os lo explicaré.
Y ahí cada uno que haga luego lo que le dé la gana.
Pero dentro de todas las opciones, las cookies son mejor.
Son mejor que el local storage.
Luego, JSON Web Tokens o JWT.
Refactorizamos alguna cosa con Middleware.
Cerrar sesión y Refresh Token.
Vamos a ver si nos da tiempo Refresh Token.
Espero que sí.
Y más adelante, ¿vale?
En una siguiente clase, si os ha gustado el contenido y todo esto.
Más adelante veremos Passport y OAuth 2.0.
El otro año mueren las Third Party Cookies.
Sí, bueno, esto lo han vuelto a retrasar el tema de las Third Party Cookies.
Otro tema muy importante de las cookies.
Que la gente se equivoca constantemente.
Las cookies no van a desaparecer, ¿vale?
Van a desaparecer solo las Third Party Cookies.
¿Esto qué quiere decir?
Lo que quiere decir es que las cookies de tu propio dominio van a seguir funcionando.
Y eso no va a desaparecer jamás.
Rompería demasiadas cosas.
Lo que van a desaparecer son las Third Party Cookies.
Que son las que se utilizan de analíticas, publicidad y todo esto.
Para que te dejen de trackear.
Para ver todo lo que haces en tu vida.
Entonces, esto es lo que vamos a hacer hoy.
Lo que vamos a utilizar hoy, vamos a utilizar Express, ¿vale?
Yo sé que hay otras alternativas.
Está Jono.
También nos gusta mucho Nest.
Pero vamos a utilizar Express porque es el más típico.
Y muchas de las cosas que vamos a hacer en Express, en realidad,
te la puedes llevar a cualquier sitio porque las APIs se parecen demasiado.
Y como no queremos cometer muchos errores en nuestro código,
vamos a utilizar Standard.
Gracias a ti.
Vamos a utilizar Standard.
Que esto lo que nos va a permitir es lintar nuestro código e incluso formatearlo.
Le ponemos la "-d", para que nos lo instale como dependencia de desarrollo.
¿Vale?
Y ya tendríamos aquí nuestras dos dependencias.
Por un lado, Express, que yo le quito el gorrito, el caret, que le llaman,
para que siempre instale esta versión fija.
Pero vamos a configurar aquí SlimConfig y le vamos a decir que utilice esta configuración de Standard.
Esta de aquí.
Y vas a ver, mira, si le quito esto, voy a quitárselo un momento,
y yo me pongo a poner aquí console.log y pongo aquí hola mundo y pongo aquí un montón de puntos y coma
y aquí separaciones que no tienen sentido, ¿vale?
Pues está mal, esto no me está formateando.
Pero ahora, en cuanto tengamos esta configuración y gracias a la extensión de Slint que tenemos en Visual Studio Code,
automáticamente ya estamos creando aquí una relación entre esta configuración, esta extensión,
y ahora fíjate, ¿ves? Se me queja.
Oye, que aquí has puesto estas semicolons.
Oye, que aquí tienes separaciones.
Y cuando guardo, me lo arregla todo.
Esto no, porque esto es una variable que no se usa y también se queja de eso.
Yo, saludando a un guapo.
Hola, Midu.
Hola.
No usaremos MVC, ¿verdad?
¿Qué se usará?
No vamos a usar MVC porque, primero, tardaríamos mucho y, segundo, la gente que no ha visto el vídeo de MVC se volvería loca.
Oye, pero ¿por qué esto no sé qué, no sé cuánto?
MVC es un patrón que requiere conocerlo para no perderse y entonces vamos a evitar utilizar MVC.
Pero vamos a hacer otra cosa, ¿vale?
Vamos a utilizar, no es otra cosa, pero vamos a utilizar un repositorio para que tengáis alguna idea de cómo poder separar alguna cosa, ¿vale?
Eso sí que lo vamos a hacer.
Eso sí, porque creo que tiene bastante sentido.
Entonces, ya teníamos ahí nuestro console.log, pero, hombre, vamos a ir un poquito más allá de un console.log.
Cosas importantes.
Aparte del linter, también voy a activar el modo módulo, ¿vale?
Vamos a decir que este proyecto es de tipo módulo.
Y esto lo que va a hacer es que vamos a poder utilizar no los requires, que es lo típico que se utiliza para traerse con CommonJS, que se llama, esto se llama CommonJS, ¿vale?
Para, en lugar de traer los módulos con CommonJS, lo vamos a hacer con el MaxScriptModules.
Así que así podremos utilizar imports y nos podemos traer express.
Si no ponemos el typeModule aquí, no podemos utilizar el import y se nos queja.
Así que vamos a crear ya nuestro servidor.
Esto es código típico y tópico para crear tu primer proyecto de express.
Tenemos el puerto, que vamos a recuperarlo de la variable de entorno.
Y si no, por defecto le vamos a poner que es el puerto 3000.
Y vamos a crear nuestro primer endpoint, donde aquí, pues nada, aquí tenemos que ponerle el callback.
Esto sería la request.
Esto sería la response.
Y aquí tendríamos que responder.
Que, a ver, por ahora vamos a responder con un Hello World.
Luego esto lo iremos cambiando.
Y vamos a decir que nuestra aplicación tiene que escuchar el puerto 3000.
O 3000, o el que le pasemos por las variables de entorno, ¿vale?
Esto es el código mínimo para que creéis vuestro proyecto de express.
O sea, esto es lo más típico.
Importar la dependencia.
Crear la aplicación.
Bueno, esto es que necesitamos tener un puerto en el que levantar el servidor.
Por defecto le decimos el 3000.
Esto en el caso que le pongamos una variable de entorno utilizará ese.
Entonces, esto lo podemos separar en un archivo.
A mí me gusta más, os voy a decir una cosa.
A mí me gusta más tener como un archivo que se llama config.js.
Y aquí, en lugar de hacer estas cosas que constantemente se ve al process.enf y tal, aquí yo lo que hago es esto.
Port, le ponemos aquí el valor por defecto.
Y esto lo sacamos process.enf.
Y todo esto lo exportamos.
Y así, en lugar de hacer estas cosas que quedan un poco, que manchan un poco el código, pues tú ya te traes desde tu configuración todo lo que necesites y ya está.
Y así, pues lo tienes en un config del process.enf, le pones incluso el valor por defecto y ya te olvidas.
Y ya ahí importas el port de la config y ya está.
Creo que queda mucho mejor.
Vamos a utilizar la anotación corta de esto, ahora que ya sabemos que eso es request y response, para que quede más cortito.
Bueno, una vez que creamos la aplicación, aquí tenemos que ir creando los endpoints.
Podemos crear con todos los verbos de acción el get, el post, el put, el delete.
Vamos a utilizar el get y el post.
Porque, ojo, también vamos a hacer rutas protegidas, que no lo he puesto por aquí.
Rutas protegidas.
Esto está interesante, las rutas protegidas.
Es fácil, o sea, hacer rutas protegidas tampoco tiene mucha historia, pero lo vamos a ver, ¿vale?
Que está interesante las rutas protegidas también, para que veáis cómo se harían, especialmente tanto en el backend como incluso que se podría llevar al frontend, ¿vale?
Entonces, aquí tendríamos el up.get, que cuando entramos a la raíz de nuestro proyecto, pues respondemos hello, hello, me do, no, yes, ¿vale?
Y aquí esto sería para levantar proyecto en el puerto que hemos dicho.
Me voy a ir a la terminal, bueno, me voy a ir al package.json y vamos a poner aquí un script dev.
En lugar de utilizar nodemon, que está muy bien nodemon, pero ahora podemos utilizar node-watch y le decimos el archivo que tiene que mirar, ¿vale?
El que tiene que observar.
Así que ahora podemos utilizar pnpm dev o ramdev, el que queráis, ¿vale?
Y esto va a estar observando continuamente nuestros archivos.
Y fíjate, yo ahora me voy aquí, localhost 3000, tenemos aquí el hello, me do, no, yes, y si yo aquí cambio esto, vamos a cambiar esto, vamos a poner un h1, no sé si lo detecta, creo que sí que detecta automáticamente, creo que sí, ¿veis?
Vale, pues fijaos que eso lo he tenido que refrescar, no tengo que hacer absolutamente nada.
Lo pongo aquí, guardo los cambios, me voy a la página y fíjate que ya tengo aquí, hola, me do, no, yes, sin instalar ningún tipo de nodemon ni nada.
Está súper, súper genial, me gusta mucho.
Ahora, en el caso que tengáis la última versión de node, porque no sé qué versión estoy utilizando yo, la 22, pues que sepáis que ahora no hace falta que utilicéis los scripts con pnpm, pnpm ramdev ni nada, sino que ahora podéis utilizar node, le decís run y el script, ¿vale?
Y fijaos, funciona exactamente igual, esto es algo nuevo que ha traído node en la última versión, la 22, si lo preferís también lo podéis hacer, ¿vale?
A partir de la versión 22, si tienes una versión antigua no podéis hacer esto, pero esto funciona exactamente igual y de hecho va un pelín más rápido, así que una cosa que os recomiendo.
Pues ya teníamos aquí lo mínimo, ya tenemos el servidor como levantado, perfecto.
¿Cuáles son los endpoints en los que vamos a trabajar?
Vale, vamos a tener el post barra login y aquí por ahora nada, lo dejamos vacío.
Vamos a tener para loguear a un usuario, vamos a tener también para registrar a un usuario, vamos a tener para cerrarle la sesión al usuario y vamos a tener también, este va a ser la ruta protegida, vamos a tener una ruta protegida que le vamos a llamar protected, ¿vale?
Protegida, protegida. Estos son los endpoints que vamos a estar implementando, ¿vale? Estos endpoints, ¿cómo vamos a poder acceder a ellos?
Pues ya se ve, cuando hagamos con el método post vayamos a barra login, pues accederemos.
De hecho, si vamos aquí a Jack y ya pues vamos a crear aquí un HTTP request, podríamos hacer HTTP barra barra localhost 3000 barra login.
Y aquí cambiamos el verbo a post y aquí pues podríamos devolver lo que queramos, ¿eh?
REST JSON USER MIDUDEP. Por ahora esto no tiene mucho sentido, pero solo para que veamos que esto funcione.
Y ahora al darle aquí, ¿veis? Me ha devuelto USER MIDUDEP.
Si aquí le cambio otra cosa, lo que sea y volvemos aquí, ¿vale? Pues podéis ver que me está devolviendo lo que sea.
Voy a hacer esto un poco más grande para que lo veáis bien, para que no nos dé ningún problemita.
Es bastante básico, ¿eh? Esta herramienta de Postman, o sea, la alternativa de Postman, es muy básica, pero para lo que queremos ya nos va bien.
Ya nos va bien. Bueno, pues ya podéis ver que ya está contestando este login.
Obviamente, si vamos a Register, como no devuelve nada, pues se va a quedar así, ¿vale?
Porque no estamos devolviendo nada, entonces se ha quedado ahí como pensando hasta que aquí pues hagamos un Regen, lo que sea también, otra vez.
Y entonces ahora sí, pues devolverá lo que sea. Pero bueno, esto lo haremos después. Por ahora nos olvidamos de esto.
Vamos a ir quitando este. Por ahora quitamos esto. Ahí tenemos todos los endpoints que vamos a hacer.
Como os he dicho, vamos a utilizar una base de datos. Hay gente que querrá que utilice MySQL, SQLite, otro que querrá Prisma, otro que querrá Postgre, otro que...
Ya estábamos en el curso, ya hicimos MySQL dos veces, ¿vale? Bueno, uno hicimos MySQL y creo que el otro lo hicimos SQLite.
Entonces, hoy vamos a utilizar algo totalmente ajeno para poder olvidarnos tanto de la base de datos.
Vamos a tener una base de datos, pero que no va a ser tan importante si es SQL o sea lo que sea, ¿vale?
No nos vamos a tener que preocupar de nada de esto. Y para hacer esto, ¿qué es lo que vamos a hacer?
Bueno, lo que vamos a necesitar en este caso, vamos a crear como un repositorio.
Vamos a utilizar una dependencia que se llama dblocal. Está bastante interesante porque te permite crear una base de datos local
y para pruebas, para no tener que levantar absolutamente nada, pues te puede servir.
Y también te puede servir incluso para algún proyecto sencillo que tengas que tener local y ya está, que va a ser este caso.
Pero nosotros lo que vamos a hacer, y que para que el día de mañana tú, si quieres conectarla a una base de datos,
que va a ser muy fácil, lo importante es que lo que vamos a hacer cumpla el mismo contrato, ¿vale?
Y esto es justamente lo que comentamos también con el MVC. Eso te puedes ver la clase si quieres.
O sea, aquí vamos a importar dblocal, from dblocal, y vamos a tener una clase que, por ejemplo, podemos llamar userrepository, ¿vale?
Y digamos que esta clase vamos a tener, pues, static create, que le vamos a pasar el username y el password.
Y también podemos tener un método que sea login, ¿vale? Login y que también username y password.
Y lo importante es que si el día de mañana tenemos otra base de datos, es que lo podáis implementar utilizando, pues, el mismo contrato.
Podríamos ir más allá, hacer inyección de dependencias, no hacer esto estático, que tenga un constructor y todo esto.
Pero no me da tiempo y no tengo ganas de explicar inyección de dependencias y todo esto.
Como tengo previsto que un día hagamos una clase de clean architecture, pues ya todo eso lo explicaremos cuando hagamos clean architecture.
Solo en este caso piensa que lo importante es que la clase que exportas, si tú lo haces con SQL, con MongoDB, con lo que sea,
lo importante es que los parámetros de entrada y lo que devuelve cada uno de los métodos sea lo mismo.
Con eso ya lo tendría solucionado, ¿vale?
Así que en este caso nosotros vamos a utilizar este DB local y nos olvidamos de todo esto.
Vamos a crear un esquema, esto es muy típico en muchas bases de datos, así que creamos un esquema, nada muy fancy,
nos vamos a enfocar más en tema de autentificación, así que vamos a tener una idea, decimos que va a ser de tipo string,
le podemos poner que sea requerido, no hace falta ni siquiera que pongamos que es primario y todo esto,
username y password, ¿vale? Esto van a ser como los tres.
¿Y este esquema de dónde lo sacamos? Pues esto vamos a tener que crear este esquema
diciéndole dónde tenemos nuestra base de datos local, porque claro, esto lo va a guardar en un archivo.
Entonces hacemos DB local y le vamos a decir que el path sea en barra DB.
Creo que no hace falta ponerle ni siquiera el archivo, solo con ponerle el path ya está.
Y luego veremos que automáticamente nos va a guardar ahí toda la información que vayamos creando, ¿vale?
De nuestros usuarios.
Entonces, importamos DB local, que esto es una base de datos local, que no sigue ni SQL ni nada,
pero sí que te da unos métodos interesantes para buscar datos, para crear datos, para actualizarlos,
como si fuese una base de datos, pero en tu disco duro.
Y aquí lo que estamos diciendo es que la carpeta punto barra DB, vamos a tener la base de datos donde va a guardar todos los archivos.
Creamos un esquema para nuestros usuarios, aquí le hemos puesto user, con los, en este caso, las propiedades que vamos a tener.
Una IDE, Username y Password, que luego ya veremos si necesitamos más, si necesitamos menos, lo que sea.
Y vamos a tener una clase que es la que exportamos, le hemos llamado UserRepository, en uno para crear usuarios y otro para hacer login.
También veremos más adelante si necesitamos más o si necesitamos menos.
¿Qué es lo que necesitamos cuando creemos los usuarios?
Lo primero, antes de nada, es que tenemos que validar que no nos están mandando cosas raras.
Así que primero, validaciones del Username.
Por ejemplo, aquí podríamos utilizar Zot, ¿vale?
Opcional, usar Zot.
Zot o lo que queráis.
Zot es una biblioteca de validaciones que te ayuda un montón.
Yo no lo voy a utilizar también para no añadir una dependencia más, pero lo podrías utilizar, ¿vale?
Le decimos, oye, por ejemplo, si el Username es diferente a String, le vamos a decir, oye, el Username tiene que ser un String, ¿vale?
Vamos a enviar un error directamente.
Tampoco vamos a aceptar que el Username sea menor a 3.
Y si es así, pues vamos a devolver un error y decimos que el Username tiene que ser como mínimo de 3 caracteres.
Estas son validaciones que son muy, muy mínimas.
Y lo mismo haríamos en este caso con el Password.
Le decimos, oye, el Password tiene que ser un String.
Si no es un String, mandamos un error, ¿vale?
Mandamos el error y le decimos que tienes un String.
Y lo mismo también lo podríamos hacer no solo para la longitud.
Podríamos decirle que debe tener un número, un símbolo, lo que sea.
Aquí sería cuestión de ir añadiendo validaciones, ¿vale?
No es tan importante las validaciones en sí que vamos a hacer en esta clase,
sino que entiendas que tienes que validar tanto el nombre de usuario como el Password, ¿vale?
Porque si no la puedes liar pardísima y puedes dejar que te pongan cosas que no tengan mucho sentido, ¿vale?
Esto sería lo primero, validaciones.
Todas las validaciones que se te ocurran van aquí.
Hay una segunda cosa que es muy importante.
Asegurarse que el Username no existe, ¿vale?
Entonces nos tenemos que asegurar que el Username que está utilizando la persona que se está registrando no existe.
Porque si no estaríamos creando el mismo usuario todo el rato.
Puede ser que petase la base de datos en el caso...
En este caso no petaría porque no hemos puesto aquí que fuese unique ni nada.
Es que porque en este caso ni siquiera tengo muy claro que realmente lo acepte.
Puede ser que sí que lo acepte.
Pero pensemos o que no lo acepta o lo que sea.
Lo cierto es que esto sí que es importante que la base de datos tenga ya esta limitación, ¿vale?
De decir, oye, no, los Usernames tienen que ser únicos.
Pero igualmente no hace falta...
Tienes dos estrategias.
Uno, saber que tu base de datos es íntegra.
Y que por lo tanto el Username lo hace único.
Intentar guardar el Username directamente.
Y dejes que pete, pero capturas el error en el código, ¿vale?
Esa sería una estrategia.
Y la segunda estrategia es decir, no, voy a intentar en el código evitar ese caso.
Y para eso lo que voy a hacer es recuperar, mirar si hay un usuario, ¿vale?
Vamos a encontrar un usuario con este Username.
Y en el caso que exista este usuario, pues vamos a mandar un error.
Ya te digo que dependiendo de la base de datos aquí la estrategia puede ser distinta.
Puede ser que quieras intentarlo.
Yo siempre lo evitaría porque intentar hacer un Insert ya sabiendo per se que ya existe un usuario
como que parece raro.
Yo no lo intentaría.
Yo iría más por esto para hacerlo en modo código.
Pero bueno, aquí cada uno, cada maestrillo tiene su librillo.
Vamos a crearle también una ID porque lo necesitamos.
Aquí no hace falta que instale ninguna dependencia para generar IDs.
Mucha gente se pone a, no sé, a instalar dependencias para generar IDs y tal.
A ver, a no ser que quieras una ID muy específica, pues puede ser.
Pero las IDs, lo mejor que puedes hacer es utilizar el Random UID en este caso.
Normalmente, en este caso, pero hay base de datos que te genera la ID.
Si la base de datos te genera la ID, normalmente mejor que te la genere la base de datos.
Porque, por ejemplo, MongoDB te genera unas IDs que están muy bien, que ya son únicas,
que te meten ahí un timestamp.
De hecho, son unas IDs muy especiales que se llaman Object ID, que tiene su historia.
Entonces, si ya te la genera, perfecto.
Si no, bueno, pues hay diferentes estrategias.
En este caso, vamos a utilizar el Random UID.
Hay una polémica ahí fuera que dice, oye, no utilices Random UID porque el UID es malo para hacer la indexación.
Y es verdad.
Cuando utilizáis índices en la base de datos, el Random UID, dependiendo de la base de datos, ¿vale?
No hay una bala de plata.
No es todo sí o todo no.
El Random UID, según en alguna base de datos, si tienes mucha información, puede tener un problema de rendimiento.
Pero es que depende de la base de datos.
Depende de un montón de cosas.
Entonces, infórmate si es una buena idea o si no es una buena idea, ¿vale?
Entonces, pues puedes poner Random UID.
Igualmente, no es una clase de base de datos y tal, porque si no, pues igualmente, seguramente tendríamos una ID pública indexada, que se pueda indexar más fácilmente o menos fácilmente, no sé qué, un montón de cosas.
Pero bueno, hoy solo para que lo sopas.
No, tampoco es buena idea hacerla incremental, porque así te pueden hacer un montón de ataques.
Hay un montón de historias, ¿vale?
¿El Random UID podría repetir sin querer un UID?
Puede repetir, pero las posibilidades son muy bajas, ¿vale?
Son muy bajas de que las repita.
Pero muy bajas, cuando decimos muy bajas, es, yo que sé, una entre 16.000 millones.
No sé, no me acuerdo del número, pero que es muy, muy, muy baja, ¿eh?
En una vida entera.
O sea, no cada vez que lo ejecutas.
O sea, es bastante poco probable.
Y ahora que ya tenemos nuestra ID, lo que decimos es que del esquema que hemos creado, vamos a crear un usuario.
Con el ID le pasamos la ID, el username, ¿vale?
Y el password.
Bueno, ahora veremos qué pasa con esto de guardar el password, ¿vale?
Le decimos que esto nos lo guarde y vamos a devolver la ID, ¿vale?
No hace falta, como ves, este user.create no es asíncrono, porque como se está guardando el local, pues esto no lo hace asíncrono y tal.
Así que no hace falta que hagamos absolutamente nada por ahora.
Luego ya veremos si necesitamos alguna cosa extra.
Devolvemos la ID y ya está.
Ya tendríamos el registro, ¿vale?
Ya tenemos el registro, pero nos faltaría...
Esto sería en el repositorio.
Como os digo, esto con la base de datos que vosotros queráis.
Vamos aquí, vamos a nuestro register y aquí tenemos que sacar la información.
Tenemos que recuperar el username y el password, pero ¿de dónde lo sacamos?
Aquí nos ponen rec.body.
¿Y el body?
¿Qué es esto del body?
El body es el cuerpo de la petición.
Esto es una cosa que el usuario, por ejemplo, aquí en Jack lo vamos a ver muy claro.
Cuando ves que aquí pone body, pone no body.
Y aquí tenemos diferentes formas de enviar información al backend, ¿no?
Tendríamos el form data, text content, que es el que vamos a utilizar, en formato JSON.
Vale, pues aquí nosotros le vamos a querer pasar, por ejemplo, el username, que va a ser midudev.
Y, bueno, midudev.
Vamos a poner otro.
Vamos a poner uno del chat.
A ver, mira, dice por aquí New.
Dice, solo después de generar mil millones de UIDs cada segundo, por los próximos 100 años,
la probabilidad de crear un duplicado es del 50%.
O sea, madre mía, o sea, imagínate.
Vamos a poner, por ejemplo, JS lacro.
Igualmente, pongamos que se duplica.
El tema es que, normalmente, las UIDs son campos primarios.
Si se duplica y se intenta introducir algo que tiene la ID duplicada, petaría y ya está.
O sea, no pasaría nada.
Sería muy raro que pasase algo porque, al final, intentaría meter la misma ID que normalmente es la primary key y ya está.
Entonces, te diría, o si no es primary key, que normalmente lo es, sería unique key seguramente.
Entonces, no habría ningún problema.
Bueno, vamos a poner username JS lacro.
O sea, es un poco difícil JS lacro.
JS la, le voy a llamar, ¿vale?
Y password vamos a poner 1, 2, 3, por ahora.
Pues esto sería el cuerpo de lo que estamos enviando a nuestra API y es lo que vamos a querer recuperar.
Este username y este password, ¿ves?
Este username y este password.
Pero este rec.body es un poco especial.
Y ahora veremos por qué.
Porque aunque me encantaría que esto fuese mágico y que te recuperase el cuerpo como si nada, en realidad hay un trabajo ahí que tenemos que hacer.
Vamos a poner, por ahora, como que sí que lo estamos recuperando.
¿Qué es lo que vamos a intentar aquí?
Vale, vamos a intentar, pues, llamar a este user repository, que es el que acabamos de crear, y llamamos al método create y le pasamos el username y el password.
Este user repository es aquí.
Como lo hemos puesto que sea estático, no tenemos que instanciar, no tenemos que hacer un new ni nada.
Hacemos user repository punto create, porque hemos puesto que es estático.
Los métodos y propiedades estáticas podemos utilizarla sin necesidad de crear una instancia de la clase, ¿vale?
¿Por qué utilizo el static y no sé qué?
Bueno, porque creo que queda bastante encapsulado aquí dentro y queda muy bien pensando en que tenéis que cumplir el mismo contrato.
Esto con TypeScript, que podríamos crear una interfaz, quedaría buenísimo.
Pero como no tenemos TypeScript, pues no se crea la interfaz, pero tenéis que hacer a la idea y ya está, ¿vale?
Entonces, tendríamos aquí ya la idea del usuario.
Vamos a devolverla, en el caso de que tenga la idea del usuario, solo para ver que todo ha ido bien.
Y vamos a tener, si tenemos algún error, pues bueno, vamos a poner un status 400 y vamos a mandar el error.
Vale, cuidado con esto, cuidado con esto.
Normalmente, vamos a mandar directamente el error message, pero normalmente no es buena idea mandar el error del repositorio, ¿vale?
¿Por qué?
Es verdad que aquí sí que hemos hecho bastante, hemos tratado bien el error y aquí nos faltaría, por ejemplo, hacer aquí un try o no.
Aquí esto al final se hace un, si manda el error, pues que lo mande y ya nos lo quedamos arriba.
Pero este es el problema. Imaginad que esto peta, crea una excepción y aquí la devolvemos directamente este error.
A ver, este error seguro que lo habéis visto millones de veces en un montón de sitios.
De que se devuelve un error con demasiada información.
Y puedes mandar información de la base de datos, de tu tabla, del código, el número de dónde está el error, un montón de cosas, ¿no?
Entonces, una cosa que podéis hacer es evitar este tipo de cosas, ¿no?
Podéis decir, oye, el error, aquí podéis ver cuál es el error, ¿no?
Podéis decir, oye, si el error, el mensaje de error es igual o si el error es tal, pues hago una cosa o hago otra.
Nosotros lo vamos a dejar en este caso, aunque ya hicimos en una de estas clases, que no me acuerdo en cuál,
pero o incluso, mira, tengo un vídeo, error como un senior, ¿vale?
Donde lo explico y hoy no lo vamos a hacer.
Este, maneja los errores de JavaScript como un senior.
No vamos a hacer todo esto, porque no vamos a estar 20 minutos haciendo esto,
pero la idea sería un poco, ¿veis?
Poder crear vuestros propios errores, extendiendo de error y haciendo estas cosas.
Y así, pues puede ser bastante interesante, porque podéis mandar qué tipo de errores sin la información del error
y desde el frontend sí que podríais decir, vale, este tipo de error, tengo que hacer esto, ¿vale?
Sin necesidad de tener toda la traza o todo el mensaje de error, ¿vale?
Y solo el tipo del error para así saber exactamente qué es lo que ha pasado sin darle tanta información.
Así que, para que lo sepáis, yo lo voy a hacer así, pero se puede hacer de otra forma,
solo que no quiero que perdamos tiempo en esto, si ya tenéis un vídeo que ya lo hace.
Vale, entonces, con esto en principio, en principio, porque ya veremos que no,
deberías traer esta información y aquí tengo un console.log que me diría aparecer el username y el password.
Si envío la petición, ¡pum! ¡Peta!
Y error 500, nada menos.
Y me dicen, no puedes estructurar la propiedad username de reg.body porque está en define.
¿Pero veis este error? ¿Veis este error?
Este es el error que no queremos enviar al frontend, ¿vale?
Este es el tipo de error que queremos evitar enviar al frontend.
Aquí lo estamos haciendo porque, de nuevo, ya os digo que no importa.
Pero este tipo de error, nosotros aquí deberíamos hacer un try-catch, evitar que esos errores llegasen realmente al frontal.
Lo estamos haciendo porque, ya os digo, que estamos aquí en un curso.
¿Por qué? Si está bonito.
No, hombre, no está bonito nada.
Y fijaos toda la información que está dando.
Está dando la línea, está dando toda la ruta, está diciéndote aquí todas las dependencias,
la versión de las dependencias.
¿Sabéis lo que es esto?
Esto es un donut para los hackers.
O sea, no hay cosa más dulce que esto, ¿vale?
Esto es un donut, bueno, no sé si le llamáis donut o donut, o dona, como le queráis llamar.
Pero es esto.
Es esto, ¿vale?
Es, vamos, lo más sabroso que se pueda meter en la boca un hacker.
Más que un caramelo.
Un caramelo no es nada.
Rosquilla.
¿Le llamáis rosquilla?
¿Churro?
¿Cómo le voy a llamar churro?
Esto es todo lo contrario a un churro.
Si justamente le falta lo del medio, que es el churro.
Bueno, es una...
Yo le llamo donut aquí.
En otros sitios le llaman dona o dognat o lo que...
¿Cómo le callas?
Donas.
Vale, pues una dona.
Está bien.
Muy bien.
Pues continuemos, continuemos.
No hagáis esas cosas de mostrar todos los errores, que ya os lo he explicado.
El problema es que esto nos ha dicho que es undefined.
Y esto es porque, por defecto, Express no tramita el cuerpo del formulario cuando se lo estás enviando como un tipo JSON.
Entonces, tenemos que hacer un poquito de trabajo en esta parte, muy poco.
Lo único que tenemos que hacer es utilizar lo que se le llama un middleware.
Un middleware es un método que se ejecuta, una función que se ejecuta antes de que llegue a las peticiones, ¿vale?
Pasa la petición por ahí, trata esa petición y entonces hace que en los siguientes endpoints, si es que llega alguno, tengamos algún tipo de modificación, validación o alguna cosa.
Ahora, aquí le estamos diciendo, en la aplicación quiero que utilices el middleware express.json.
No hace falta instalar nada porque ya viene incorporado en Express, ¿vale?
Y Express.json lo que va a hacer es mirar si la request, si la petición, tiene algo en el cuerpo, como un post y tiene en el cuerpo un JSON y lo tiene que transformar y te lo va a dejar disponible en request.body, ¿vale?
Solo con esa línea ya lo deberíamos tener.
Ahora, si nos vamos aquí y le damos a check, ¿vale?
Mid, gracias por hacerme recuperar el amor por la programación.
Ya me llegó una chamba de una landing la Jare con Astro.
¡Qué bueno!
Muy bien, me alegro, amigo.
Vale, lo malo, no sé por qué, me dice que username tiene que ser, tiene que, tiene que, no sé qué.
Vamos a ver por qué, porque aquí se supone que este username y este password debería llegarle.
Ah, espérate, estoy utilizando, este es el register y este es, ah, register también, ¿vale?
Dice username must be a string.
Bueno, vamos a ver por aquí.
Y username, si es diferente a string, claro.
Si es diferente a string, vale, pues sí, debería estar, ¿no?
Bueno, vamos a ver si es que igual hay alguna cosa que se le ha ido la olla al watch, que no lo está pillando.
¿Hay algún error?
Me dice que no, pero a ver, yo estoy bastante seguro, no sé si es que no lo está enviando, no sé si es que no lo está enviando, no sé si es que no lo está enviando o, ¿ves?
Vale, ahora sí, ahora sí.
O sea, me da la sensación que era el JSON este, me da la sensación que era culpa de la aplicación, porque fijaos que ahora ha cambiado el error, que esto sí que lo entendía, ¿vale?
Porque fijaos que el password, ahora sí, son solo tres números, vamos a poner el password infinito, ¿vale?
4, 5, 6, y ahora, ¿vale?
Ahora me ha creado el usuario, me da un 200 y aquí tendríamos la ID del usuario, ¿vale?
Si ahora le vuelvo a dar otra vez, fíjate que le doy aquí a enviar, ¡pum!
El usuario ya existe, de nuevo, a lo mejor estos errores, no deberíamos, a ver, este error, este mensaje, porque ya lo hemos tratado un poco, sí que puede estar bien
y ya no estamos enviando tanta información, pero fijaos que ya no me permite enviar el mismo usuario y si miramos nuestra base de datos, ¿vale?
Aquí tendríamos la información del usuario, primer error, error grave, error grave, grave.
Esto son cosas que solo haría Microsoft, ¿vale? En las que te deja la base de datos en texto plano, porque si nos fijamos aquí, fíjate que tenemos que, sí, la ID, el username y el password,
toma, ahí tienes el password. Esto es lo que se le dice tener el password en texto plano.
¿Qué significa texto plano? Pues que no tenemos ningún tipo de codificación ni nada, estamos exponiendo el password de nuestro usuario
y lo que es peor es que a la mínima que esta base de datos se filtre, pues fíjate que grave error.
Ya con este password, ¿qué es lo que suelen hacer muchas veces? Pues si además tienes el email, pues empiezan a intentar utilizar este password
ya no solo en el mismo servicio que han hackeado, sino que en tu email, donde sea, y estás jodido, jodido.
Es como si te metieran un puño por el... En fin, total, que vamos a ver cómo podéis, cómo tenéis que arreglar esto.
No guardéis nunca el password en texto plano. Error mío, lo he hecho mal, vamos a arreglarlo en un momento.
Lo primero, vamos a instalar Bcrypt, que lo que nos va a permitir justamente es codificar en un hash,
que se le llama, nuestra contraseña. Y lo bueno de este hash es que va a ser un hash único
que vamos a poder comparar con el password que guardemos hasheado, pero no vamos de ninguna forma,
vamos a ser capaz de hacer... O sea, no vamos a poder sacar del hash, no vamos a poder sacar realmente nunca
cuál era el valor que teníamos, ¿vale? O sea, no vamos a poder transformar del hash al texto plano,
sino que siempre lo vamos a tener que comparar ya hasheado, ¿vale? Siempre vamos a tener que mirar
ya con el hash y le podemos pasar con una función, que la veremos ahora, la comparación.
Pero no vamos a poder hacer como... No, no, pero dime de este hash cuál era realmente el texto plano,
que lo quiero saber. Porque si pudieras hacer eso, pues entonces, ¿qué gracia tendría?
Ya no tendría ningún tipo de gracia, ya sería una cagada importante. Pues no va a funcionar así.
Una cosa importante de Bcrypt, que lo sepáis, al final esta biblioteca la tenéis disponible
en Node.js, pero que realmente es una versión que hay en Node.js. Tenéis versiones en un montón
de sitios, ¿vale? Lo digo porque hay veces que la gente se cree, ah, no, es que esto solo existe
en Node.js, esto de Bcrypt. Y no, lo podéis utilizar en más sitios, ¿vale? Vamos a evitar esto
del texto plano. ¿Dónde lo vamos a hacer? Bueno, pues por suerte, ya tenemos este repositorio,
ya hemos instalado la dependencia de Bcrypt, ¿vale? Y aquí vamos a importarla. Mira, para hacer
la distinción en qué dependencias son de Node, porque esta de Cripto es de Node, y cuáles son
externas, vamos a poner ahí Node 2 puntos, y aquí vamos a importar también otra vez Bcrypt,
from Bcrypt, ¿vale? ¿Y qué hacemos? Pues nada, antes de guardar este password, después de las
validaciones, lo que vamos a hacer aquí es decir, bueno, vamos a hacer un hash, vamos
a hashear, bueno, vamos a hacerlo después de esta validación, realmente, porque antes
no lo necesitamos, y aquí hacemos un hash password, y llamamos Bcrypt.hash. Tenemos hash y hash
sync. Ahora os explico los dos, vamos a intentar primero el sync, que es más fácil. Y primero
le ponemos cuál es el password, ¿vale? Y luego un número mágico, que se llama salt
roll. ¿Qué es esto de salt? Esta es la sal, la sal, sería la sal, salt. Es la sal,
esta es la sal, ¿vale? Vale, ¿qué es exactamente esto de la sal, de la vida y tal? Esto realmente
lo que está haciendo, a ver si sale otra vez, aquí lo tenemos, ¿vale? Dice, esto es lo
que se hace es para generar el password hasheado, ¿vale? Para codificar nuestro password. Y el
número de veces es el número de, como de vueltas que le va a dar, cuanto mayor sea,
obviamente va a ser como más potente la codificación, pero el problema es que va a
tardar más tiempo. O sea, que hay que intentar tener algún tipo de cuidado de decir, a ver,
voy a codificarlo lo suficiente, pero tampoco quiero que esto me tarde media hora. Así
que cuanto más grande sea, pues vamos a tener aquí más codificación, pero va a tardar
más tiempo. Normalmente se suele poner un 10, ¿vale? Por eso es este número mágico
de 10. Si una cosa que se puede hacer no solo es tenerlo aquí en una constante, sino que lo
podéis poner en una configuración. ¿Por qué? Porque normalmente, ¿ves? Salt rounds. Normalmente,
dependiendo del entorno, vais a poner más o menos. Por ejemplo, en producción es posible que os
interese que sea más grande y en test a lo mejor os interesa que sea más pequeño para que vayan más
rápido o en entorno de desarrollo, ¿vale? Solo para que lo sepáis. Yo creo que con 10 es suficiente,
pero solo para que lo tengáis en cuenta. Vamos a importar este import salt rounds y este salt rounds,
¿vale? Pensad que es echarle sal. Pero claro, cuando tienes demasiada sal, pues le da hipertensión,
¿ok? Vale. Y este hash password es el que vamos a guardar ahora, ¿ok? Y lo guardamos así. Esto es,
vamos, importantísimo. Ahora vamos a borrar, o bueno, voy a poner otro usuario, vamos a poner mi dudeb,
¿vale? Guardamos aquí. Me lo ha guardado perfectamente. Si le doy otra vez, el usuario
ya existe. Y si vamos a nuestra base de datos, fijaos que ahora sí me ha creado esto aquí,
hasheado en condiciones. ¿Vale? ¿Qué es lo que pasa? Esto funcionar funciona bien, lo estamos viendo,
pero un detalle importante, ¿eh? Técnicamente el front de inicio no debería enviarlo en texto plano.
Eso no tiene ningún sentido, te voy a explicar por qué. Pongamos que el front desde un inicio no lo
debería enviar en texto plano, ¿vale? Y que realmente hacéis algo, generáis algo desde el
front para evitar que no lo envíe en texto plano. Da igual. O sea, todo lo que hagas en el cliente es
código que está expuesto y que, por lo tanto, da igual el cómo lo hashes porque cualquier persona
va a poder ver el JavaScript para ver cómo lo estás hasheando. Lo que es importante realmente es
que utilices HTTPS, porque esto es lo que se va a significar, es que cuando tú lo envíes del cliente
al servidor, esa conexión es segura y, por lo tanto, los datos que se transmiten están codificados.
Entonces, no es tan importante lo que tú haces en el cliente y no enviarlo en texto plano, porque tú,
si lo hasheas, aunque tú quieras hashearlo, ya está, ¿vale? Tú imagínate que lo hasheas en el cliente
increíble. Cualquier persona puede ver en JavaScript cómo utilizas esos hasheos y qué estás utilizando
para hacerlo y ya está. O sea, tampoco te está haciendo, no está dando ningún beneficio. Todo lo contrario.
El problema es que encima, luego en el backend, tienes que validar realmente que el password sea
correcto, que tenga una longitud y tal. Esas validaciones se tienen que hacer en el backend.
Entonces, lo que es realmente importante es utilizar HTTPS para que las requests, las peticiones,
estén bien codificadas, ¿vale? Ahí lo tendrías. Se intercepta la petición. Como digo, con HTTPS,
se intercepta la petición no deberían ser capaces de ver muchas cosas, pero es que da igual. Se intercepta
la petición. Es como si hay mucha gente que dice, y si tienen acceso a mi cookie, es que si tienen
acceso a tu cookie, está jodido, ¿eh? O sea, está jodido ya. O sea, si alguien tiene acceso a tu
ordenador físico, ya te van a estar judiendo directamente, ¿eh? Y además, de temas de cifrado,
aunque hay cifrados simples, la idea es que tengáis el cifrado completo. ¿Ves? Y si tienen acceso a mi cookie,
claro, es que... Y si tienen acceso a mis contraseñas, es que, claro, es que hay un montón de cosas que,
al final, luego para eso hay otro tipo de cosas como, por ejemplo, la autentificación en dos pasos y todo
esto, pero claro, al final... Y si alguien tiene tu móvil también físico y se sabe también la
contraseña. Así que, claro, estas cosas no tienen mucho sentido. Bueno, total, ¿qué os he dicho?
Esto de HashSync. ¿Esto qué significa? Esto significa el HashSync bloquea el thread principal.
Esto justamente lo vimos ayer. ¿Qué quiere decir? A ver, codificar, hacer cualquier cosa de codificación
es costosa, ¿vale? Es costosa porque al final la criptografía, pues se tiene que hacer, hay muchos
cálculos y tal, queramos o no, pues va a necesitar tiempo de computación. ¿Qué es lo que podéis hacer,
al menos, para mejorar un poquito esto? Lo que podéis hacer es utilizar la forma asíncrona.
Entonces, en lugar de bloquear el thread, lo que puedes hacer es utilizar el punto Hash. Pero esto
lo que hace es devolver una promesa. Así que hay que hacerle un Await. Y como vamos a utilizar un Await,
vamos a tener que poner aquí un Async, ¿vale? Para poder utilizar el Await, vamos a tener que decirle
que esta función es asíncrona. Y ahora esto va a funcionar exactamente igual, ¿vale? Mi DUDEP2,
guardamos, ¿vale? Y no me la he devuelto. ¿Por qué no me ha devuelto esto? ¿Qué he hecho mal?
¿Qué he hecho mal? ¿Por qué no me ha devuelto mi D? Ah, vale. Ahora ya sé lo que decís. Cierto, me falta
esta Await. Tenéis toda la razón, tenéis toda la razón. Menos mal que os tengo, ¿eh? Menos mal que os tengo.
¿Ves? Por eso me tendría que hacer más chuletas para hacer estas cosas. Es verdad que he cambiado esto
a Async Await y luego aquí no lo he cambiado. Esto es interesante y este error mío,
mío, error mío, gracias. Pero este error es interesante porque esto es lo que os decía
antes de que os tenéis que asegurar que siempre tenga el mismo contrato. ¿Esto qué quiere decir?
Que si luego cambiar la base de datos, lo importante es que aunque cambies todo esto,
¿vale? Que todo esto puede cambiar, todo esto puede cambiar, pero todo lo demás no.
Ni lo que devuelves, ni los parámetros, ni obviamente cómo lo utilizas en otro sitio.
Entonces, obviamente es importante que si utilizáis Async Await, pues aquí hay que utilizar la
Await porque si no, no funciona. Gracias porque no había caído. Ahora obviamente esto me dice
que existe y aquí ahora sí tenemos la ID funcionando perfectamente. Típico error, ¿eh? Típico error,
típico error. Vale, ya tendríamos esto del texto plano, perfecto. Vamos con la autentificación
típica basada en lo típico, ¿no? Usuario y contraseña y los errores que tiene. Podríamos aquí,
ya tenemos el login, lo tenemos aquí, el login. ¿Y aquí qué? Pues cuando hacemos el login del
usuario tendríamos que hacer otra vez todas estas validaciones, ¿vale? Tendríamos que hacer otra
vez todas estas validaciones. ¿Pero esto tiene sentido? No. ¿Por qué? Porque no queremos repetir
código y en este caso tiene bastante sentido. Entonces, yo voy a hacer esto, pero de nuevo,
yo creo que lo mejor sería utilizar algo como Zot. ¿Por qué? Porque así ya tenéis un esquema,
que validáis las cosas mucho más fácil y tal. Pero bueno, podríamos crear también una clase con
las validaciones, con todos los errores y tal. Y aquí, por ejemplo, pues devolveríamos estas,
las podríamos poner aquí, ¿vale? Para no repetir el código. Estas las podríamos poner aquí.
Y además, estas validaciones las podríamos sacar a un archivo, ¿vale? Y estas validaciones ya
podríamos hacer validation.username, validation.password y estas dos también las podríamos
hacer exactamente aquí. Algo que os recomiendo, porque al sacar las validaciones del repositorio,
lo que podéis hacer es que estas validaciones, independientemente de la base de datos que
utilicéis, las vais a poder reutilizar, ¿vale? O sea, que ahí ya veis un poco la idea esta de
reutilizar. Se podrían incluso inyectar las validaciones por dependencias, por parámetro,
pero bueno, eso ya más que nada para que tengáis la idea. Así que estas validaciones las reutilizamos.
Y ahora que ya estemos aquí hechas, lo primero que vamos a hacer cuando tengamos un login,
primero vamos a buscar el usuario. Porque si el usuario existe, bien. Si no existe, pues
está la cosa de que te vas a iniciar sesión si este usuario no existe. Si no tenemos usuario,
pues le decimos, oye, que el usuario en esta base de datos no existe, que te lo has inventado.
Y luego tenemos que mirar si es válido. Si es válido, ¿cómo lo miramos? Tenemos que comparar
con bcrypt. Fijaos otra vez que tenemos el compare sync, ¿no? Tenemos que comparar el
password que nos pasan con el que tenemos hasheado, ¿vale? En la base de datos. Este sería
el que nos pasan y este el que tenemos hasheado en la base de datos. Entonces, este compare
internamente ya va a hacer esta comparación entre los datos que tenemos encriptados y los
datos que nos están pasando desde fuera, ¿vale? Pero en ningún momento nos va a decir,
o sea, solo nos va a decir true o false, pero no nos va a decir, claro, aquí sí que
podríamos llegar a saber, si pongo un console log y miro el password y luego me devuelve
un true, obviamente, podría saber que ese password es el del hash. Pero el tema es que
es difícil que un usuario te esté ahí constantemente y el probarlo así a lo bestia
no es tan fácil, ¿vale? Te tienen que hacer un ataque muy bestia y que normalmente va a ser
mucho más problemático el tema del rate limit porque tendrían que hacerte tantas
peticiones para sacarlo así a fuerza bruta que, hombre, te darías cuenta que te están
atacando. O sea, que tenlo en cuenta. No dejes un console log, no hagas ninguna cosa y ya
lo tendrías así, ¿vale? Entonces, internamente esto va a hacer la comparación, no te vas
a tener que preocupar. No es que lo desencriptes, sino que lo que hace en realidad es encriptar
este password y va a comparar el que está hasheado con el que le ha pasado. Pero no es
que lo va a desencriptar. Importante, ¿vale? No penséis que lo desencripta porque es que
eso no es lo que va a pasar. No los desencripta, sino que lo que hace es encriptar este para
comparar el resultado. Y una vez que ya tenemos esto, podemos decir, oye, si no es válido,
pues el password es inválido. Y si no, pues vamos a devolver el usuario. Así estaríamos
haciendo el check del login. Cuando ya tenemos este login aquí, tenemos que irnos aquí al
login y vamos a ver qué hacemos. Vale, sacamos otra vez username y password del request.body y
vamos a intentar recuperar el usuario de nuestro repositorio. Importante, el repositorio, no
sé si lo he puesto compareSync. Vamos a hacer que sea asíncrono también, ¿vale? También
tiene su forma asíncrona con el compare, ¿vale? Con el async await. Así que aquí también
nos aseguramos que hacemos una await y esto tiene que ser un método asíncrono. Y aquí
pues vamos a hacer el login, pasándole el username y el password. Y nada, vamos a enviar
el usuario, aunque ahora veremos esto, ¿eh? Ahora veremos esto porque esto es otro error
muy común que muchas veces se comete y que vamos a arreglar. Entonces, aquí vamos a darle
un 401 porque se supone que no tiene autorización y vamos a enviar el mensaje, aunque ya hemos
visto antes que si podemos evitar enviar todo el mensaje, mejor que mejor. ¿Vale?
Entonces, con esto deberíamos ser capaces de hacer o de iniciar sesión. Vámonos a Jack,
¿vale? Que ya teníamos aquí este. Voy a iniciar otro. Ah, mira, una cosa que se puede
hacer, si no me equivoco, es duplicar. Entonces, vamos a duplicar y este lo voy
a transformar en un login y le damos aquí y fijaos, ahora ya tenemos el login, ha
iniciado sesión, pero ¿qué está pasando aquí? ¿Pero esto qué es? ¿Pero esto qué
es? Que, a ver, esto de enviar todo el usuario tiene muchos bichos. De hecho, si
utilizáis TypeScript, es muy buena idea que tengáis como diferentes interfaces o tipos
para los usuarios. Digamos, la información pública del usuario y la información privada
del usuario. Entonces, tendríais el usuario completo y tendríais que omitir esas propiedades
que no deben estar en la pública. Y una de ellas, por supuesto, es el password. No
hace falta que enviéis todo el usuario con el ID, el username y sobre todo el password.
No enviéis el password nunca, jamás. ¿Vale? No enviéis el password. Entonces, para arreglar
esto, lo único que tenemos que hacer, ¿vale? Nos vamos por aquí y cuando hemos recuperado
el usuario que nos dice que es válido y tal, pues aquí deberíamos como separar. Ya
os digo que con TypeScript esto os ayuda mucho el poder separarlo. Vamos a sacar el password.
Vamos a poner aquí private password o incluso podemos ponerle un underscore porque no lo
vamos a utilizar. Y aquí vamos a poner public user. ¿Vale? User. Esta forma es una forma
que es bastante interesante. Esto es una forma elegante de quitarle propiedades a un objeto.
¿Vale? Imagínate que tú no quieres ni devolver el password, ni el rol, ni otro campo que tengamos
en user. Hay dos formas de hacerlo. Uno podría ser pues empezar a crear un objeto desde cero,
que esto puede ser interesante. Por ejemplo, username punto public user username. O sea, bueno,
user punto username, ¿no? Y aquí ir creando constantemente, pero si solo es un campo el
que quieres quitar, pues a lo mejor te puede ser buena idea hacer esto. ¿Cuál es mejor? A ver,
normalmente puede ser mejor el otro, el largo. ¿Por qué? Porque entonces así, si el día de mañana se
añade un nuevo campo en la base de datos, no se te va a colar por arte de magia. Así que está siendo
mucho más explícito de cuáles son los campos que quieres devolver. En este caso estamos siendo
explícito, pero sobre, solo sobre los que no queremos devolver, que en este caso sería el password.
Pero si el día de mañana resulta que pongo aquí refresh token, pues la vamos a liar, vamos a tener
que tocar código y tal. Entonces, cualquiera de las dos, no es que haya una perfecta, pero para que lo
tengas en cuenta en los dos casos, ¿vale? Pues aquí en este caso lo vamos a hacer así, que nos lo
simplifica y ya está. Muy bien, ya tendríamos todo el registro, el login parece que funciona,
perfecto, el login funciona. Si le pongo un password que no es, pues me dice que el password es
invalid, ¿vale? Si intento utilizar un usuario que no existe, me dice que el usuario no existe. Si lo
pongo todo, pues ya tenemos el login. Esto está muy bien, pero claro, normalmente el login y el registro
no se hace a través de una API y ya está, sino que se tiene que renderizar una página. Como es una cosa
que no hemos visto en el curso de Node.js, el renderizar una página, lo vamos a ver en un
momentito y vas a ver lo fácil que es. Vamos a crear aquí una carpeta, una carpeta views y
dentro voy a poner example.ejs. Vamos a utilizar un template engine o un sistema de plantillas.
Hay muchas, variadas, podéis utilizar handlebars, mustache, podéis utilizar el que queráis. A mí,
uno de mis favoritos que le recuerdo, lo recuerdo con mucho cariño, es ejs, ¿vale? ¿Por qué? Pues no
sé, porque la e es de elegante, efectivo, fácil, no sé, el que queráis. Pero hay un montón,
utilízate el que más rabia os dé. Igualmente este es muy sencillo porque el sistema de plantillas
está basado en JavaScript. Entonces cualquier cosa que en cualquier momento veáis, pues vais a ver
que va a ser con JavaScript, ¿no? Así que vamos a echarle aquí un vistazo. Vámonos aquí,
example.ejs. Y aquí pues vamos a crear con HTML. Vamos a poner aquí body. Y bueno, esto sería como
para que lo veamos, pero para que veáis el sistema de plantillas funciona así. Hay que poner el menor
que, el tanto por ciento y aquí lo que queremos evaluar, ¿vale? Esto sería hola name, ¿vale?
Esta sería la forma en la que se tiene que utilizar. Aunque luego veréis que también se puede evaluar
código JavaScript ahí dentro. Este sería el ejemplo y ahora le vamos a decir que en nuestra
raíz, en lugar de enviar esto, vamos a renderizar este sistema de plantillas. Para eso tenemos que
hacer unos pocos pasos. Uno, en nuestra app le tenemos que decir cuál es el sistema de plantillas
que queremos utilizar. Entonces le decimos que el Vue Engine es ejs. Ya os digo que hay diferentes,
este es uno de ellos. Ahora, aquí en el res.sen vamos a utilizar otro método que es render. Y le
decimos que queremos renderizar el example, ¿vale? Fijaos que ya automáticamente ya sabe que va a
utilizar la carpeta Vue. ¿Por qué? Porque esto es como una configuración ya preestablecida que dentro
de la carpeta Vue se ponen todas las plantillas. Entonces ya le pones el nombre de la plantilla,
que es example, y ya la detecta. Y luego le podríamos pasar la información que queremos
poder acceder aquí dentro. Aquí tenemos name, ¿vale? Pues vamos a poner name y vamos a poner
midudev, por ejemplo. Y esta propiedad vamos a poder accederla aquí directamente. Este names,
le cambiamos username para que lo veáis, ¿vale? Tenemos que cambiar aquí username. Y solo nos falta
un paso más, que obviamente es instalar la dependencia. Pnpm install ejs, la instalamos,
guardamos aquí los cambios. Y ahora, si nos vamos a localhost 3000, ¿vale? Fijaos que me pone
hola midudev. Si cambiamos aquí el nombre y pongo feralp, pues aquí tenemos a feralp. O sea,
que ya está funcionando nuestro sistema de plantillas. Es un ejemplo sencillo, pero ya tenemos aquí una
plantilla. Como no quiero perder tiempo escribiendo HTML, toda la plantilla y todo esto, voy a hacer
solo que este example vamos a crear, vamos a utilizar aquí protected. Lo vamos a utilizar
también como si fuese la página protegida. Vamos a poner este contenido. Esta es protegido. Está
protegido, ¿vale? Y este example lo vamos a eliminar. Pero ya os digo, como no quiero perder
tiempo HTML, estilos y todo esto, y me quiero enfocar totalmente en el tema de Node.js, vamos a hacer una cosa
y es que ya he preparado una vista que es la que quiero utilizar en el index. Entonces, index.js, os lo enseño
un poquito, todo lo que hace esto. ¿Qué es lo que hace? Bueno, esto es lo que va a enseñarnos. Son unos
formularios de inicio de sesión y de registro. Y además tiene un poquito de lógica, porque si se le pasa
al usuario, lo que vamos a hacer es que le vamos a saludar al usuario y le vamos a dar la oportunidad
de cerrar la sesión. Si el usuario no ha iniciado sesión, lo que vamos a hacer es enseñarle tanto
el login como el registro. Y tiene un poquito de JavaScript aquí, que lo que hace es hacer los
posts que hemos hecho en esta aplicación, tanto el login como el register. Eso lo está haciendo aquí
con JavaScript. Hacemos un fetch, que es la forma de hacer peticiones nativas sin dependencias en
JavaScript. En el cliente le decimos que el método es post, como hemos hecho justamente
aquí, ¿no? Que tenemos aquí el post y que le vamos a enviar el cuerpo con el tipo de
contenido como un JSON, que lo teníamos, joder, otra vez, que no sé por qué se me va
para arriba. Lo tenemos, ¿lo ves? Content type, le decimos application JSON y le enviamos
como una cadena de texto el username y el password. Y aquí, una vez que tenemos la respuesta,
enseñamos unas cositas visualmente para que se vea el usuario y luego enviamos al usuario
a la próxima página, al protected, ¿no? Que ahí es donde se supone que ese contenido
está protegido y solo el usuario, si ha iniciado sesión, lo podrá ver. Lo mismo con el registro,
es exactamente lo mismo, la misma idea y hace exactamente lo mismo. Y luego lo mismo para
cerrar sesión. Este índex es el que vamos a querer renderizar aquí y por ahora no le vamos
a pasar nada porque no tenemos nada, así que renderizamos el índex, no le pasamos ningún
objeto, deberíamos ver el formulario de inicio de sesión y de cerrar sesión, ¿vale? Entonces,
vamos a ir a verlo, a ver si funciona. Vale, pues funciona. Tenemos aquí el formulario de inicio
de sesión y el de registro. ¿Hasta aquí alguna pregunta? Entonces, así es como se realiza
una app con el backend en el mismo sitio de servicio. Claro, a ver, muchas veces aquí
lo que podéis hacer es justamente renderizar y, de hecho, se podría hacer incluso con una
aplicación de React sin ningún problema. Tendríamos que utilizar React en service
rendering, pero se podría hacer. Pero ¿cuál es mejor, EJS o React? Yo sé que siempre
os encanta decir, ¿cuál es mejor? Primeros que no son comparables. Lo segundo es que no
hay uno mejor que el otro porque como no son comparables, pues es imposible. Entonces,
React lo que te permite es utilizar lo mismo el servidor y el cliente.
¿Por qué eres tan guapo?
Muchas gracias, Maco. El tema no es que sean mejores, que son totalmente diferentes. Seguramente
para una aplicación mucho más grande y tal sería interesante utilizar React porque
lo mismo que renderizas en el servidor, lo renderizas en el cliente y además en el cliente
le darías interactividad, que sería interesante. Esto sería un ejemplo de service
rendering totalmente. Esto es service rendering porque si miráis el page source vais a ver
que tenemos todo el HTML que se está renderizando en el servidor y esto lo que hace es que vaya
tan rápido. Claro, obviamente.
Cuando usas cookies, tanto el back como el front tienen que estar obligatoriamente en el
mismo puerto URL para que se pasen correctamente las requests. Sí y no. De hecho, de eso
vamos a hablar ahora después, que es interesante. En el front del password se puede
ver. Sí, en el front el password se puede ver. De hecho, antes lo hemos comentado porque
es interesante. O sea, porque da igual que en el front se pueda ver el password porque
al final si en el front alguien tiene acceso directamente a tu front es que ya estás, ya
la has cagado directamente. O sea, si alguien puede ver, por ejemplo, cómo estás escribiendo,
pues es que ya le estás jodido. Y en el front no está el ataque porque eso es lo que significaría
es que vamos a tener acceso a la máquina del usuario. Si en el front va a tener... Otra
cosa es que te intercepten las peticiones y tal. Pero ahí es donde vamos a necesitar
otro tipo de asegurarnos, ¿no? De, por ejemplo, utilizar protocolos que están cifrados como
HTTPS y este tipo de cosas, ¿vale? Si guardo el token en la cookie cada vez que se
refresca la página en front y que volverá a validarla el token. Bueno, ahora lo veremos.
Si llegamos al refresh token, lo veremos, ¿vale? Así que vamos a darle.
¿Por qué compare no utiliza salt? Porque ya está hasheado, ¿vale? O sea, ya está hasheado
el password, ya está hasheado en sí y ya no necesita el salt para saber cómo deshassearlo.
En el hash, aunque no lo parezca, claro, porque nosotros vemos el hash, pero hay que tener
en cuenta que en el hash que tenemos nosotros aquí, cuando nosotros hasheamos el password,
fíjate en una cosa. Aquí hay más información de la que parece. Por ejemplo, fíjate que el
principio, ¿ves que se parece? 2B, 10, este 10 igual nos quiere decir algo. Entonces, ya
el password hasheado tiene cierta información de cómo debe, por ejemplo, tratar, tiene como
un timestamp, tiene algunas cosas como información y entonces ya no le tenemos que pasar el salt
porque solo con el hash ya tiene información de cómo tiene que volver a hacerlo, ¿vale?
O sea, cómo tiene que hashear el otro password para poder compararlos, ¿vale? Lo que hay
al principio, ¿vale? Lo que hay al principio ya es cierta información y luego a partir de
aquí, digamos que tiene más información, otra que genera aleatoriamente y cosas así.
O sea, ese es el truco de muchas codificaciones. De hecho, con los JSON Web Tokens que vamos
a ver ahora, vais a ver que también pasa, ¿vale? Una pregunta, ¿es una manera segura cómo
se podría vulnerar para descubrir una contraseña? En estos casos es fuerza bruta. Tú tendrías
que ir probando, ir hasheando. Imagínate, dices 1, 2, 3, 4, 5, 6. Entonces lo hasheas,
miras el hash, ¿vale? Y una vez que miras el hash, compararlo. Esto sería así todo rato.
Todo rato tendría que ser así, ¿vale? En este caso, fíjate, bueno, ves que me dice el mismo,
pero esto en este caso, vete a saber si tiene que ver. Si no, lo que suele ocurrir es que de
esto se ha creado un diccionario gigante donde se pueden ver los passwords más típicos.
Por ejemplo, 1, 2, 3, 4, 5, 6, se sabe que se hasheda a tal.
Hola, amigo. ¿Cómo estás?
Espero que bien. Te mando un saludo. Últimamente me he perdido tus directos y no he renovado
mi sub debido a algunas situaciones personales.
No pasa nada, amigo.
Estoy viendo tus videos para aprender y distraerme. Gracias por tu contenido.
Gracias a ti, amigo. Muchas, muchas, muchas gracias. Pues el problema que teníamos con
MD5, que era una forma de hashear antigua, es que fíjate que aquí teníamos que tu cadena
era predecible porque siempre se hasheaba igual. 1, 2, 3, 4, 5, 6, ¿ves? Constantemente siempre
se hashea igual. Y lo mismo pasa con el SHA-1. Como siempre se hashea igual, aquí puedes utilizar
un diccionario muy fácilmente para decir, vale, voy a ver si este hash corresponde con
una cadena en el diccionario. Pero en estos, como bcrip, es que veréis que aunque hasheéis
la misma contraseña, no está el mismo hash. De hecho, hemos estado hasheando todo el rato
la de 1, 2, 3, 4, 5, 6. Pero si os fijáis, de hecho lo voy a hacer otra vez para que lo
veáis, ¿vale? Fijaos aquí, voy a hashear 1, 2, 3, 4, 5, 6 en mi dudev 10, ¿vale? Voy a enviar
aquí y fijaos, fijaos que este password que ha hasheado aquí, aunque sí que empieza igual,
luego cambia totalmente. O sea, que es muy interesante esta codificación porque no se puede
utilizar tan fácilmente un diccionario para atacarte. ¿Por qué? Porque tiene diferentes
estrategias dentro, que está haciendo tener pues una semilla, que lo que hace es, o sea, está
utilizando el salt que estábamos diciendo antes de los rounds, tiene ahí cierta información
codificada para poder hacer que sea totalmente diferente, pero aún así, con esa información,
ser capaz de compararlo sin desvelar cuál era el texto plano, ¿vale? Entonces, sí, sí,
MD5 está prohibido, ¿vale? Está totalmente, totalmente prohibido, ¿eh? Claro que dice, a lo mejor
cuenta también la fecha y tal. Claro, en este tipo de cosas también, también se puede hacer, ¿eh?
Y no hay forma de deshasear, es que no se deshasea, de nuevo, repito, no es que se deshasee, no se descodifica,
lo que hace es codificar la otra, ¿ok? No la descodifica, no hay una forma, no hay una forma de decir,
descodifícame esto, no hay una forma, no hay una forma de decir, dime cuál es la que estaba antes,
no funciona así. Lo que funciona básicamente es realmente comparar el hash una vez que lo has hecho,
¿vale? Vale, pues venga, ya que hemos hecho esto de los MD, ya tenemos aquí login y register,
por ejemplo, o sea, aquí ponemos, vamos a poner, vamos a poner alguno de que tengamos en el chat,
tenemos a fmoreno, fmoreno, le voy a llamar admin123, admin123, ¿vale? fmoreno, registramos,
¿ves? Usuario registrado, entrando, porque le he dado como un tiempo, ¿vale? Se ha quedado pensando,
no sé si lo veis, y esto es porque nos falta implementar la, ta, ta, ta, ta, ta, esta de
protected, ¿vale? Vamos a poner esta de protected.
Me doy una pregunta, en mi empresa yo trabajo en la parte del backend y debo documentar los endpoints
para que los frontend los prueben y los usen, pero hay endpoints de guardado que cuando yo los pruebo
ellos ya no los pueden volver a probar porque no son idempotentes, ¿cómo me recomiendas manejar?
Porque no son idempotentes, o sea, es que pues al final vas a necesitar, si no son idempotentes
necesitas estado, si necesitas estado, en algún sitio lo tienes que guardar, redis, base de datos,
lo que tú quieras, pero entiendo que lo vas a tener que hacer así, ¿no? Eso es lo que necesitas,
es que porque al final si lo guardas en memoria también es peligroso porque si se reinicia el proceso
por lo que sea, pues ya se te resetearía la memoria. Vale, renderizamos el protected, ¿vale?
Entonces, vale, y este es el problema. El protected nos dice que el username no lo encuentra
porque dice que username is not defined, pero es que el problema, y aquí es donde tenemos
el problema, es la falta de sesión del usuario. ¿Dónde tenemos la sesión del usuario?
Está muy bien, he podido logar al usuario, de hecho si me voy para atrás, ¿vale?
Y aquí ponemos fmoreno admin 1, 2, 3, le damos a iniciar sesión, parece sesión iniciada
entrando, es verdad que entra, o sea, es verdad que este código ha recuperado el usuario
y la contraseña, ha validado que está bien, todo ha funcionado bien, de hecho para ver
que esto funciona, si pongo cualquier contraseña me la invento, ¿ves? Error a iniciar sesión
porque nuestra API, si nos fijamos, ¿vale? Me está dando un 401, me dice que el password
es inválido, perfecto. Ahora, si le pongo admin 1, 2, 3, pues vamos a ver que me dice,
sí, sí, el password es correcto, ¿vale? Login, me ha devuelto aquí el usuario y tal,
pero cuando me lleva a la página de protegido, claro, me dice, oye, es que no tiene
su nombre de usuario y es que aquí no se lo estamos pasando, deberíamos inyectarle
aquí el username, ¿vale? Para que lo pueda tener. Pero, ¿qué problema tenemos aquí?
Que es que este protected hemos dicho que solo cuando tenemos sesión del usuario,
pero es que no tenemos sesión del usuario, ¿cómo hacemos esto de la sesión del usuario?
A ver, hay diferentes formas de crear una sesión del usuario. Una muy fácil,
pero que no vamos a ver hoy, es utilizar, por ejemplo, Express Session, ¿no?
Y esto podría crear una sesión del usuario, lo podríamos guardar en diferentes sitios,
pero esto no es lo que queremos ver. También podríamos guardarla en una base de datos,
por ejemplo, en Redis se pueden guardar sesiones de usuario y todo esto, ¿no?
Y podríamos crear en nuestra base de datos, podríamos tener, para saber si la sesión,
es válida o no, ¿no? Porque tenemos que tener sesión, tener la esquema de la sesión,
tener la ID de qué usuario, cuándo expira esta sesión, ¿vale?
Tendríamos que tener esta información y guardarla, que cada vez que haga login,
¿vale? Pues tendríamos que crearle una sesión y devolverle la ID y todo esto.
Pero, ¿cuál es el problema que tenemos con todo esto que estamos viendo de la sesión?
Dos cosas. La primera, que necesitamos lo que llamamos un estado.
Necesitamos un estado porque necesitamos, de alguna forma, guardar esa sesión en algún sitio
para verificar que el usuario, el usuario tiene acceso a todo esto, ¿no?
Que está verificado. Que la sesión es válida en el tiempo.
Que no está, no ha cerrado sesión y tal. Que esa sesión todavía existe.
Eso es lo primero. Y lo segundo es que, además, la sesión se la pueden robar muy fácilmente.
Le podrían, si alguien tuviese exactamente esa sesión que ya está guardada, pues nada,
se la roban y dice, vale, pues esta sesión, pues ahora le hago pasar por Pepito.
Y ya está, ¿no? O sea, que tendríamos otro problema.
Tendríamos toda la complejidad de tener que guardar en un estado, base de datos y todo esto,
y además también tendríamos algunos problemas de seguridad.
¿Cómo podemos arreglar esto? ¿Por qué se necesita una sesión?
Lo acabo de explicar. Porque yo ahora, si estoy viajando a otra página web,
claro, a mí el login me funciona, ¿vale? Ahora el usuario está logueado,
pero ¿cómo sabe cuando viajo a otra página web que este usuario estaba logueado?
Para saber que el usuario sigue logueado, eso justamente es la definición de sesión.
La sesión es cuando el usuario, entre diferentes navegaciones,
somos capaces de saber que ese usuario tiene la sesión iniciada.
O sea, que está logueado, que tiene permisos, que de una forma u otra identificamos
que ese usuario realmente ya ha pasado por un proceso de verificación, ¿vale?
Entonces, no vamos a querer tener un estado como tal, porque esto nos complica un montón las cosas,
así que vamos a hacerlo de otra forma.
Y para ello vamos a utilizar lo que se llaman JSON Web Tokens, o JSON Web Tokens,
con lo que queráis pronunciar, ¿vale?
¿Y qué es esto de los JSON Web Tokens? Ahí vamos a quitar este aquí.
Son un estándar que son de código abierto, que son muy seguros,
que al final lo que te permite es representar la sesión del usuario.
En realidad no es la sesión del usuario porque se puede utilizar para otras cosas
que no tengan nada que ver con la sesión del usuario.
Es una forma de comunicación de dos partes sin necesidad de tener un estado,
porque lo que tiene esto es que en este token va a guardar diferente información.
No tiene por qué ser el usuario, puede ser otra cosa, puede ser una transacción,
por ejemplo, entre dos partes, puede ser cualquier cosa.
A nosotros, en nuestro caso, sí que va a ser una sesión de usuario,
pero podría ser otra cosa que lo que queramos es intercambiar de forma segura
información entre dos partes.
Eso es lo que nos permite y nos permite además decodificar, verificar y asegurarnos
que la persona o el sistema que nos está enviando esta información es quien dice ser.
Estos tokens se dividen en tres partes, ¿vale?
Tendríamos por una parte, tendríamos el encabezado, que lo teníamos aquí,
que es lo que nos va a indicar el algoritmo y el tipo del token.
Luego tendríamos el payload, que sería esta parte de aquí, que la tenemos en púrpura,
que es donde tendríamos los datos que van a venir totalmente codificados
y finalmente tendríamos la firma.
Hay gente que le llama footer, no sé por qué, porque no tiene mucho sentido.
Yo le llamo signature, que tiene más sentido, o firma o verify signature,
como le queráis llamar, ¿vale?
Y esto es lo que va a tener, cada uno tiene obviamente un uso específico,
pero esto lo que nos va a permitir es poder decodificar este sí.
Nos va a permitir decodificar la información.
Vamos a poder verificar que el token realmente tiene sentido
y vamos a poder extraer la información que tengamos aquí, ¿vale?
Este payload lo vamos a poder tener.
Este payload es muy importante, que aunque hay parte de la información
que sí que tiene que ver con los JSON Web Tokens,
aquí podemos poner información nuestra que queramos.
Por ejemplo, este sub es el subject, ¿vale?
Que en este caso puede ser que sí que sea suyo,
el cuándo se ha enviado esto, esto es el timestamp,
pero nosotros podemos poner aquí lo que queramos, por ejemplo,
el rol del usuario, ¿vale?
Le podemos poner que user.
Vais a ver que esto va cambiando.
Conforme yo voy escribiendo, fíjate que el token que se escribe
es totalmente distinto.
Podemos ponerle incluso un array, podemos tener aquí los favoritos
del usuario, podemos decir un, dos, tres, ¿vale?
Claro, el token cada vez va a ser mayor.
La idea no es enviar toda la información de usuario en este token,
obviamente, pero sí esas partes de la información que puedan ser sensibles.
Y, hombre, la sesión del usuario, el nombre del usuario
y ciertas informaciones del usuario pueden ser sensibles
y puede ser interesante que los tengamos así, codificados, ¿vale?
Y ahora, en este Verify Signature, una parte muy importante
es que, además de que vamos a poder tener aquí diferentes formas
de codificarla y decodificarla, ¿ves?
Se utilizan diferentes algoritmos.
Esta información la tenemos aquí en el header, ¿vale?
Podríamos tener aquí, que hay algunos que son mejores,
pero vais a ver que son cada vez más costosos,
que son más grandes, que no sé qué.
¿Vale? Este será como el más sencillo.
También necesitamos una palabra secreta.
Y la palabra secreta, esta palabra secreta,
fíjate que ya me dice que es una palabra secreta
y me dice que es un secreto que es bastante débil.
O sea, aquí lo que espera es un secreto bastante bestia, ¿eh?
Bastante bestia, que sea muy, muy, muy, muy grande.
Que no sea fácil de, con fuerza bruta, intentar sacarlo.
Pero esta palabra secreta es nuestra.
La tenemos que poner nosotros, ¿vale?
Esta palabra secreta la tendremos nosotros.
No en el código, sino como variable de entorno.
Y esta palabra secreta es la vida.
Es la vida.
Si se te escapa esta palabra secreta,
todo esto se desmorona y se va a tomar por saco.
Así que ten mucho cuidado de que no se te olvide
la palabra secreta en tu código, porque la lías partida.
Entonces, esto sería lo que son los JSON Web Tokens.
Se generan con la clave secreta.
Y esto nos va a permitir crear un token de autenticación, ¿vale?
En el servidor verificaremos el token
y verificaremos si el usuario está autentificado.
Ahora, esto sería un poco cómo va a funcionar.
Lo vamos a implementar y luego volveremos a este gráfico.
Y os explicaré un poco el paso a paso, ¿vale?
Lo que hace primero, después, cómo vuelve y todo esto.
Pero vamos a implementarlo para que luego lo veamos con más chicha,
que no te lo explico aquí, que queda un poco demasiado
y ya te da la chapa con los JSON Web Tokens
que creo que has tenido suficiente.
Luego te explico también las ventajas que tienen los JSON Web Tokens,
aunque ya más o menos te lo puedes imaginar.
Pero el primero y el más importante es la autenticación,
autentificación sin estado, ¿vale?
Te permite los JSON Web Tokens,
sin necesidad de mantener sesión en el servidor
o en la base de datos,
te permite tener toda la información necesaria
porque se incluye en el propio token.
Puedes tener cuándo expira el token,
qué usuario, el que está con la sesión iniciada, lo que sea.
Y esto hace que sean muy escalables
porque la escalabilidad es infinita.
No necesitas tener una base de datos muy grande
para guardar todo esto
porque no dependes de guardar esto.
Son interoperables
porque estos JSON Web Tokens te los puedes llevar
en diferentes lenguajes de programación,
diferentes plataformas, diferentes dispositivos.
Es un estándar abierto que funciona en cualquier sitio
y además tienes seguridad, ¿no?
Porque te permite cifrar y firmar toda la información que quieras
de forma segura y son súper flexibles
porque puedes enviar un montón de información.
Esos serían un poco los cinco pasos.
Vamos, vámonos al código.
Ahora que ya os he dicho todo esto, ¿vale?
Vamos con el login.
Lo primero que vamos a necesitar,
esto seguro con los JSON Web Tokens,
es el hecho de tener la dependencia.
Ya os digo que los JSON Web Tokens
los podéis implementar en un montón de sitios
y si vais a librerías,
vais a encontrar que tenéis librerías en .NET
y más de una.
O sea, tenéis diferentes implementaciones
y también es que lo tenéis en todos los sitios.
Si buscáis Node, en Node también tenéis un montón.
Tenéis JSON Web Token, Jose, AWST.
La de Jose está divertida,
pero vamos a utilizar la más típica que es esta, ¿vale?
JSON Web Token.
Pero, bueno, que si os gusta más otra,
la podéis utilizar.
Ya os digo que lo tenéis en un montón de sabores.
Le vamos a dar en install, JSON Web Token, ¿vale?
Instalamos esta dependencia
y aquí en el login lo primero que vamos a hacer
es crear el token, ¿vale?
Así que vamos a crear aquí el token, token
y vamos a importar la dependencia
de los JSON Web Token, import.
Vamos a hacerlo así, JSON Web Token.
Y aquí vamos a tener JSON Web Token.
.sync para firmar
y aquí podéis guardar la información que queráis.
Por ejemplo, el username que lo tenemos de aquí.
Este username lo tenemos aquí,
aunque también lo podríamos sacar de user,
que debería ser como el más válido
porque es el que hemos sacado de la base de datos.
Podríamos guardar la id también, la id.
Vamos a, tendríamos la id del user.id
y el username, que sería user.username, ¿vale?
Esto por un lado, ¿vale?
Tenemos aquí JSON Web Token
y necesitamos como segundo parámetro
el secreto, el secret key, ¿vale?
Aquí, esto es muy mala idea,
que pongáis el secret aquí.
¿Por qué?
Porque está expuesto en el código.
No lo ponemos en el código.
Entonces, como mínimo,
deberíamos tener aquí el secret.
Podemos poner así, ¿vale?
Podéis ponerle un valor por defecto.
Yo no os lo recomiendo,
pero como estamos en desarrollo
y no quiero poner las variables de entorno y tal,
lo podéis hacer.
Pero lo ideal es que evitéis poner un valor por defecto
para que así seguro no se os olvide en producción
inyectárselo como variable de entorno.
Pero bueno, le podéis poner aquí
this is an awesome secret key, ¿vale?
Tiene que ser muy largo,
como si fuese un hash.
No pongáis una palabra ni en broma, ¿vale?
Tiene que ser algo mucho más largo que esto
y con hashes, historias y símbolos y lo que sea, ¿vale?
Solo para que os hagáis a la idea
y muy seguro.
Vale, me ha gustado esa frase.
Vale, pues este secret JSON Web Token
es el que vamos a utilizar aquí.
Lo utilizamos aquí y lo importamos.
Y luego hay un tercer parámetro
porque los JSON Web Tokens
también tienen expiración.
Le vamos a decir, oye, este token,
¿cuánto tiempo tiene que vivir?
Entonces le podemos decir,
¿cuánto tiempo tiene que perdurar?
Pues le vamos a decir que en una hora,
por ejemplo, en una hora,
normalmente cuando son tokens
que son de acceso,
deberían ser muy cortos
y luego se pueden crear otros tokens
que son de refresco
que pueden ser más largos.
Por ahora vamos a crear este que sea una hora.
Vamos a ver si luego nos da tiempo
al Refresh Token
para que os lo explique.
Pero ahora el problema del millón es
¿qué hacemos con este token?
¿Lo devolvemos?
¿Devolvemos este token
y que cuando el usuario haga login
tenemos el token aquí
y lo guardamos en el local storage?
¿Hacemos eso?
¿Utilizamos el local storage?
No, esto es polémico, ¿vale?
Y hay gente que lo que haría
es ponerlo en el local storage.
Lo que os digo es
que es verdad que
ya cuando una persona
tiene acceso a tu máquina,
tanto el local storage
como las cookies están jodidas, ¿vale?
Porque pueden verlo todo.
Pero si hablamos de un punto de vista
estrictamente de seguridad,
deberíamos evitarlo.
Y es mucho mejor
hacerlo en cookie.
No hacerlo ni en local storage,
ni en session storage,
ni en nada storage, ¿vale?
Tendría que estar en una cookie.
¿Y por qué en una cookie?
Por diferentes motivos.
Lo primero,
una cookie tiene un poquito
más de seguridad.
A ver, ¿por qué en la cookie
puede ser un poco más seguro?
Las cookies son menos vulnerables
a los ataques de cross-site scripting, ¿vale?
Que el session storage
y el local storage.
¿Esto qué es?
Cuando un script malicioso, por ejemplo,
te inyecta código en un sitio web,
este código puede acceder
a tu local storage
y tu session storage.
Y tú me dirás,
¿pero a la cookie también?
No.
Porque las cookies
tienen una capa de seguridad adicional
que se llama HTTP only.
Que lo que te permite,
esta banderita de las cookies,
lo que te permite
es que no puedan ser accedidas
a través de JavaScript.
y que solo se puedan acceder
en la petición en el servidor.
Entonces,
¿esto significa
que estás 100% seguro?
No,
pero es una capa más de seguridad.
Ya no te pueden atacar,
no eres vulnerable
a los ataques
de cross-site scripting.
No es perfecto,
pero tal.
Luego también las cookies
se pueden,
tienen un tiempo de expiración.
Cosa que en el local storage
y en session storage
no tienen como tal
de forma oficial
un tiempo de expiración.
Lo puedes simular,
puedes tener herramientas tal,
el session storage
se elimina
cuando cierras el navegador del todo,
que es una cosa
que no ocurre nunca,
¿vale?
El cerrarlo del todo,
porque al final,
aunque tú cierres la pestaña,
la sesión como que sigue funcionando.
Entonces,
esto de tener una expiración
de forma nativa
también puede ayudar.
También las cookies
puedes configurar
que se envíen solo
a través de HTTPS,
que esto es otra cosa
que es interesante,
lo cual,
pues quieras o no,
proporciona encriptación
y autentificación
de los datos transmitidos.
Y esto también
reduce el riesgo
de que puedas tener ataques
de el hombre en el medio
o man in the middle,
¿no?
Donde un atacante intercepta
y modifica los datos
que se han transmitido.
Como viaja en la cookie,
pues este problema
no lo deberías tener
porque debería estar codificado.
También,
de nuevo,
no significa que esté
100% seguro,
pero ayuda.
Y luego también
el session storage
y el local storage
pueden hacer
el ataque este
de cuando un atacante
envía una solicitud
desde el navegador
del usuario
sin conocimiento
del usuario,
¿vale?
Esto se hace mucho
en CSS,
por ejemplo.
En CSS hay un ataque
que se llama
cross-site request,
no acuerdo qué,
¿no?
En el que tú
te haces,
sin que te des cuenta,
pueden hacer una petición
a un servidor
en tu nombre.
¿Qué pasa?
Que como el session storage
y el local storage
son accesibles
desde JavaScript,
pues lo puedes leer,
lo envías,
se envían fácilmente esto
y ya está.
Ahora,
como no se puede enviar,
la cookie no se puede leer
en el JavaScript,
pues es mucho más complicado.
No imposible,
pero más complicado.
Y además,
puedes hacer que las cookies
solo se envíen
a dominios
que sean el tuyo propio.
Entonces,
y eso lo vamos a hacer ahora.
Entonces,
lo que va a ocurrir
es que tú,
hostia,
tenía que haber puesto
la cámara en primera persona,
y os estoy dando la chapa
con esto en pequeño.
Eso,
cross-site request forgery.
Gracias,
que no me acordaba.
El tema es que
lo que puedes hacer
es que las cookies
solo funcionen
en tu dominio
y eso es lo que va a hacer también.
Es otra capa más
y ya está.
Así que,
¿es perfecto las cookies?
No,
pero hablando
en términos de seguridad,
al final,
la idea es que sí que son
más seguras
que el local storage.
O sea,
son así.
O sea,
son más seguras
que las local storage.
Y hay un quinto punto
de todo esto
que es la facilidad de uso.
Porque ya no tiene
la responsabilidad
el cliente
de la gestión
de guardar el token.
Lo haces desde el servidor
y ya lo tiene pegado.
Y esto te va a facilitar
la interoperabilidad
entre diferentes servicios,
en diferentes partes
de la aplicación,
sin necesidad de preocuparte
del código
y solo ponerlo
en el servidor.
O sea,
que esas serían
un poco algunas ideas.
Entonces,
para guardar
y tratarlo en las cookies,
vamos a crear,
vamos a añadir
otra dependencia
que es
cookie parser.
Cookie parser
es otro
middleware más
que tenemos
en Express
que vamos a importar aquí.
Cookie parser
que nos va a facilitar
la posibilidad
de modificar
las cookies.
Entonces,
utilizamos aquí
el cookie parser,
lo ponemos aquí
y ahora,
cuando hagamos el login
y tengamos este token,
vamos a poder guardarlo
en la cookie.
Así que vamos a poner aquí
cookie
y aquí hay diferentes nombres
que le podéis poner.
Ahora,
para diferenciarlo
por si hacemos
en otro momento
el refresh token,
access token,
le pasamos el token
y aquí,
importante,
las configuraciones
que os decíamos.
HTTP only,
¿vale?
¿Esto qué es?
Esto lo que va a decir
es que la cookie
solo se puede acceder
en el servidor,
¿vale?
No vais a poder leerla
desde JavaScript
y eso ahora lo veremos.
No podremos hacer
un document.cookie
y ver esta cookie.
No la vamos a poder leer.
Luego también
podríais hacer
el secure
para que solo funcione
con HTTPS.
Esto obviamente
no siempre lo vais a querer
y podríamos hacer
que si estamos
en producción
pues hacemos
que sea segura,
¿vale?
Y así la cookie
solo se puede acceder
en HTTPS.
Y otra opción
que tenéis
para un poquito más
de seguridad
será la de same site,
¿vale?
Tenéis el que es laxo
o podríais hacerlo
más estricto
que solo se puede acceder
desde el mismo dominio.
Le podríamos poner
también un maxH
pero bueno,
ya el token
tiene el que tiene,
o sea que tampoco
tiene mucho sentido
pero bueno,
solo vamos a poner
maxH
¿vale?
La cookie solo tiene
validez una hora
y esto lo que va a hacer
es que la respuesta
va a pegar esta cookie
y vamos a poder acceder a ella
la vamos a tener ya
en el cliente.
Pero fijaos en una cosa,
vamos a hacer esto,
vamos,
nos vamos por aquí,
ahora esto me había dado
un error antes
que no tiene mucho sentido,
ahora arreglaremos,
nos vamos aquí,
ah no me acuerdo
que había puesto
midudep 3
y 1, 2, 3, 4, 5, 6
puede ser,
¿vale?
Login,
vale,
vamos a ver,
funciona,
vale,
hola midudep,
este contenido está protegido,
vale,
no sé por qué
ahora no me ha petado
el protected,
el protected,
protected,
ah porque he puesto esto
para que no me petase
pero debería petar,
¿vale?
Pero vamos a ver
lo interesante,
primero,
si nos vamos a application,
¿vale?
Si nos vamos a application
aquí en cookies,
fijaos que tenemos aquí
el access token,
¿vale?
Este sería el token,
tendríamos aquí
la expiración,
el tamaño,
fijaos este
http only,
el secure
está desactivado
porque no estamos
en producción
y tendríamos aquí
el same site
y esto significa
que esta cookie
no se va a enviar
a un servicio,
o sea,
un dominio
que no sea el nuestro
y esto es importante
porque antes
alguien decía
en el chat,
ostras,
pero claro,
el problema es que
esta cookie
va a viajar
en todas las peticiones,
bueno,
pero en este caso
va a estar trabajando,
va a estar enviándose
en nuestras peticiones,
en nuestro dominio,
no se va a enviar
a cualquier sitio,
¿vale?
entonces,
este access token
¿podemos acceder a él
desde el document.cookie?
fíjate,
no,
y esto es muy importante,
¿no?
document.cookie
nos dice que no tenemos cookies,
nos dice que está vacío,
¿por qué?
porque esta cookie
no podemos acceder a ella
desde el cliente,
¿ok?
pero en cambio
una cosa que sí que es interesante
es que cada vez que hagamos ahora,
aunque yo aquí,
fíjate,
estoy en el login,
¿vale?
fíjate lo que está pasando
en la network,
si hacemos esto
un poquito más pequeño
y refrescamos
este localhost,
si miramos aquí,
fijaos que
cuando hago cualquier petición,
aquí sí que tengo
la cookie pegada
y esta cookie
está llegando
a las peticiones
que estamos haciendo aquí
en el servidor,
¿qué significa esto?
pues esto lo que significa
es que vamos a poder arreglar
en el protected,
vamos a poder acceder
a esta información,
en el protected
vamos a poder verificar
que realmente
está esa cookie
y vamos a poder acceder
a qué usuario
es el que tiene acceso
y vamos a poder acceder
a la información
que hemos guardado
en el payload,
entonces recuperamos
el token
de rec.request.cookies.accessToken
este accessToken
es el mismo nombre
que le hemos dado
aquí, ¿vale?
o sea, no es magia,
es ese nombre.
¿vale?
y ahora que tenemos
este token
pues simplemente
primero,
si no tenemos token
directamente
pues ya sabemos
que este usuario
le vamos a dar
res.return
res.status.403
¿vale?
y le vamos a decir
que acceso
access
not authorized
¿vale?
no está autorizado
porque esto es una ruta
protegida
pero aquí
vamos a intentar
verificar
si realmente
este token
tiene sentido
vamos a sacar
vamos a sacar
los datos
de este token
utilizando
el mismo secreto
¿vale?
este ahora
sí que hay que pasarle
el secreto
esto lo que va a hacer
es de este token
va a extraer los datos
y en estos datos
vamos a tener
el mismo payload
que estábamos guardando
aquí
¿ves?
que tenemos la id
y el username
pues se supone
que aquí en data
deberíamos tener
esa id
y ese
y ese username
así que cuando
hagamos este render
deberíamos ser capaces
de pasarle
este data
directamente
que va a tener
el id
y el username
y poder acceder a él
y poder verlo
en la página
¿vale?
y si no aquí
pues deberíamos decirle
res status
creo que aquí
401
y le decimos
que tampoco
tampoco estás autorizado
con esto
ahora si vamos
a la ruta
protegida
como tenemos
la sesión iniciada
¿vale?
hola midudep3
¿ves?
ahora
aquí en el login
fijaos que claro
no me está cambiando
pero no me está cambiando
porque
aquí en el index
que he puesto aquí
tendríamos que tener aquí
fijaos que tenemos aquí
type of username
undefined
no sé qué
vale
esto
este ya es username
en el index
vamos aquí al index
¿veis que no le estoy pasando nada?
tendríamos que hacer otra vez lo mismo
tendríamos que hacer
todo esto
tenemos que recuperar el token
recuperar el token
verificar el token
midu
puso un interceptor
cubrir mis peticiones
con el token
que está en el local storage
¿podría hacer algo parecido
con las cookies?
claro que sí
podrías hacer exactamente
lo mismo con las cookies
o hacer que eso ocurra
en el backend
lo que tenga que pasar
si te tiene que dar el backend
un error de no autorizado
tampoco pasa nada
hay cosas que a veces
le hacemos en el cliente
y que no pasa nada
si alguien intenta
hacer la petición
pues te da el error
el backend
y se lo devuelves
y ya está
y eso que te quitas
del cliente
que también tiene sentido
vale pues entonces
tendríamos que hacer algo
parecido a esto
solo que aquí
tendríamos que renderizar
sí o sí esto
y ahora arreglaremos esto
lo vamos a mejorar
¿vale?
pero esta será la idea
cuando vamos a la portada
vamos a recuperar el token
recuperamos el data del token
y el index
le pasamos la data
si no tenemos data
si no verificamos
si no lo tenemos
pues nada
renderizamos igual
a ver
aquí a lo mejor
no sé si funcionará
sí que funciona
¿ves?
hola midu-dep3
estás en el panel de administración
tenemos que poner
el cerrar sesión
todavía no lo tenemos
ahora lo haremos
no os preocupéis
pero en el application
fíjate que si yo guardo
el access token
y refresco
¿vale?
pues me da un error
porque aquí
no deberíamos hacerlo así
sino que deberíamos hacer
que si no tenemos token
vamos a devolver directamente esto
¿vale?
porque aquí seguramente
seguramente no le gusta
alguna cosa
¿vale?
pero mejor así
¿vale?
vamos a hacer midu-dep3
1, 2, 3, 4, 5, 6
¿vale?
sesión iniciada
me ha puesto el access token
en la ruta protegida
perfecto
si vuelvo aquí a la home
fijaos
tengo el cerrar sesión
porque tengo la sesión
o sea ya está detectando
que tiene la sesión
tiene el access token
por lo tanto
me ha renderizado
en el servidor
la información correcta
de hecho lo podéis ver aquí
solo me está renderizando
la parte que debe ver
el usuario
con la sesión iniciada
no me está renderizando
lo de iniciar sesión
registro y tal
solo la parte de cerrar sesión
¿vale?
y si cerramos sesión
que esto lo arreglaremos ahora
lo voy a hacer manualmente
y refresco
me vuelve a salir otra vez
el registro
para arreglar un poco esto
porque fijaos
que estamos poniendo
aquí el token
el token
el token
otra vez el token
vamos a crear
un middleware
igual que tenemos
estos dos middleware
los middleware
os recuerdo
son funciones
por las que pasa
la petición
modificamos
ya puede ser
la petición
o la respuesta
y dejamos
que pase la petición
a la siguiente función
a la que le pertoca
o sea
que aquí
podemos hacer una función
para que pase
todas las requests
que van a pasar
podríamos hacer
que solo sean
las funciones
get
las post
o que sean
pero en este caso
creo que tiene sentido
que sean todas
y aquí lo que podemos hacer
es utilizar
en lugar de tener que repetir
este código
constantemente
vamos a mover
esto del token
lo vamos a mover aquí
y podemos decir
vale
vamos a tener aquí
que data sea nul
por defecto
ok
y vamos a intentar
que si tenemos
el data
vale
lo metemos aquí
data
verify
no se que no se cuanto
vamos a crear
voy a crear
un rec
punto
session
punto
user
nul
vale
lo que vamos a hacer aquí
es
añadir información
a la petición
y lo bueno
es que al modificar
la petición
vamos a poder acceder
a esta propiedad
session
en cualquier endpoint
más adelante
entonces aquí haremos
rec
session
punto
user
igual
data
y si esto
por lo que sea
da un error
pues lo que podemos
le decimos que oye
session
user
sea nul
que en realidad
esto ya lo tenemos
o sea no debería tener
ningún problema
podríamos hacer exactamente
lo mismo
y ya está
y olvidarnos
y no hacerlo
y ya está
pero esto lo que nos
permitiría ya
es olvidarnos
aquí debajo
de hacer nada
ah
importante
hay que llamar al next
vale
hay que llamar al next
esto lo que hace es enviar
seguir
seguir a la siguiente
ruta
o middleware
en este caso
el siguiente
si voy a la raíz
sería este
pero si voy al login
sería este
vale
el next lo que hace es
vale
ya he terminado
ve al siguiente
entonces
esto como tal
no hace falta
y tampoco
en realidad este catch
tampoco pasa nada
porque oye
si no puede verificar
pues no mete al usuario
y ya está
con esto
este data
bueno pues entonces
esto ya lo podríamos poner aquí
vale
porque total
esto ya sería null
creo que con esto
ya lo tendríamos
y lo bueno es que
nos permitiría
ahora
simplificar todo esto
porque ahora
tendríamos aquí
el user
esto es
de reg
session
que si es null
pues es null
res render
index
y le pasamos
todo el usuario
nos olvidamos
de todo esto
fíjate que queda mucho más limpio
y lo mismo
también nos pasaría
con la ruta protegida
en lugar de tener que hacer
todo esto
de mirar el token
y que es access not author
y no sé qué
no sé cuánto
lo bueno es que podemos sacar
el usuario
y si no tenemos usuario
pues entonces le devolvemos
el error
y si tenemos usuario
pues renderizamos
directamente esto
ya nos facilita mucho más
la validación
no tener que estar pendiente
en todos los sitios
de extraer el token
y tal
guardamos en un solo sitio
lo que es
el chequeo del token
y ya está
vamos a ver si todo esto
funciona
aquí parece que funciona
vamos a ver
midudep3
1,2,3,4,5,6
hacemos el login
vale
aquí parece que sí
aquí ha entrado perfectamente
contenido está protegido
y si vamos a la raíz
funciona bien
solo nos falta
cerrar sesión
lo único que necesitamos ahora
es decirle
que la sesión
la tenemos que eliminar
no hay ningún problema
porque es muy fácil
para cerrar la sesión
lo único que tengo que hacer
es limpiar la cookie
y para eso
hacemos un clear cookie
de la respuesta
queremos limpiar la cookie
de access token
y ya pues puedes
por un lado
podrías hacer el message
del logout successful
pero también incluso
podríamos hacer una redirección
o sea aquí puedes hacer
lo que tú quieras
aquí porque estoy utilizando
como si fuese una API
y estoy esperando
que al darle al botón
haga la petición
pero podríais hacer
una redirección
aquí sin ningún problema
a la ruta que queráis
puede ser que sea la home
a lo que sea
lo importante es que limpien la cookie
y ya está
así que si le damos
a cerrar sesión
pues ya está
ya me ha vuelto aquí
me ha eliminado aquí la cookie
y ya lo tendríamos
podríamos volver a hacer esto
midwdev3
con el login
vale
con el login correcto
vale
sesión iniciada
me ha puesto la cookie
navegamos al otro sitio
si vamos a la home
tenemos cerrar sesión
tenemos aquí la cookie
cerramos la sesión
se acabó la cookie
y ya está
así es como tendríamos
el access token
perfectamente
sincronizado
y sin ningún tipo de problema
ahora
tenemos un problema todavía
no me va a dar tiempo
a hacerlo hoy
vale
lo haremos para la siguiente clase
pero
como funcionaría
el refrescar la cookie
el problema es que
esta cookie
este token
solo tiene una hora
ahora
que pasa
cuando pasas ahora
pues que el token
se expira
y no funciona
que hacemos
que volvemos a hacer
que el usuario
inicie sesión
le tenemos que pedir
otra vez
que tenga que iniciar sesión
pues no
lo que tendríamos que hacer
es un refresh token
el refresh token
que ahora no va a dar tiempo
a hacerlo
porque no me da la vida
y tengo que ir a correr
sería
que aquí
cuando estamos creando
este verify
y hacemos el token
hay el verify
no
aquí no
en el login
cuando hacemos esto
igual que creamos este token
tendríamos que crear
un segundo token
que fuese
refresh token
que va a tener
más
puede ser
normalmente son más largos
siete días
por ejemplo
vale
siete días
o lo que sea
y aquí
este token
tendríamos que guardarlo
también en una cookie
pero entonces
haríamos algo diferente
con el access token
porque el access token
a lo mejor
no sería tan importante
tenerlo así
lo podríamos hacer
de una forma diferente
podríamos cambiar cosas
pero lo importante
es que tendríamos dos tokens
uno
el de acceso
que sería el que dura
muy poco tiempo
y otro
el de refresco
y el de refresco
lo que haríamos
es que conforme
vamos utilizando
la página web
en cada app
y lo que sea
podemos ir creando
un nuevo access token
para que lo use
el usuario
entonces este access token
sería regenerando
constantemente
para que nunca
llegue a expirarse
y de esta forma
con el refresh token
que vamos a tener
mucho más cuidado
no lo vamos a enviar
a servicios
ni nada
lo va a tener el usuario
pero vamos a intentar
no enviarlo
a ningún sitio
externo
ni para APIs
ni nada
sino que lo vamos a tener
simplemente
para crear access tokens
vale
esa sería la idea
pero lo haremos
y cuando harías
cuando expires
el refresh token
el refresh token
hay diferentes
claro
igual que tenemos
el refresh token
que se puede
el access token
que se expira
el refresh token
se pueden hacer
diferentes estrategias
se puede
volver a crear
una vez que veamos
que si
por número de usos
volver a recrearlo
cada vez que
o obligar al usuario
que tenga que iniciar sesión
o hacer que todavía
que dure mucho más tiempo
seguro que lo habéis
visto alguna vez
en Gmail
o algún sitio
que no sabéis
por qué de repente
os pide iniciar sesión
otra vez
pues eso
es porque ha aspirado
el refresh token
básicamente
por mucho tiempo
que llevases
pues al final dice
bueno
hasta aquí ha llegado
la cosa
y por eso
lo tenemos que hacer
entonces
normalmente pasa eso
pero puede ser
que después de hacer
algún uso
hacer un pseudo
inicio de sesión
porque hay muchas veces
que se hacen
pseudos inicios de sesión
también regenerar
el refresh token
hay un montón de cosas
os dejo
todas las clases
vale
todas las clases
también si os interesa
la próxima vez
haremos refresh tokens
haremos passport
que es una forma
muy interesante
de tratar
autentificación
en Node.js
y OAuth 2.0
para hacer
un inicio de sesión
de Google
puramente con Node.js
para que veáis
cómo funciona
y todos los pasos
que tiene
que es muy interesante
entonces
os dejo
midu.link
barra note
el curso de Node.js
mañana no hago directo
porque estoy
en el Open Expo Europe
que estoy nominado
a mejor creador
de contenido de tecnología
no sé si tenemos
la buena suerte
de ganar
pero muchas gracias
a todos los que me votasteis
4.000 votos
de lejos
el más votado
creo que el segundo
no sé si tenía
900 o así
pero igualmente
os lo agradezco infinito
gracias a todos
y cada uno de vosotros
por haberme votado
ojalá que
bueno
que el jurado
crea que nos lo hemos ganado
hemos hecho cosas
muy increíbles este año
y creo que como
como comunidad
nos merecemos
ese privilegio
pero bueno
si no
no pasa nada
porque aunque mañana
no habrá directo
el lunes
volvemos con las noticias
de tecnología
y de desarrollo
y de javascript
el lunes
veremos si el viernes
a lo mejor
hacemos un directo
clandestino
no lo sé
ya os contaré
y si no
el lunes
será el último stream
hasta
hasta mucho tiempo
porque la semana
que viene
me voy a Japón
el martes que viene
me voy a Japón
así que el lunes
será el último directo
hasta
julio
el 17 de junio
será el último directo
hasta julio
hasta el 1 de julio
pero
en julio
tenemos
el curso de react native
una nueva hackathon
que vamos a hacer
con inteligencia artificial
con premios monetarios
con premios monetarios
premios muy bestias
y vamos a colaborar
con una empresa
internacional
muy grande
muy top
que no te lo puedes perder
curso de react native
en julio
hackathon
con una empresa
sobre inteligencia artificial
muy bestia
y además
vamos a tener
la depths league
el concurso
entre programadores
como un concurso
de la tele
donde se van a estar
peleando
para ganar
así que
amigos
espero que os haya gustado
os quiero mucho
gracias por vuestro apoyo
gracias por estar ahí
nos vemos
hasta luego
no
¡Gracias!