Spanish (Español) translation by Elías Nicolás (you can also view the original English article)
Es un hecho bien demostrado que las contraseñas son inherentemente débiles por naturaleza. De manera que pedir a los usuarios finales que creen contraseñas seguras para cada una de las aplicaciones que utilizan simplemente empeora esta cuestión.
Es una solución fácil permitir a los usuarios autenticarse mediante sus cuentas sociales existentes como Facebook, Twitter, Google, etc.. En este artículo, vamos a hacer justamente eso y agregar esta capacidad de acceso social a la aplicación Node de muestra desarrollada en la primera parte de esta serie sobre autenticación, de forma que seamos capaces de autenticarnos a través de nuestras cuentas de Facebook y Twitter utilizando el middleware Passport.
Si no has echado un vistazo al artículo anterior, te recomiendo que lo hagas, puesto que vamos a trabajar sobre la base establecida en dicho artículo y a añadirle nuevas estrategias, rutas y vistas.
Acceso social
Para los no-iniciados, el acceso social es un tipo de identificación única usando información existente de sitios de redes sociales como Facebook, Twitter, etc., donde se espera normalmente que los usuarios tengan ya cuentas creadas.
El acceso social se basa principalmente en un esquema de autenticación como OAuth 2.0. Para obtener más información sobre los diferentes flujos de inicio de sesión que soporta OAuth, lee este artículo. Elegimos Passport para manejar el acceso social por nosotros, ya que proporciona diferentes módulos para una variedad de proveedores de OAuth, ya sea Facebook, Twitter, Google, GitHub, etc.. En este artículo usaremos los módulos passport-facebook y passport-witter para proporcionar funcionalidad de inicio de sesión a través de las cuentas existentes de Facebook o Twitter.
Autenticación a través de Facebook
Para habilitar la autenticación a través de Facebook, primero tenemos que crear una Facebook App utilizando el Facebook Developer Portal. Anota el App ID (identificador de la aplicación) y el App Secret (secreto de la aplicación), y especifica la URL de callback yendo a Ajustes (Settings) y especificando la URL del sitio (Site URL) en la sección Website para la aplicación. También asegúrate de introducir una dirección válida de correo electrónico para el campo Contact Email (correo electrónico de contacto). Es un requisito para poder realizar esta aplicación pública y accesible por el público.
A continuación, vaya a la sección Estado y revisión y gire el control deslizante a Sí para que la aplicación sea pública. Creamos un archivo de configuración, fb.js, para mantener esta información de configuración que será necesaria para conectarse a Facebook.
1 |
// facebook app settings - fb.js |
2 |
module.exports = { |
3 |
'appID' : '<your_app_identifier>', |
4 |
'appSecret' : '<your_app_secret>', |
5 |
'callbackUrl' : 'https://localhost:3000/login/facebook/callback' |
6 |
}
|
Estrategia de acceso al Facebook
De nuevo en nuestra aplicación de nodo, ahora definimos una Estrategia de Pasaporte para autenticar con Facebook usando el módulo FacebookStrategy, utilizando las configuraciones anteriores para obtener el perfil de Facebook del usuario y mostrar los detalles en la vista.
1 |
passport.use('facebook', new FacebookStrategy({ |
2 |
clientID : fbConfig.appID, |
3 |
clientSecret : fbConfig.appSecret, |
4 |
callbackURL : fbConfig.callbackUrl |
5 |
},
|
6 |
|
7 |
// facebook will send back the tokens and profile
|
8 |
function(access_token, refresh_token, profile, done) { |
9 |
// asynchronous
|
10 |
process.nextTick(function() { |
11 |
|
12 |
// find the user in the database based on their facebook id
|
13 |
User.findOne({ 'id' : profile.id }, function(err, user) { |
14 |
|
15 |
// if there is an error, stop everything and return that
|
16 |
// ie an error connecting to the database
|
17 |
if (err) |
18 |
return done(err); |
19 |
|
20 |
// if the user is found, then log them in
|
21 |
if (user) { |
22 |
return done(null, user); // user found, return that user |
23 |
} else { |
24 |
// if there is no user found with that facebook id, create them
|
25 |
var newUser = new User(); |
26 |
|
27 |
// set all of the facebook information in our user model
|
28 |
newUser.fb.id = profile.id; // set the users facebook id |
29 |
newUser.fb.access_token = access_token; // we will save the token that facebook provides to the user |
30 |
newUser.fb.firstName = profile.name.givenName; |
31 |
newUser.fb.lastName = profile.name.familyName; // look at the passport user profile to see how names are returned |
32 |
newUser.fb.email = profile.emails[0].value; // facebook can return multiple emails so we'll take the first |
33 |
|
34 |
// save our user to the database
|
35 |
newUser.save(function(err) { |
36 |
if (err) |
37 |
throw err; |
38 |
|
39 |
// if successful, return the new user
|
40 |
return done(null, newUser); |
41 |
});
|
42 |
}
|
43 |
});
|
44 |
});
|
45 |
}));
|
Configuración de rutas
Ahora necesitamos agregar ciertas rutas para permitir el inicio de sesión con Facebook y para manejar la devolución de llamada después de que el usuario haya autorizado la aplicación para usar su cuenta de Facebook.
1 |
// route for facebook authentication and login
|
2 |
// different scopes while logging in
|
3 |
router.get('/login/facebook', |
4 |
passport.authenticate('facebook', { scope : 'email' } |
5 |
));
|
6 |
|
7 |
// handle the callback after facebook has authenticated the user
|
8 |
router.get('/login/facebook/callback', |
9 |
passport.authenticate('facebook', { |
10 |
successRedirect : '/home', |
11 |
failureRedirect : '/' |
12 |
})
|
13 |
);
|
La página de inicio de sesión de nuestra aplicación de demostración se ve así:



