Usando Passport con Sequelize y MySQL
Spanish (Español) translation by Elías Nicolás (you can also view the original English article)
Sequelize es un NOM de Node.js basado en promesas. Se puede usar con PostgreSQL, MySQL, MariaDB, SQLite y MSSQL. En este tutorial, implementaremos la autenticación para los usuarios de una aplicación web. Y usaremos Passport, el popular middleware de autenticación para Node, junto con Sequelize y MySQL para implementar el registro y el inicio de sesión del usuario.
Empezando
Asegúrese de tener instalado lo siguiente en su máquina:
- Node
- MySQL
Para este tutorial, utilizaremos Node.js junto con Express, de modo que seguiremos adelante y comenzaremos a instalar lo que necesitamos.
Paso 1: Genera un archivo package.json
Crea un directorio para tu aplicación. Dentro de este directorio, ejecútelo desde su terminal o símbolo del sistema:
1 |
npm init |
Esto inicializa el administrador de dependencias npm. Esto presentará una serie de indicaciones que atravesaremos rápidamente.
- Escriba el nombre de su aplicación sin espacios y presione Entrar para 'name' ('nombre').
- Presione Entrar para 'versión'.
- Para 'description' ('descripcion'), en este tutorial, teclearemos "Usar pasaporte con Sequelize y MySQL" como descripción y presionaremos Enter. Esto también puede estar en blanco.
- Para 'entry point (index.js)', escriba server.js y presione Entrar.
- Para 'test command' ('comando de prueba'), presione Enter.
- Para 'git repository' ('repositorio git'), puedes ingresar el repositorio git donde reside tu aplicación si tienes uno o simplemente presionar Enter para dejar esto en blanco.
- Para 'Keywords' ('Palabras clave'), presione Entrar.
- Para 'author' ('autor'), presione Entrar o escriba su nombre antes de hacer eso.
- Para 'license' ('licencia'), presione Enter.
- Para '(Is this okay )' ('(¿Está bien?')'), Esto muestra cómo se verá tu package.json. Escriba Yes y presione Entrar.
Paso 2: Instalar dependencias
Las principales dependencias para este tutorial son:
- Express
- Sequelize
- MySQL
- Passport
- Passport Local Strategy
- Body Parser
- Express Session
- Bcrypt Nodejs
- Express Handlebars
Para instalarlos, desde su terminal o símbolo del sistema, ejecute los siguientes uno tras otro.
1 |
npm install express --save |
2 |
|
3 |
npm install sequelize --save |
4 |
|
5 |
npm install mysql --save |
6 |
|
7 |
npm install passport --save |
8 |
|
9 |
npm install passport-local --save |
10 |
|
11 |
npm install body-parser --save |
12 |
|
13 |
npm install express-session --save |
14 |
|
15 |
npm install bcrypt-nodejs --save |
16 |
|
17 |
npm install express-handlebars --save |
Si estás usando Git para este proyecto:
En la carpeta del proyecto, crea un archivo .gitignore.
Agregue esta línea al archivo .gitignore.
node_modules
Paso 3: configura la aplicación
Ahora, creamos un archivo de servidor. Este será el archivo principal al que se llama cuando escribe lo siguiente:
1 |
npm start |
Esto ejecuta la aplicación. También puede ejecutar la aplicación escribiendo node server.js.
1 |
node server.js |
Luego, en nuestra carpeta de proyectos, creamos un nuevo archivo y le damos el nombre server.js.
Dentro del archivo server.js, pegamos lo siguiente:
1 |
var express = require('express'); |
2 |
var app = express(); |
3 |
|
4 |
|
5 |
app.get('/', function(req, res) { |
6 |
|
7 |
res.send('Welcome to Passport with Sequelize'); |
8 |
|
9 |
});
|
10 |
|
11 |
|
12 |
app.listen(5000, function(err) { |
13 |
|
14 |
if (!err) |
15 |
console.log("Site is live"); |
16 |
else console.log(err) |
17 |
|
18 |
});
|
La primera línea asigna el módulo express a una variable express. Entonces inicializamos Express y le damos el nombre en una variable: app.
Luego hacemos que la aplicación escuche en el puerto 5000. Puede elegir cualquier número de puerto libre en su computadora.
A
continuación, llamamos a la función de enrutamiento express app.get()
para responder con "Bienvenido a pasaporte con Sequelize" cuando se
realiza una solicitud GET a "/".
Para probar en su computadora, ejecute esto desde el interior de su carpeta de proyectos:
1 |
node server.js |
Si ve el texto "Bienvenido a Pasaporte con Sequelize" cuando visite http://localhost:5000/ ¡entonces le felicito! De lo contrario, verifique que haya hecho todo exactamente como está escrito anteriormente.
A continuación, importamos algunos módulos que necesitamos, como passport, express-session y body-parser.
Después de var app = express() agregamos las siguientes líneas:
1 |
var passport = require('passport') |
2 |
var session = require('express-session') |
3 |
var bodyParser = require('body-parser') |
En las dos primeras líneas, importamos el módulo passport y express-session, y ambos debemos gestionar la autenticación.
Luego, importamos el módulo body-parser. Esto extrae la parte completa del cuerpo de una solicitud entrante y la expone en un formato que es más fácil de trabajar. En este caso, usaremos el formato JSON.
Para que nuestra aplicación use el body parser, agregamos estas líneas algunos espacios debajo de las líneas de importación:
1 |
//For BodyParser
|
2 |
app.use(bodyParser.urlencoded({ extended: true })); |
3 |
app.use(bodyParser.json()); |
A continuación, inicializamos passport y express session y la sesión passport y los agregamos como middleware. Hacemos esto agregando estas líneas algunos espacios después de la línea de importación bodyParser.
1 |
// For Passport
|
2 |
|
3 |
app.use(session({ secret: 'keyboard cat',resave: true, saveUninitialized:true})); // session secret |
4 |
|
5 |
app.use(passport.initialize()); |
6 |
|
7 |
app.use(passport.session()); // persistent login sessions |
Comenzaremos a trabajar en la autenticación real ahora.
Haremos esto en cuatro pasos:
- Configure Sequelize con MySQL.
- Crea el modelo de usuario.
- Configurar vistas
- Escribe una estrategia de passport.
1. Configurar Sequelize con MySQL
Primero, creamos una base de datos en MySQL. Dale tu
nombre preferido. Por el bien de este tutorial, creemos una base de
datos llamada secuencize_passport en MySQL.
Luego configuramos la configuración para manejar los detalles de la base de datos.
Primero, importemos el módulo dot-env para manejar las variables de entorno.
Ejecute esto en su carpeta de proyecto raíz:
1 |
npm install --save dotenv |
Luego lo importamos en el archivo del servidor principal, server.js, justo debajo de las otras importaciones.
1 |
var env = require('dotenv').load(); |
A continuación, creamos un archivo en nuestra carpeta de proyectos y lo nombramos .env.
El siguiente paso a seguir es opcional si no estás usando Git:
Agregaremos el archivo .env a su archivo .gitignore.
Su archivo .gitignore debería verse así:
1 |
node_modules |
2 |
.env |
Después de esto, agregamos nuestro entorno al archivo .env agregando esta línea:
NODE_ENV='development'
Luego creamos un archivo config.json que Sequelize usará para administrar diferentes entornos.
Lo primero que debe hacer es crear una carpeta llamada config en nuestra
carpeta de proyectos. Dentro de esta carpeta, creamos un archivo
config.json. Este archivo debe ignorarse si está presionando a un
repositorio. Para hacer esto, agregue el siguiente código a su
.gitignore:
config/config.json
Luego, pegamos el siguiente código en nuestro archivo config.json.
1 |
{
|
2 |
|
3 |
"development": {
|
4 |
|
5 |
"username": "root", |
6 |
|
7 |
"password": null, |
8 |
|
9 |
"database": "sequelize_passport", |
10 |
|
11 |
"host": "127.0.0.1", |
12 |
|
13 |
"dialect": "mysql" |
14 |
|
15 |
}, |
16 |
|
17 |
"test": {
|
18 |
|
19 |
"username": "", |
20 |
|
21 |
"password": null, |
22 |
|
23 |
"database": "", |
24 |
|
25 |
"host": "", |
26 |
|
27 |
"dialect": "mysql" |
28 |
|
29 |
}, |
30 |
|
31 |
"production": {
|
32 |
|
33 |
"username": "", |
34 |
|
35 |
"password": null, |
36 |
|
37 |
"database": "", |
38 |
|
39 |
"host": "127.0.0.1", |
40 |
|
41 |
"dialect": "mysql" |
42 |
|
43 |
} |
44 |
|
45 |
} |
Recuerde reemplazar los valores en el bloque de desarrollo anterior con los detalles de autenticación de su base de datos.
A continuación, instalamos la secuencia con npm. Para hacer esto, ejecute el siguiente comando en la carpeta raíz del proyecto:
1 |
npm install --save sequelize |
Ahora es el momento de crear la carpeta de modelos models .
Primero, hacemos una aplicación llamada app en nuestra carpeta de proyectos.
Dentro de la carpeta app, creamos una nueva carpeta llamada models y creamos un nuevo archivo llamado index.js en la carpeta models.
Dentro del archivo index.js, pegamos el código a continuación.
1 |
"use strict"; |
2 |
|
3 |
var fs = require("fs"); |
4 |
var path = require("path"); |
5 |
var Sequelize = require("sequelize"); |
6 |
var env = process.env.NODE_ENV || "development"; |
7 |
var config = require(path.join(__dirname, '..', 'config', 'config.json'))[env]; |
8 |
var sequelize = new Sequelize(config.database, config.username, config.password, config); |
9 |
var db = {}; |
10 |
|
11 |
|
12 |
fs
|
13 |
.readdirSync(__dirname) |
14 |
.filter(function(file) { |
15 |
return (file.indexOf(".") !== 0) && (file !== "index.js"); |
16 |
})
|
17 |
.forEach(function(file) { |
18 |
var model = sequelize.import(path.join(__dirname, file)); |
19 |
db[model.name] = model; |
20 |
});
|
21 |
|
22 |
Object.keys(db).forEach(function(modelName) { |
23 |
if ("associate" in db[modelName]) { |
24 |
db[modelName].associate(db); |
25 |
}
|
26 |
});
|
27 |
|
28 |
|
29 |
db.sequelize = sequelize; |
30 |
db.Sequelize = Sequelize; |
31 |
|
32 |
module.exports = db; |
Este archivo se usa para importar todos los modelos que colocamos en la carpeta models y exportarlos.
Para probar que todo está bien, lo agregamos en nuestro archivo server.js.
1 |
//Models
|
2 |
var models = require("./app/models"); |
3 |
|
4 |
//Sync Database
|
5 |
models.sequelize.sync().then(function() { |
6 |
|
7 |
console.log('Nice! Database looks fine') |
8 |
|
9 |
}).catch(function(err) { |
10 |
|
11 |
console.log(err, "Something went wrong with the Database Update!") |
12 |
|
13 |
});
|
Aquí, estamos importando los modelos y luego llamando a la función de sincronización Sequelize.
Ejecute esto para ver si todo está bien:
1 |
node server.js |
Si recibe el mensaje "Site is live Nice! Database looks fine" (El sitio está en buen estado, la base de datos se ve bien), entonces ha configurado el Sequelize correctamente.
De lo contrario, repase cuidadosamente los pasos anteriores e intente solucionar el problema con ayuda.
2. Crea el Modelo de Usuario
Lo siguiente que vamos a hacer es crear el modelo de usuario, que es básicamente la tabla de usuarios. Esto contendrá información básica del usuario.
En nuestra carpeta models, creamos un archivo y le damos el nombre user.js. La ruta completa de este archivo debe ser app/models/user.js.
Abra el archivo user.js y agregue el siguiente código:
1 |
module.exports = function(sequelize, Sequelize) { |
2 |
|
3 |
var User = sequelize.define('user', { |
4 |
|
5 |
id: { |
6 |
autoIncrement: true, |
7 |
primaryKey: true, |
8 |
type: Sequelize.INTEGER |
9 |
},
|
10 |
|
11 |
firstname: { |
12 |
type: Sequelize.STRING, |
13 |
notEmpty: true |
14 |
},
|
15 |
|
16 |
lastname: { |
17 |
type: Sequelize.STRING, |
18 |
notEmpty: true |
19 |
},
|
20 |
|
21 |
username: { |
22 |
type: Sequelize.TEXT |
23 |
},
|
24 |
|
25 |
about: { |
26 |
type: Sequelize.TEXT |
27 |
},
|
28 |
|
29 |
email: { |
30 |
type: Sequelize.STRING, |
31 |
validate: { |
32 |
isEmail: true |
33 |
}
|
34 |
},
|
35 |
|
36 |
password: { |
37 |
type: Sequelize.STRING, |
38 |
allowNull: false |
39 |
},
|
40 |
|
41 |
last_login: { |
42 |
type: Sequelize.DATE |
43 |
},
|
44 |
|
45 |
status: { |
46 |
type: Sequelize.ENUM('active', 'inactive'), |
47 |
defaultValue: 'active' |
48 |
}
|
49 |
|
50 |
|
51 |
});
|
52 |
|
53 |
return User; |
54 |
|
55 |
}
|
Ahora ejecuta:
1 |
node server.js |
Debería ver el familiar "Site is live. Nice! Database looks fine." ("El sitio está en vivo. La base de datos de Niza se ve bien"). mensaje. Esto significa que nuestros modelos de Sequelize se han sincronizado correctamente, y si revisa su base de datos, debería ver una tabla de usuarios con las columnas especificadas.
3: Configurar vistas
Primero, creemos la vista para registrarla y conectarla.
Lo primero que debe hacer es importar el módulo de manillar express que usamos para las vistas en este tutorial.
Agregue esta línea al archivo de inicio principal, server.js.
var exphbs = require('express-handlebars')
Su bloque de importación debería verse así en este punto.
1 |
var express = require('express') |
2 |
var app = express() |
3 |
var passport = require('passport') |
4 |
var session = require('express-session') |
5 |
var bodyParser = require('body-parser') |
6 |
var env = require('dotenv').load() |
7 |
var exphbs = require('express-handlebars') |
A continuación, agregamos las siguientes líneas en nuestro archivo server.js.
1 |
//For Handlebars
|
2 |
app.set('views', './app/views') |
3 |
app.engine('hbs', exphbs({ |
4 |
extname: '.hbs' |
5 |
}));
|
6 |
app.set('view engine', '.hbs'); |
Ahora, en nuestra carpeta de aplicaciones, creamos tres carpetas llamadas views, controllers y routes.
En la carpeta de vistas, creamos un archivo llamado signup.hbs y pegamos el código debajo en él.
1 |
<!DOCTYPE html>
|
2 |
<html>
|
3 |
|
4 |
<head>
|
5 |
<title></title>
|
6 |
</head>
|
7 |
|
8 |
<body>
|
9 |
<form id="signup" name="signup" method="post" action="/signup"> |
10 |
<label for="email">Email Address</label> |
11 |
<input class="text" name="email" type="email" /> |
12 |
<label for="firstname">Firstname</label> |
13 |
<input name="firstname" type="text" /> |
14 |
<label for="lastname">Lastname</label> |
15 |
<input name="lastname" type="text" /> |
16 |
<label for="password">Password</label> |
17 |
<input name="password" type="password" /> |
18 |
<input class="btn" type="submit" value="Sign Up" /> |
19 |
</form>
|
20 |
|
21 |
</body>
|
22 |
|
23 |
</html>
|
Luego, en nuestra carpeta controllers, creamos un nuevo archivo y lo nombramos authcontroller.js.
En este archivo, pegamos el siguiente controlador para la ruta de registro que crearemos en un momento.
1 |
var exports = module.exports = {} |
2 |
|
3 |
exports.signup = function(req, res) { |
4 |
|
5 |
res.render('signup'); |
6 |
|
7 |
}
|
A continuación, creamos una ruta para el registro. En la carpeta de rutas, creamos un nuevo archivo llamado auth.js y luego, en este archivo, importamos el controlador de autenticación y definimos la ruta de registro.
1 |
var authController = require('../controllers/authcontroller.js'); |
2 |
|
3 |
module.exports = function(app) { |
4 |
|
5 |
app.get('/signup', authController.signup); |
6 |
|
7 |
}
|
Ahora, importaremos esta ruta en nuestro server.js y pasaremos la aplicación como argumento.
En el servidor, después de importar los modelos, agregue estas líneas:
1 |
//Routes
|
2 |
var authRoute = require('./app/routes/auth.js')(app); |
Ejecuta esto:
1 |
node server.js |
Ahora, visite http://localhost:5000/signup y verá el formulario de registro.
Repitamos los pasos para el formulario de inicio de sesión. Como antes, crearemos un archivo llamado signin.hbs en nuestra carpeta de vistas y pegaremos el siguiente código HTML en él:
1 |
<!DOCTYPE html>
|
2 |
<html>
|
3 |
|
4 |
<head>
|
5 |
<title></title>
|
6 |
</head>
|
7 |
|
8 |
<body>
|
9 |
<form id="signin" name="signin" method="post" action="signin"> |
10 |
<label for="email">Email Address</label> |
11 |
<input class="text" name="email" type="text" /> |
12 |
<label for="password">Password</label> |
13 |
<input name="password" type="password" /> |
14 |
<input class="btn" type="submit" value="Sign In" /> |
15 |
</form>
|
16 |
|
17 |
</body>
|
18 |
|
19 |
</html>
|
Luego, agregue un controlador para el inicio de sesión en la app/controllers/authcontroller.js.
1 |
exports.signin = function(req, res) { |
2 |
|
3 |
res.render('signin'); |
4 |
|
5 |
}
|
Luego, en app/routes/auth.js, agregamos una ruta para iniciar sesión de esta manera:
app.get('/signin', authController.signin);
Ahora cuando corres:
1 |
node server.js |
y visite http://localhost:5000/signin/, debería ver el formulario de inicio de sesión.
El paso final y principal es escribir nuestras estrategias de passport.
4. Escribe una estrategia de Passport
En app/config, creamos una nueva carpeta llamada pasaporte.
Luego, en nuestra nueva carpeta app/config/passport, creamos un nuevo archivo y lo llamamos passport.js. Este archivo contendrá nuestras estrategias de passport.
En passport.js, usaremos el modelo de usuario y el pasaporte.
Primero, importamos bcrypt, que necesitamos para proteger las contraseñas.
var bCrypt = require('bcrypt-nodejs');
Luego, agregamos un bloque module.exports como este:
1 |
module.exports = function(passport, user) { |
2 |
|
3 |
}
|
Dentro de este bloque, inicializamos la estrategia de pasaporte local y el modelo de usuario, que se pasará como argumento. Así es como hacemos esto:
1 |
module.exports = function(passport, user) { |
2 |
|
3 |
var User = user; |
4 |
var LocalStrategy = require('passport-local').Strategy; |
5 |
|
6 |
}
|
A continuación, definimos nuestra estrategia personalizada con nuestra instancia de LocalStrategy de esta manera:
1 |
passport.use('local-signup', new LocalStrategy( |
2 |
|
3 |
{
|
4 |
usernameField: 'email', |
5 |
passwordField: 'password', |
6 |
passReqToCallback: true // allows us to pass back the entire request to the callback |
7 |
|
8 |
},
|
9 |
|
10 |
));
|
Ahora hemos declarado qué campos de solicitud (req) son nuestro usernameField y passwordField (variables de passport).
La última variable, passReqToCallback, nos permite pasar la solicitud completa a la devolución de llamada, lo que es particularmente útil para registrarse.
Después de la última coma, agregamos esta función de devolución de llamada.
1 |
function(req, email, password, done) { |
2 |
|
3 |
}
|
En esta función, manejaremos el almacenamiento de los detalles de un usuario.
Primero, agregamos nuestra función de generación de contraseñas hash dentro de la función de devolución de llamada.
1 |
var generateHash = function(password) { |
2 |
|
3 |
return bCrypt.hashSync(password, bCrypt.genSaltSync(8), null); |
4 |
|
5 |
};
|
Luego, utilizando el modelo de usuario de Sequelize inicializado como User, verificamos si el usuario ya existe y, de no ser así, lo agregamos.
1 |
User.findOne({ |
2 |
where: { |
3 |
email: email |
4 |
}
|
5 |
}).then(function(user) { |
6 |
|
7 |
if (user) |
8 |
|
9 |
{
|
10 |
|
11 |
return done(null, false, { |
12 |
message: 'That email is already taken' |
13 |
});
|
14 |
|
15 |
} else |
16 |
|
17 |
{
|
18 |
|
19 |
var userPassword = generateHash(password); |
20 |
|
21 |
var data = |
22 |
|
23 |
{
|
24 |
email: email, |
25 |
|
26 |
password: userPassword, |
27 |
|
28 |
firstname: req.body.firstname, |
29 |
|
30 |
lastname: req.body.lastname |
31 |
|
32 |
};
|
33 |
|
34 |
|
35 |
User.create(data).then(function(newUser, created) { |
36 |
|
37 |
if (!newUser) { |
38 |
|
39 |
return done(null, false); |
40 |
|
41 |
}
|
42 |
|
43 |
if (newUser) { |
44 |
|
45 |
return done(null, newUser); |
46 |
|
47 |
}
|
48 |
|
49 |
});
|
50 |
|
51 |
}
|
52 |
|
53 |
});
|
User.create() es un método Sequelize para agregar nuevas entradas a la base de datos. Observe
que los valores en el objeto data se obtienen del objeto req.body
que contiene la entrada de nuestro formulario de suscripción.
Tu passport.js debería verse así:
1 |
//load bcrypt
|
2 |
var bCrypt = require('bcrypt-nodejs'); |
3 |
|
4 |
|
5 |
module.exports = function(passport, user) { |
6 |
|
7 |
|
8 |
var User = user; |
9 |
|
10 |
var LocalStrategy = require('passport-local').Strategy; |
11 |
|
12 |
|
13 |
passport.use('local-signup', new LocalStrategy( |
14 |
|
15 |
{
|
16 |
|
17 |
usernameField: 'email', |
18 |
|
19 |
passwordField: 'password', |
20 |
|
21 |
passReqToCallback: true // allows us to pass back the entire request to the callback |
22 |
|
23 |
},
|
24 |
|
25 |
|
26 |
|
27 |
function(req, email, password, done) { |
28 |
|
29 |
var generateHash = function(password) { |
30 |
|
31 |
return bCrypt.hashSync(password, bCrypt.genSaltSync(8), null); |
32 |
|
33 |
};
|
34 |
|
35 |
|
36 |
|
37 |
User.findOne({ |
38 |
where: { |
39 |
email: email |
40 |
}
|
41 |
}).then(function(user) { |
42 |
|
43 |
if (user) |
44 |
|
45 |
{
|
46 |
|
47 |
return done(null, false, { |
48 |
message: 'That email is already taken' |
49 |
});
|
50 |
|
51 |
} else |
52 |
|
53 |
{
|
54 |
|
55 |
var userPassword = generateHash(password); |
56 |
|
57 |
var data = |
58 |
|
59 |
{
|
60 |
email: email, |
61 |
|
62 |
password: userPassword, |
63 |
|
64 |
firstname: req.body.firstname, |
65 |
|
66 |
lastname: req.body.lastname |
67 |
|
68 |
};
|
69 |
|
70 |
User.create(data).then(function(newUser, created) { |
71 |
|
72 |
if (!newUser) { |
73 |
|
74 |
return done(null, false); |
75 |
|
76 |
}
|
77 |
|
78 |
if (newUser) { |
79 |
|
80 |
return done(null, newUser); |
81 |
|
82 |
}
|
83 |
|
84 |
});
|
85 |
|
86 |
}
|
87 |
|
88 |
});
|
89 |
|
90 |
}
|
91 |
|
92 |
));
|
93 |
|
94 |
}
|
Ahora importaremos la estrategia en server.js.
Para hacer esto, agregamos estas líneas debajo de las rutas importadas en server.js.
1 |
//load passport strategies
|
2 |
require('./app/config/passport/passport.js')(passport, models.user); |
Tu server.js debería verse así en este momento:
1 |
var express = require('express') |
2 |
var app = express() |
3 |
var passport = require('passport') |
4 |
var session = require('express-session') |
5 |
var bodyParser = require('body-parser') |
6 |
var env = require('dotenv').load() |
7 |
var exphbs = require('express-handlebars') |
8 |
|
9 |
|
10 |
//For BodyParser
|
11 |
app.use(bodyParser.urlencoded({ |
12 |
extended: true |
13 |
}));
|
14 |
app.use(bodyParser.json()); |
15 |
|
16 |
|
17 |
// For Passport
|
18 |
app.use(session({ |
19 |
secret: 'keyboard cat', |
20 |
resave: true, |
21 |
saveUninitialized: true |
22 |
})); // session secret |
23 |
app.use(passport.initialize()); |
24 |
app.use(passport.session()); // persistent login sessions |
25 |
|
26 |
|
27 |
//For Handlebars
|
28 |
app.set('views', './app/views') |
29 |
app.engine('hbs', exphbs({ |
30 |
extname: '.hbs' |
31 |
}));
|
32 |
app.set('view engine', '.hbs'); |
33 |
|
34 |
|
35 |
|
36 |
app.get('/', function(req, res) { |
37 |
|
38 |
res.send('Welcome to Passport with Sequelize'); |
39 |
|
40 |
});
|
41 |
|
42 |
//Models
|
43 |
var models = require("./app/models"); |
44 |
|
45 |
//Routes
|
46 |
|
47 |
var authRoute = require('./app/routes/auth.js')(app); |
48 |
|
49 |
|
50 |
//load passport strategies
|
51 |
|
52 |
require('./app/config/passport/passport.js')(passport, models.user); |
53 |
|
54 |
|
55 |
//Sync Database
|
56 |
|
57 |
models.sequelize.sync().then(function() { |
58 |
|
59 |
console.log('Nice! Database looks fine') |
60 |
|
61 |
|
62 |
}).catch(function(err) { |
63 |
|
64 |
console.log(err, "Something went wrong with the Database Update!") |
65 |
|
66 |
});
|
67 |
|
68 |
|
69 |
app.listen(5000, function(err) { |
70 |
|
71 |
if (!err) |
72 |
|
73 |
console.log("Site is live"); |
74 |
|
75 |
else console.log(err) |
76 |
|
77 |
});
|
Ahora realmente aplicaremos la estrategia a nuestra ruta /signup.
Así es como lo hacemos:
Primero, vamos a app/routes/auth.js, y agregamos una ruta para publicar para suscribirse de esta manera.
1 |
app.post('/signup', passport.authenticate('local-signup', { |
2 |
successRedirect: '/dashboard', |
3 |
|
4 |
failureRedirect: '/signup' |
5 |
}
|
6 |
|
7 |
));
|
Como necesitamos pasaporte, debemos pasarlo a este método. Podemos importar el pasaporte en este script o pasarlo desde server.js. Hagamos esto último.
Modifique la función exportada en este app/routes/auth.js para tener passport como parámetro. El código en la app/routes/auth.js debería verse así después de su modificación.
1 |
var authController = require('../controllers/authcontroller.js'); |
2 |
|
3 |
|
4 |
module.exports = function(app, passport) { |
5 |
|
6 |
app.get('/signup', authController.signup); |
7 |
|
8 |
|
9 |
app.get('/signin', authController.signin); |
10 |
|
11 |
|
12 |
app.post('/signup', passport.authenticate('local-signup', { |
13 |
successRedirect: '/dashboard', |
14 |
|
15 |
failureRedirect: '/signup' |
16 |
}
|
17 |
|
18 |
));
|
19 |
|
20 |
|
21 |
|
22 |
}
|
Luego, en server.js, modificamos las rutas de importación y agregamos el pasaporte como un argumento como este:
var authRoute = require('./app/routes/auth.js')(app,passport);
Ahora, vaya a la URL de registro http://localhost:5000/signup/ e intente registrarse.
Cuando intente registrarse, obtendrá un error "Failed to serialize user into session" ("No se pudo serializar al usuario en la sesión"). Esto se debe a que el pasaporte debe guardar un ID de usuario en la sesión y lo usa para administrar la recuperación de los detalles del usuario cuando sea necesario.
Para resolver esto, vamos a implementar las funciones de serialización y deserialización del pasaporte en nuestro archivo app/config/passport/passport.js.
Primero, agregamos la función serializar. En esta función, guardaremos el user id en la sesión.
Para hacer esto, agregamos las siguientes líneas debajo de la inicialización de la estrategia local.
1 |
//serialize
|
2 |
passport.serializeUser(function(user, done) { |
3 |
|
4 |
done(null, user.id); |
5 |
|
6 |
});
|
A continuación, implementamos la función deserializar. Agregue la función justo debajo de la función serializar.
1 |
// deserialize user
|
2 |
passport.deserializeUser(function(id, done) { |
3 |
|
4 |
User.findById(id).then(function(user) { |
5 |
|
6 |
if (user) { |
7 |
|
8 |
done(null, user.get()); |
9 |
|
10 |
} else { |
11 |
|
12 |
done(user.errors, null); |
13 |
|
14 |
}
|
15 |
|
16 |
});
|
17 |
|
18 |
});
|
En la
función de deserialización anterior, utilizamos la promesa Sequelize
findById para obtener el usuario, y si tiene éxito, se devuelve una
instancia del modelo Sequelize. Para obtener el objeto User desde esta instancia, usamos la función Sequelize getter como esta: user.get().
Ahora corre de nuevo:
1 |
node server.js |
E intenta inscribirte. ¡Hurra si tienes el "Cannot GET /dashboard" (No se puede GET /dashboard)! Significa que nuestra autenticación fue exitosa. Recuerde que hemos sido redirigidos a /dashboard en nuestro método passport.authenticate en routes/auth.js.
Ahora continuemos y agreguemos esa ruta. Luego, agregue un middleware para asegurarse de que solo se puede acceder a la página cuando un usuario inicia sesión en la sesión.
En nuestra carpeta de app/views, creamos un nuevo archivo llamado dashboard.hbs y agregamos el siguiente código HTML en él.
1 |
<!DOCTYPE html>
|
2 |
<html>
|
3 |
|
4 |
<head>
|
5 |
<title>Passport with Sequelize</title> |
6 |
</head>
|
7 |
|
8 |
<body>
|
9 |
<h2>Dashboard</h2> |
10 |
<h5>Hurray! you are logged in.</h5> |
11 |
|
12 |
</body>
|
13 |
|
14 |
</html>
|
En routes/auth.js, agregamos esta línea dentro del bloque module.exports:
app.get('/dashboard',authController.dashboard);
A continuación, vamos a app/controllers/authController.js y agregamos el controlador del dashboard.
1 |
exports.dashboard = function(req, res) { |
2 |
|
3 |
res.render('dashboard'); |
4 |
|
5 |
}
|
Su AuthController.js debería verse así:
1 |
var exports = module.exports = {} |
2 |
|
3 |
|
4 |
exports.signup = function(req, res) { |
5 |
|
6 |
res.render('signup'); |
7 |
|
8 |
}
|
9 |
|
10 |
exports.signin = function(req, res) { |
11 |
|
12 |
res.render('signin'); |
13 |
|
14 |
}
|
15 |
|
16 |
|
17 |
exports.dashboard = function(req, res) { |
18 |
|
19 |
res.render('dashboard'); |
20 |
|
21 |
}
|
Ahora, ejecute la aplicación nuevamente e intente registrarse con una dirección de correo electrónico diferente a la que utilizó anteriormente. Serás redireccionado apropiadamente a la ruta /dashboard.
Pero /dashboard no es una ruta protegida, lo que significa que incluso si un usuario no está conectado, puede verlo. No queremos esto, así que agregaremos una ruta /logout para registrar al usuario y luego proteger la ruta y probar lo que hemos hecho.
Hagámoslo:
En routes/auth.js agregamos esta línea:
app.get('/logout',authController.logout);
Luego agregamos el controlador en la app/controllers/authController.js.
1 |
exports.logout = function(req, res) { |
2 |
|
3 |
req.session.destroy(function(err) { |
4 |
|
5 |
res.redirect('/'); |
6 |
|
7 |
});
|
8 |
|
9 |
}
|
Ahora ejecute la aplicación nuevamente e inscríbase con una dirección de correo electrónico diferente.
Después de eso, visite http://localhost:5000/logout para desconectar al usuario. Ahora visite http://localhost:5000/dashboard.
Notarás que es bastante accesible. Agreguemos un middleware personalizado para proteger esa ruta.
Para hacer esto, abrimos app/routes/auth.js y agregamos esta función en el bloque module.exports, debajo de todas las otras líneas de código.
1 |
function isLoggedIn(req, res, next) { |
2 |
|
3 |
if (req.isAuthenticated()) |
4 |
|
5 |
return next(); |
6 |
|
7 |
res.redirect('/signin'); |
8 |
|
9 |
}
|
A continuación, modificamos el controlador de ruta del tablero para que se vea así:
app.get('/dashboard',isLoggedIn, authController.dashboard);
Ahora cuando vuelva a ejecutar la aplicación e intente visitar la página del tablero y no haya iniciado sesión, deberá redirigirla a la página de inicio de sesión.
¡Uf! Es hora de implementar la parte final: el inicio de sesión.
Primero, agregaremos una nueva estrategia local para iniciar sesión en app/config/passport/passport.js.
1 |
//LOCAL SIGNIN
|
2 |
passport.use('local-signin', new LocalStrategy( |
3 |
|
4 |
{
|
5 |
|
6 |
// by default, local strategy uses username and password, we will override with email
|
7 |
|
8 |
usernameField: 'email', |
9 |
|
10 |
passwordField: 'password', |
11 |
|
12 |
passReqToCallback: true // allows us to pass back the entire request to the callback |
13 |
|
14 |
},
|
15 |
|
16 |
|
17 |
function(req, email, password, done) { |
18 |
|
19 |
var User = user; |
20 |
|
21 |
var isValidPassword = function(userpass, password) { |
22 |
|
23 |
return bCrypt.compareSync(password, userpass); |
24 |
|
25 |
}
|
26 |
|
27 |
User.findOne({ |
28 |
where: { |
29 |
email: email |
30 |
}
|
31 |
}).then(function(user) { |
32 |
|
33 |
if (!user) { |
34 |
|
35 |
return done(null, false, { |
36 |
message: 'Email does not exist' |
37 |
});
|
38 |
|
39 |
}
|
40 |
|
41 |
if (!isValidPassword(user.password, password)) { |
42 |
|
43 |
return done(null, false, { |
44 |
message: 'Incorrect password.' |
45 |
});
|
46 |
|
47 |
}
|
48 |
|
49 |
|
50 |
var userinfo = user.get(); |
51 |
return done(null, userinfo); |
52 |
|
53 |
|
54 |
}).catch(function(err) { |
55 |
|
56 |
console.log("Error:", err); |
57 |
|
58 |
return done(null, false, { |
59 |
message: 'Something went wrong with your Signin' |
60 |
});
|
61 |
|
62 |
});
|
63 |
|
64 |
|
65 |
}
|
66 |
|
67 |
));
|
En esta
estrategia, la función isValidPassword compara la contraseña ingresada
con el método de comparación bCrypt ya que almacenamos nuestra
contraseña con bcrypt.
Si los detalles son correctos, nuestro usuario iniciará sesión.
Ahora ve a routes/auth.js y agrega la ruta para publicar en /signin.
1 |
app.post('/signin', passport.authenticate('local-signin', { |
2 |
successRedirect: '/dashboard', |
3 |
|
4 |
failureRedirect: '/signin' |
5 |
}
|
6 |
|
7 |
));
|
Tus routes/auth.js deberían verse así cuando hayas terminado.
1 |
var authController = require('../controllers/authcontroller.js'); |
2 |
|
3 |
|
4 |
module.exports = function(app, passport) { |
5 |
|
6 |
|
7 |
app.get('/signup', authController.signup); |
8 |
|
9 |
|
10 |
app.get('/signin', authController.signin); |
11 |
|
12 |
|
13 |
app.post('/signup', passport.authenticate('local-signup', { |
14 |
successRedirect: '/dashboard', |
15 |
|
16 |
failureRedirect: '/signup' |
17 |
}
|
18 |
|
19 |
));
|
20 |
|
21 |
|
22 |
app.get('/dashboard', isLoggedIn, authController.dashboard); |
23 |
|
24 |
|
25 |
|
26 |
app.get('/logout', authController.logout); |
27 |
|
28 |
|
29 |
app.post('/signin', passport.authenticate('local-signin', { |
30 |
successRedirect: '/dashboard', |
31 |
|
32 |
failureRedirect: '/signin' |
33 |
}
|
34 |
|
35 |
));
|
36 |
|
37 |
|
38 |
function isLoggedIn(req, res, next) { |
39 |
|
40 |
if (req.isAuthenticated()) |
41 |
|
42 |
return next(); |
43 |
|
44 |
res.redirect('/signin'); |
45 |
|
46 |
}
|
47 |
|
48 |
}
|
Ahora ejecute la aplicación e intente iniciar sesión. Debería poder iniciar sesión con cualquiera de los detalles que utilizó al registrarse, y se lo dirigirá a http://localhost:5000/dashboard/.
¡Felicitaciones si has llegado al final de este tutorial! Hemos utilizado con éxito Sequelize y Passport con una base de datos MySQL.
El código completo para este tutorial se puede encontrar en GitHub.
Conclusión
Con esto concluye nuestro tutorial sobre el uso de Passport para la autenticación de usuarios con Sequelize y MySQL. Sequelize es un ORM realmente útil para tratar con MySQL cuando se usa Node. Personalmente, he encontrado que es muy útil, y definitivamente debes considerar usarlo en tu próxima aplicación Node-MySQL.



