constexpress=require("express");constcors=require("cors");constapp=express();constPORT=3000;constloginRoute=require("./routes/login.js");constregisterRoute=require("./routes/register.js");constprotectedRoutes=require('./routes/protected.js');app.use(cors());app.use(express.json());app.use("/login",loginRoute);app.use("/register",registerRoute);app.use('/protected',protectedRoutes);app.listen(PORT,()=>{console.log(`Servidor escuchando en http://localhost:${PORT}`);})
El archivo login.js
constexpress=require("express");constjwt=require("jsonwebtoken");constbcrypt=require('bcrypt');constpool=require("../config/db.js");constrouter=express.Router();constJWT_SECRET="12345";router.post("/",async(req,res)=>{const{user,password}=req.body;if (!user||!password) {returnres.status(400).json({message:"Faltan datos"});}try{const[rows]=awaitpool.execute("SELECT * FROM users WHERE user = ?", [user]);if (rows.length ===0) {returnres.status(401).json({message:"Usuario o contraseña incorrectos"})}constuserDB=rows[0];constvalidPassword=awaitbcrypt.compare(password,userDB.password);if (!validPassword) {returnres.status(401).json({message:"Usuario o contraseña incorrectos"});}consttoken=jwt.sign({id:userDB.id,user:userDB.user},JWT_SECRET,{expiresIn:"1h"});res.json({token:token});}catch (error) {console.log(error);res.status(500).json({message:"Error interno del servidor"})}})module.exports=router;
El archivo register.js
constexpress=require('express');constbcrypt=require('bcrypt');constpool=require('../config/db.js');// importa el pool de conexiones MySQLconstrouter=express.Router();constsaltRounds=10;router.post("/",async(req,res)=>{const{user,password}=req.body;if (!user||!password) {returnres.status(400).json({message:"Faltan datos"});}try{const[existingUsers]=awaitpool.execute("SELECT * FROM users WHERE user = ?", [user]);if (existingUsers.length >0) {returnres.status(409).json({message:"El usuario ya existe"});}consthashedPassword=awaitbcrypt.hash(password,saltRounds);awaitpool.execute("INSERT INTO users (user, password) VALUES (?, ?)", [user,hashedPassword]);res.status(201).json({message:"Usuario registrado correctamente"});}catch (error) {res.status(500).json({message:"Error interno del servidor"});}});module.exports=router;
constjwt=require("jsonwebtoken");constJWT_SECRET="12345";functionauthenticateToken(req,res,next){constauthHeader=req.headers["authorization"];consttoken=authHeader&&authHeader.split("")[1];if (!token) {returnres.status(401).json({message:"Token no proporcionado"});}jwt.verify(token,JWT_SECRET,(err,user)=>{if (err) {returnres.status(403).json({message:"Token invalido"});}req.user=user;next();})}module.exports=authenticateToken;
En el frontend tendremos 3 ficheros de javascript:
El archivo login.js
constloginUser=document.querySelector("#login-user");constloginPassword=document.querySelector("#login-password");constloginButton=document.querySelector("#login-button");loginButton.addEventListener("click",async(e)=>{constuserInfo={user:loginUser.value,password:loginPassword.value,}try{constresponse=awaitfetch("http://localhost:3000/login",{method:"POST",headers:{"Content-Type":"application/json",},body:JSON.stringify(userInfo),});constdata=awaitresponse.json();if (response.ok) {// Aquí recibes el token JWTconsttoken=data.token;alert("Login exitoso");// Guardar token en localStorage (o cookie, según prefieras)localStorage.setItem("jwtToken",token);// Redirigir o mostrar contenido protegido// window.location.href = "/dashboard.html"; // ejemplo}else{alert(data.message||"Error en el login");}}catch (error) {console.error("Error en login:",error);alert("Error en la conexión con el servidor");}});
El archivo register.js
constregisterUser=document.querySelector("#register-user");constregisterPassword=document.querySelector("#register-password");constregisterButton=document.querySelector("#register-button");registerButton.addEventListener("click",async(e)=>{constuserInfo={user:registerUser.value,password:registerPassword.value,}try{constresponse=awaitfetch("http://localhost:3000/register",{method:"POST",headers:{"Content-Type":"application/json",},body:JSON.stringify(userInfo),});constdata=awaitresponse.json();if (response.ok) {alert(data.message);// Usuario registrado correctamenteregisterUser.value="";registerPassword.value="";}else{alert(data.message||"Error al registrar");}}catch (error) {console.error("Error en registro:",error);alert("Error en la conexión con el servidor");}});
El archivo protected.js
asyncfunctioncheckAuth(){consttoken=localStorage.getItem("jwtToken");if (!token) {window.location.href="index.html";// No hay token, redirigirreturn;}try{constresponse=awaitfetch("http://localhost:3000/protected/profile",{method:"GET",headers:{"Authorization":"Bearer "+token}});if (!response.ok) {// Token inválido o expiradolocalStorage.removeItem("jwtToken");window.location.href="index.html";return;}// Token válido, puedes obtener data si quieresconstdata=awaitresponse.json();console.log("Usuario autenticado:",data.user);// Aquí sigues en la página}catch (error) {console.error("Error validando token:",error);localStorage.removeItem("jwtToken");window.location.href="index.html";}}// Ejecutar al cargar la páginacheckAuth();