Como usar Passport JS con facebook, JWT, MongoDB, Express JS y Vue JS
En este ejemplo te enseñare como crear un login social de una manera muy simple con 10 pasos.
enlace del repositorio de ejemplo
Indice
-
- Instalación de dependencias en el backend.
-
- Estructura del backend.
-
- Creación del servidor Express JS.
-
- Conexión a la base de datos MongoDB
-
- Creación de Schema de base de datos MongoDB.
-
- Configuracion de Passport JS con facebook.
-
- Creación de rutas de Registro e Inicio de Sesión.
-
- Creación de boton de de Registrarse e Inicio de Sesion con Vuejs
-
- Configuracion de Passport-JWT
-
- Creacion de ruta protegida
1) Instalación de dependencias en el backend.
npm install express passport passport-facebook passport-jwt cors jsonwebtoken && npm install nodemon -D
2) Estructura del backend.
Vamos a crear una estructura de carpetas para los archivos que usaremos en este ejemplo:
--src/
models/
user.js
passport/
facebook-auth.js
verify-token.js
routes/
routes.js
rutasProtegidas.js
--database.js
-server.js
-package.json
3) Creación del servidor Express JS.
crearemos un servidor muy sencillo con el framework de Node JS
server.js
const express = require('express');
const morgan = require('morgan')
const passport = require('passport')
const cors = require('cors')
const app = express()
//settings
//middlewares
app.use(passport.initialize());
app.use(morgan('dev'))// para ver los estados http de las peticiones
app.use(express.json());
app.use(express.urlencoded({extended:false}))
app.use(cors())
//importando rutas
app.use('/', require('./routes/routes'));
//Creando servidor
let puerto = process.env.PORT || 3000
app.listen(puerto, () => console.log(`server on port ${puerto}`))
4) Conexión a la base de datos MongoDB
database.js
const mongoose = require('mongoose')
mongoose.connect("mongodb://localhost:27017/covid-19",{
useNewUrlParser:true,
useUnifiedTopology:true
}).then(db => console.log('database is connected'))
.catch(err => console.log(err));
5) Creación de Schema de base de datos MongoDB.
Para este ejemplo usaremos Mongoose como ORM.
models/user.js
const mongoose = require('mongoose')
const {Schema} = mongoose;
const userSchema = new Schema({
email: String,
firstname: String,
last_name: String,
imagen:String,
_id:String,
incluido: {type: Boolean, default: false}
});
module.exports = mongoose.model('users', userSchema);
6) Configuracion de Passport JS con facebook.
Creamos un estrategia, para usar la autenticación de Facebook, primero debe crear una aplicación en Facebook Developers en el cual obtendremos:
- App ID
- App Secret.
passport/facebook-auth.js
const passport = require("passport");
const FacebookStrategy = require("passport-facebook").Strategy;
const User = require("../models/user");
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
const user = await User.findById(id);
done(null, user);
});
// Estrategia para Registrarse
passport.use(
"sign-in-facebook",
new FacebookStrategy(
{
clientID: 11228228282, // coloca tu propio clientID
clientSecret: "2222wssandndnehenf",// coloca tu propio secret
callbackURL: "http://localhost:3000/auth/facebook/callback",
profileFields: ["email", "name", "photos","profileUrl"],
},
async (accessToken, refreshToken, profile, done) => {
const user = await User.findById(profile.id); //si no existe en la base de datos lo guarda
if (user) {
return done(null,false);
} else {
const { email, first_name, last_name } = profile._json;
const user = new User();
(user.email = email),
(user.firstname = first_name),
(user.last_name = last_name);
user._id = profile.id;
user.imagen = profile.photos[0].value
await user.save(); //guardamos en la base de datos
done(null, profile); //devolvemos el profile con todos los datos del usuario
}
}
)
);
// Estrategia para Iniciar Sesion
passport.use(
"sign-up-facebook",
new FacebookStrategy(
{
clientID: 2576357032629101111111117, // coloca tu propio clientID
clientSecret: "3af7d2f7630645b43ef7791111111c148e3ce8d",// coloca tu propio secret
callbackURL: "http://localhost:3000/auth/facebook/signin",
profileFields: ["email", "name", "photos"],
},
async (accessToken, refreshToken, profile, done) => {
const user = await User.findById(profile.id); // si existe en la base de datos
// puede iniciar sesion
if (user) {
done(null, user);
} else {
return done(null, false);
}
}
)
);
7) Creación de rutas de Registro e Inicio de Sesión.
Creamos las rutas y utilizaremos jsonwebtoken para poder crear un token con caducidad de 24 horas.
Para este ejemplo mandaremos al cliente el token por cookie lo recomendable es que le ponga otro nombre para hacer “un poco mas seguro el token” con fines educativos le coloque token
routes/routes.js
const router = require("express").Router();
const passport = require("passport");
const User = require('../models/user')
const jwt = require('jsonwebtoken') //importamos el modulo para crear el token
//rutas para facebook
router.get(
"/auth/facebook",
passport.authenticate("sign-in-facebook", {
scope: ["email"],
})
);
//ruta para Registrarse
router.get("/auth/facebook/callback",passport.authenticate("sign-in-facebook", { session: true }),
function (req, res) {
if (req.user) {
const token = jwt.sign({id: req.user._id}, 'top_secret', {
expiresIn: 60 * 60 * 24 // equivalente a 24 horas
})
res.cookie('token', token)
console.log('el token es ',token);
res.redirect(`http://localhost:8080/about`);
} else {
failureRedirect: `http://localhost:8080/`;
}
}
);
//rutas para Iniciar Sesion
router.get(
"/auth/facebook/signin",
passport.authenticate("sign-up-facebook", { session: true }),
function (req, res) {
if (req.user) {
const token = jwt.sign({id: req.user._id}, 'top_secret', {
expiresIn: 60 * 60 * 24 // equivalente a 24 horas
})
res.cookie('token', token)
res.redirect(`http://localhost:8080/animales`);
} else {
failureRedirect: `http://localhost:8080/`;
}
}
);
module.exports = router;
8) Creación de boton de de Registrarse e Inicio de Sesion con Vuejs
Para este ejemplo muy sencillo solo utilizaremos una etiqueta para indicarle la ruta que creamos en el servidor
Enlace de Registro
<template>
<div>
<a href="http://localhost:3000/auth/facebook/callback"> Registrarse con facebook</a>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String,
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
Enlace de Inicio de Sesión
<template>
<div>
<a href="http://localhost:3000/auth/facebook/signin">
Iniciar Sesion con facebook
</a>
</div>
</template>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
9) Configuracion de Passport-JWT
Esta estrategia nos servira para usarla como middleware ya que con esta verificaremos el token que nos pasa el usuario.
en secretOrKey pasamos el texto con el cual firmamos el token en la ruta
ExtractJWT.fromUrlQueryParameter(‘secret_token’) le indicamos a la estrategia que le pasaremos el token por un parametro llamado secret_token
passport/verify-token.js*
const JWTstrategy = require('passport-jwt').Strategy;
const passport = require('passport')
//Usamos esto para extraer el JWT enviado por el usuario
const ExtractJWT = require('passport-jwt').ExtractJwt;
//Esto verifica que el token enviado por el usuario es válido
passport.use(new JWTstrategy({
//secreto que solíamos firmar nuestro JWT
secretOrKey : 'top_secret',
//esperamos que el usuario envíe el token como un parámetro de consulta con el nombre 'secret_token'
jwtFromRequest : ExtractJWT.fromUrlQueryParameter('secret_token')
}, (token, done) => {
try {
//Pass the user details to the next middleware
return done(null, token);
} catch (error) {
done(error);
}
}))
Creamos la vista de animales
Obtenemos el token definimos en el backend con document.cookie
Si iniciamos sesion correctamente debemos ver el arreglo de animales por pantalla.
<template>
<div>
<h1>Animales</h1>
<h1 v-for="a in animales" :key="a.id">{{a.nombre}}</h1>
</div>
</template>
<script>
import axios from "axios";
export default {
created() {
let valor = document.cookie.split("token=");
this.cookie = valor[1];
},
mounted(){
this.obtenerAnimales()
},
data() {
return {
cookie: "",
animales: []
};
},
methods:{
obtenerAnimales(){
// haces la peticion a la ruta animal del servidor
axios.get(`http://localhost:3000/api/animales?secret_token=${this.cookie}`)
.then(res => {
this.animales = res.data.animales
})
.catch(err => console.log(err))
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
10) Creacion de ruta protegida
Para este ejemplo crearemos una ruta /animales la cual devuelve como json un arreglo de animales
todas las rutas que pongamos en este archivo seran protegidas
routes/rutasProtegidas
const router = require("express").Router();
router.get("/animales", (req, res, next) => {
let animales = [
{ id: 1, nombre: "Elefante" },
{ id: 2, nombre: "Perro" },
{ id: 1, nombre: "Tigre" }
];
res.json({"animales": animales})
next();
});
module.exports = router;
Finalmente nuestro server.js
importamos los ficheros de las estrategias
app.use('/api’, passport.authenticate(‘jwt’, { session : false }), rutasProtegidas ); le estamos indicando que deben pasar por la estrategia para poder acceder a la ruta
const express = require('express');
const morgan = require('morgan')
const passport = require('passport')
const cors = require('cors')
//initializations
const app = express()
require('./database')
require('./passport/facebook-auth')
require('./passport/verify-token')
//settings
//middlewares
app.use(passport.initialize());
app.use(morgan('dev'))// para ver los estados http de las peticiones
app.use(express.json());
app.use(express.urlencoded({extended:false}))
app.use(cors())
//importando rutas
app.use('/', require('./routes/routes'));
const rutasProtegidas = require('./routes/rutasProtegidas')
app.use('/api', passport.authenticate('jwt', { session : false }), rutasProtegidas );
let puerto = process.env.PORT || 3000
app.listen(puerto, () => console.log(`server on port ${puerto}`))