Al hacer clic en el botón Iniciar sesión con Facebook, intentará autenticarse con Facebook. Si ya has iniciado sesión en Facebook, mostrará el cuadro de diálogo siguiente pidiendo tu permiso, o bien te pedirá que inicies sesión en Facebook y luego muestres este diálogo.



Si permite que la aplicación reciba su perfil público y su dirección de correo electrónico, se llamará a nuestra función de devolución de llamada registrada con los detalles del usuario. Podemos guardarlos para futuras referencias o mostrarlos o simplemente optar por ignorarlos, dependiendo de lo que quiera hacer con la información. Siéntase libre de saltar adelante en el tiempo y echa un vistazo al código completo en este repo git.
Sería bueno tener en cuenta que, aparte de la información básica que ofrece esta aplicación de demostración, podría utilizar el mismo mecanismo de autenticación para extraer más información útil sobre el usuario, como su lista de amigos, utilizando el ámbito apropiado y utilizando las API de Facebook con el token de acceso recibido con el perfil de usuario.
Autenticación de Twitter
Un módulo de autenticación similar necesita estar cableado para gestionar la autenticación a través de Twitter y Passport chips para ayudar con su módulo passport-passport.
En primer lugar, es necesario crear una nueva aplicación de Twitter utilizando su interfaz de administración de aplicaciones. Una cosa a tener en cuenta aquí es que mientras se especifica la URL de devolución de llamada, Twitter no parece funcionar bien si se da "localhost" en el campo de URL de devolución de llamada. Para superar esta limitación durante el desarrollo, puede utilizar la dirección de bucle especial o "127.0.0.1" en lugar de "localhost". Después de crear la aplicación, anote la siguiente clave de la API y la información secreta en un archivo de configuración de la siguiente manera:
1 |
// twitter app settings - twitter.js
|
2 |
module.exports = { |
3 |
'apikey' : '<your_app_key>', |
4 |
'apisecret' : '<you_app_secret>', |
5 |
'callbackUrl' : 'http://127.0.0.1:3000/login/twitter/callback' |
6 |
}
|
Estrategia de acceso de Twitter
La estrategia de inicio de sesión para Twitter es una instancia de TwitterStrategy
y se ve así:
1 |
passport.use('twitter', new TwitterStrategy({ |
2 |
consumerKey : twitterConfig.apikey, |
3 |
consumerSecret : twitterConfig.apisecret, |
4 |
callbackURL : twitterConfig.callbackURL |
5 |
},
|
6 |
function(token, tokenSecret, profile, done) { |
7 |
// make the code asynchronous
|
8 |
// User.findOne won't fire until we have all our data back from Twitter
|
9 |
process.nextTick(function() { |
10 |
|
11 |
User.findOne({ 'twitter.id' : profile.id }, |
12 |
function(err, user) { |
13 |
// if there is an error, stop everything and return that
|
14 |
// ie an error connecting to the database
|
15 |
if (err) |
16 |
return done(err); |
17 |
|
18 |
// if the user is found then log them in
|
19 |
if (user) { |
20 |
return done(null, user); // user found, return that user |
21 |
} else { |
22 |
// if there is no user, create them
|
23 |
var newUser = new User(); |
24 |
|
25 |
// set all of the user data that we need
|
26 |
newUser.twitter.id = profile.id; |
27 |
newUser.twitter.token = token; |
28 |
newUser.twitter.username = profile.username; |
29 |
newUser.twitter.displayName = profile.displayName; |
30 |
newUser.twitter.lastStatus = profile._json.status.text; |
31 |
|
32 |
// save our user into the database
|
33 |
newUser.save(function(err) { |
34 |
if (err) |
35 |
throw err; |
36 |
return done(null, newUser); |
37 |
});
|
38 |
}
|
39 |
});
|
40 |
});
|
41 |
})
|
42 |
);
|
Configuración de rutas
1 |
// route for twitter authentication and login
|
2 |
// different scopes while logging in
|
3 |
router.get('/login/twitter', |
4 |
passport.authenticate('twitter') |
5 |
);
|
6 |
|
7 |
// handle the callback after facebook has authenticated the user
|
8 |
router.get('/login/twitter/callback', |
9 |
passport.authenticate('twitter', { |
10 |
successRedirect : '/twitter', |
11 |
failureRedirect : '/' |
12 |
})
|
13 |
);
|
14 |
|
15 |
/* GET Twitter View Page */
|
16 |
router.get('/twitter', isAuthenticated, function(req, res){ |
17 |
res.render('twitter', { user: req.user }); |
18 |
});
|
Ahora para probar esto, asegúrese de usar http://127.0.0.1:
<port>
en lugar de usar http://localhost
:<port>
. Como
ya hemos mencionado anteriormente, parece que hay un problema al
intercambiar fichas con Twitter con "localhost" como nombre de host. Al
hacer clic en el botón Iniciar sesión con Twitter, como se espera, pide
el consentimiento del usuario para permitir que esta aplicación utilice
Twitter.



Al permitir que la aplicación acceda a su cuenta de Twitter y la información limitada, se llama al manejador de devolución de llamada que está registrado en la estrategia de inicio de sesión, que se utiliza para almacenar estos detalles en una base de datos de fondo
Conclusión
¡¡Y ahí lo tienes!! Hemos añadido con éxito los inicios de sesión de Facebook y Twitter a nuestra aplicación de ejemplo sin escribir mucho código y manejar las complejidades involucradas con el mecanismo de autenticación permitiendo que Passport haga el trabajo pesado. Se pueden escribir estrategias de inicio de sesión similares para una variedad de proveedores que soporta Passport. El código para toda la aplicación se puede encontrar en este repositorio git. Siéntase libre de extenderlo y usarlo en sus propios proyectos.