Normalmente en nuestras aplicaciones web llega un momento en el que necesitamos implementar un sistema de registro y autenticación de usuarios.
Podemos programarlo desde cero, pero llega a ser una tarea bastante tediosa, tenemos que tener en cuenta sesiones, privacidad, encriptación de contraseñas, etc,... Si ha esto le sumamos la implementación de un registro con cuenta de Facebook o Twitter como en el acceso a los cursos de Mejorando.la, la cosa se complica bastante.
Para implementar un registro y autenticación de usuarios en Node.js, tenemos la librería Passport. A continuación veremos como implementarlo.
Necesitamos tener Node.js y MongoDB instalados en nuestro entorno. La instalación es diferente según el sistema operativo. Googlea sobre ello, encontrarás información de sobra
Configurando nuestro entorno
Seguidamente vamos a crear el esqueleto de una aplicación Node con el framework Express
Código :
$ npm install -g express $ express login-social $ cd login-social $ npm install
A continuación instalamos las dependencias que vamos a emplear en la aplicación, lo hacemos con el flag `--save` para guardarlos en el `package.json`
Código :
$ npm install --save mongoose $ npm install --save passport $ npm install --save passport-twitter $ npm install --save passport-facebook
Vamos a crear un modelo para guardar los datos del usuario. El siguiente código corresponde al archivo models/user.js:
Código :
var mongoose = require('mongoose'); var Schema = mongoose.Schema; var UserSchema = new Schema({ name: String, provider: String, provider_id: {type: String, unique: true}, photo: String, createdAt: {type: Date, default: Date.now} }); var User = mongoose.model('User', UserSchema);
Dando de alta nuestra aplicación en redes sociales
Antes de configuar Passport, vamos a crear una aplicación en Facebook y otra en Twitter para obtener sus claves de API (Key y Secret) y así poder usar esos proveedores en nuestras estrategias de registro.
Registro en Twitter: http://dev.twitter.com
Registro en Facebook: http://developers.facebook.com
Estas claves las vamos a indicar en un fichero de configuración ya que es una buena práctica es mantener las API Keys separadas del código fuente que subimos al repositorio, en un archivo `config.js` que luego importamos desde donde lo necesitemos:
Código :
var config = { twitter: { key: ‘TWITTER_API_KEY’, secret: ‘TWITTER_API_SECRET’ }, facebook: { id: ‘FACEBOOK_APP_ID’, secret: ‘FACEBOOK_APP_SECRET’ } }; module.exports = config;
Usando passport.js
Lo siguiente que debemos hacer es configurar Passport, para ello hacemos uso de las funciones `serializeUser` y `deserializeUser` hacemos que el objeto que representa al usuario se almacene en la sesión. Las estrategias `TwitterStrategy` y `FacebookStrategy` utilizamos las estrategias de autenticación que nos proporciona Passport. Necesitamos las claves que hemos indicado antes:
passport.js
Código :
var mongoose = require('mongoose'); var User = mongoose.model('User'); var TwitterStrategy = require('passport-twitter').Strategy; var FacebookStrategy = require('passport-facebook').Strategy; var config = require('./config); module.exports = function(passport) { passport.serializeUser(function(user, done) { done(null, user); }); passport.deserializeUser(function(obj, done) { done(null, obj); }); passport.use(new TwitterStrategy({ consumerKey: config.twitter.key, consumerSecret: config.twitter.secret, callbackURL: '/auth/twitter/callback' }, function(accessToken, refreshToken, profile, done) { User.findOne({provider_id: profile.id}, function(err, user) { if(err) throw(err); if(!err && user!= null) return done(null, user); var user = new User({ provider_id: profile.id, provider: profile.provider, name: profile.displayName, photo: profile.photos[0].value }); user.save(function(err) { if(err) throw err; done(null, user); }); }); })); passport.use(new FacebookStrategy({ clientID: config.facebook.id, clientSecret: config.facebook.secret, callbackURL: '/auth/twitter/callback' }, function(accessToken, refreshToken, profile, done) { User.findOne({provider_id: profile.id}, function(err, user) { if(err) throw(err); if(!err && user!= null) return done(null, user); var user = new User({ provider_id: profile.id, provider: profile.provider, name: profile.displayName, photo: profile.photos[0].value }); user.save(function(err) { if(err) throw err; done(null, user); }); }); }));
Ya podemos configurar el server express con los middlewares `app.js`:
Código :
var mongoose = require('mongoose'); var passport = require('passport'); require('./models/user'); require('./passport')(passport); mongoose.connect('mongodb://localhost/passport-example', function(err, res) { if(err) throw err; console.log('Conectado con éxito a la BD'); }); … app.use(express.cookieParser()); app.use(express.urlencoded()); app.use(express.json()); app.use(express.methodOverride()); app.use(express.session({ secret: 'secretkey' })); // Configuración de Express app.use(passport.initialize()); app.use(passport.session()); ... // Rutas de Passport app.get('/logout', function(req, res) { req.logout(); res.redirect('/'); }); app.get('/auth/twitter', passport.authenticate('twitter')); app.get('/auth/facebook', passport.authenticate('facebook')); app.get('/auth/twitter/callback', passport.authenticate('twitter', { successRedirect: '/', failureRedirect: '/login' })); app.get('/auth/facebook/callback', passport.authenticate('facebook', { successRedirect: '/', failureRedirect: '/login' })); ...
Puedes ver el resto del archivo y los demás de la aplicación en el siguiente repositorio de GitHub: https://github.com/carlosazaustre/passportjs-example
El siguiente controlador, nos renderiza la página `index.html` en la que veremos el enlace al login/registro tanto con facebook como con twitter y en cuando estemos logueados, mostraremos información del usuario:
Código :
exports.index = function(req, res){ res.render('index', { title: 'Passport-Example', user: req.user }); };
Esta sería la plantilla HTML, en la que usamos el engine Jade:
Código :
extends layout block content h1= title p Welcome to #{title} if(user) ul li img(src="#{user.photo}") li Bienvenido #{user.name} li a(href='logout') Salir else ul li a(href='auth/twitter') Login con Twitter li a(href='auth/facebook') Login con Facebook
El flujo de la aplicación sería el siguiente. Primero nos muestra los enlaces para autenticarnos con nuestra cuenta en Twitter o Facebook.
Elegimos Twitter y la apliación nos redirige a la página de Twitter del API para autenticarnos.
Y por último, cuando se finaliza la autenticación, el callback nos devuelve a la URL de inicio donde vemos nuestro nombre, el enlace al `logout` y nuestra foto de twitter.
Tenéis todo el código utilizado disponible y comentado en español en este respositorio de GitHub. Espero que os sirva en vuestros proyectos y desarrollos
¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.
Por sergio el 23 de Agosto de 2014
Por iKenshu el 23 de Agosto de 2014
Cómo sería en la versión 4 de express?
El tutorial esta perfecto. Saludos!
Por Miguel el 23 de Agosto de 2014
Lo que estaba necesitando, gracias !!
Por peyoromn el 24 de Agosto de 2014
500 FacebookGraphAPIError: (#100) Tried accessing nonexisting field (provider) on node type (User)
Por carlosazaustre el 24 de Agosto de 2014
La versión 4 de Express cambia algunas cosas, como las rutas. tengo un post en mi blog que comenta los cambios.
@peyoromn prueba a eliminar el campo "provider" en model/user.js, quizá la nueva versión de Passport o el API de Facebook no hagan uso de ello.
Saludos!
Por Alfredo el 08 de Septiembre de 2014
> node-gyp rebuild
C:\nodejs\login-social\node_modules\facebook\node_modules\base64>node "C:\Progra
m Files\nodejs\node_modules\npm\bin\node-gyp-bin\\..\..\node_modules\node-gyp\bi
n\node-gyp.js" rebuild
gyp ERR! configure error
gyp ERR! stack Error: Can't find Python executable "python", you can set the PYT
HON env variable.
gyp ERR! stack at failNoPython (C:\Program Files\nodejs\node_modules\npm\nod
e_modules\node-gyp\lib\configure.js:103:14)
gyp ERR! stack at C:\Program Files\nodejs\node_modules\npm\node_modules\node
-gyp\lib\configure.js:64:11
gyp ERR! stack at Object.oncomplete (fs.js:107:15)
gyp ERR! System Windows_NT 6.2.9200
gyp ERR! command "node" "C:\\Program Files\\nodejs\\node_modules\\npm\\node_modu
les\\node-gyp\\bin\\node-gyp.js" "rebuild"
gyp ERR! cwd C:\nodejs\login-social\node_modules\facebook\node_modules\base64
gyp ERR! node -v v0.10.28
gyp ERR! node-gyp -v v0.13.0
gyp ERR! not ok
npm ERR! [email protected] install: `node-gyp rebuild`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] install script.
npm ERR! This is most likely a problem with the base64 package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! node-gyp rebuild
npm ERR! You can get their info via:
npm ERR! npm owner ls base64
npm ERR! There is likely additional logging output above.
npm ERR! System Windows_NT 6.2.9200
npm ERR! command "C:\\Program Files\\nodejs\\\\node.exe" "C:\\Program Files\\nod
ejs\\node_modules\\npm\\bin\\npm-cli.js" "install" "--save" "passport" "facebook
"
npm ERR! cwd C:\nodejs\login-social
npm ERR! node -v v0.10.28
npm ERR! npm -v 1.4.9
npm ERR! code ELIFECYCLE
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR! C:\nodejs\login-social\npm-debug.log
npm ERR! not ok code 0
Por txesterfield el 26 de Septiembre de 2014
Solo me queda una duda, una vez que resgitras via twitter/facebook en tu aplicación al usuario... para volver a entrar en la app no debería de volver a autorizar a la app de nuevo, no? Directamente se podría loguear.
Estoy viendo que el callback de twitter devuelve un oauth_token y un oauth_verifier pero que se utilizan en la sesión. No hay manera de recuperar un token del usuario para entrar directamente sin tener que hacerle autenticarse de nuevo?
Gracias y buen trabajo.
Por danieling el 05 de Noviembre de 2014
500 FacebookGraphAPIError: (#100) Tried accessing nonexisting field (provider) on node type (User)
Comenten o borren las lineas donde aparece provider en user.js y passport.js
Por juang el 01 de Diciembre de 2014
Por juang el 01 de Diciembre de 2014
Muchas gracias!! excelente tutorial
Por Gustavo el 05 de Diciembre de 2014
set keyfacebook=896789798hhjkhjkhjkhjkh
y luego referenciarlas desde el código fuente
en fin, muy buen ejemplo
Por adelosri el 03 de Enero de 2015
Por NodeNoob el 26 de Enero de 2015
profileFields : ['id', 'displayName','photos']
del archivo user y el de crear nuevo usuario y resetean el node