1. Small change in 'app.js' file in order to initialize passport middleware (in bold):
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const cors = require('cors');
const passport = require('passport');
const mongoose = require('mongoose');
const users = require('./routes/users');
const dbconfig = require('./config/database');
/* Connect to database */
mongoose.connect(dbconfig.database, (err) => {
if(err){
console.log('Database connection error: ', err);
}
});
mongoose.connection.on('connected', () => {
console.log('Connected to database ' + dbconfig.database);
});
/* Express initialization */
const app = express();
/* Server port number */
const port = 3000;
/* Middleware - CORS */
app.use(cors());
/* Set static folder */
app.use(express.static(path.join(__dirname, 'public')));
/* Middleware - Body parser */
app.use(bodyParser.json());
/* Middleware - Passport */
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport);
app.use('/users', users);
/* Root */
app.get('/', (req, res) => {
res.send('Invalid endpoint');
})
/* Start server */
app.listen(port, () => {
console.log('Server started on port '+port);
})
2. Create a new file '/config/passport.js' with the code below:
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const User = require('../models/user');
const config = require('../config/database');
module.exports = function (passport) {
let opts = { };
opts.jwtFromRequest = ExtractJwt.fromAuthHeader();
opts.secretOrKey = config.secret;
passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
User.getUserById(jwt_payload._doc._id, (err, user) => {
if(err){
return done(err, false);
}
if(user){
return done(null, user);
} else {
return done(null, false);
}
})
}))
}
3. Implement the '/users/authenticate' router in '/routes/users.js' (changes are in bold):
const express = require('express');
const router = express.Router();
const passport = require('passport');
const jwt = require('jsonwebtoken');
const User = require('../models/user');
const config = require('../config/database');
router.post('/register', (req, res) => {
let newUser = new User({
name: req.body.name,
email: req.body.email,
username: req.body.username,
password: req.body.password
});
User.addUser(newUser, (err, user) => {
if(err){
res.json({success: false, msg: 'Failed to register user' });
} else {
res.json({success: true, msg: 'User registered' });
}
});
})
router.post('/authenticate', (req, res) => {
const username = req.body.username;
const password = req.body.password;
User.getUserByUsername(username, (err, user) => {
if(err) throw err;
if(!user) {
return res.json({success: false, msg: 'User not found'});
}
User.comparePassword(password, user.password, (err, isMatch) => {
if(err) throw err;
if(isMatch){
const token = jwt.sign(user, config.secret, {
expiresIn: 604800 //1 week
})
res.json({
success: true,
token: 'JWT '+token,
user: {
id: user._id,
name: user.name,
username: user.username,
email: user.email
}
});
} else {
return res.json({success: false, msg: 'Wrong password'});
}
})
})
})
router.get('/profile', passport.authenticate('jwt', {session:false}), (req, res) => {
res.json({user: req.user})
})
module.exports = router;
4. Extend the user model in '/model/user.js' by adding the function 'comparePassword' as below (in bold):
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const config = require('../config/database');
// User Schema
const userSchema = mongoose.Schema({
name: { type: String },
email: { type: String, required: true },
username: { type: String, required: true },
password: { type: String, required: true }
});
const user = module.exports = mongoose.model('User', userSchema);
module.exports.getUserById = function (id, callback) {
user.findById(id, callback)
}
module.exports.getUserByUsername = function (username, callback) {
const query = { username: username };
user.findOne(query, callback);
}
module.exports.addUser= function (newUser, callback) {
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if(err) throw err;
newUser.password = hash;
newUser.save(callback);
})
})
}
module.exports.comparePassword = function (candidatePassword, hash, callback) {
bcrypt.compare(candidatePassword, hash, (err, isMatch) => {
if(err) throw err;
callback(null, isMatch);
})
}
5. Test the service using Postman (Chrome extension):
URL: localhost:3000/users/authenticate
Headers -> Content-Type: application/json
Body: raw ->
{
"username": "john",
"password": "1234"
}
References:
- https://www.npmjs.com/package/passport-jwt
- https://youtu.be/6pdFXmTfkeE?list=PLillGF-RfqbZMNtaOXJQiDebNXjVapWPZ
-
No comments:
Post a Comment