From 6ef8c7ea46fa7b287f69ca0e66dbcd86991feb68 Mon Sep 17 00:00:00 2001 From: chrisperk Date: Tue, 21 Mar 2017 23:07:56 -0500 Subject: [PATCH] added authentication with passport and jwt-token --- .gitignore | 2 ++ src/index.js | 21 ++++++++----- src/routes/AuthenticationRoutes.js | 47 +++++++++++++++++++++++++++++- src/services/passport.js | 46 +++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 5148e52..d48be40 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ logs *.log npm-debug.log* +.env + # Runtime data pids *.pid diff --git a/src/index.js b/src/index.js index d67af11..fe52fe9 100644 --- a/src/index.js +++ b/src/index.js @@ -1,23 +1,30 @@ // dotenv allows us to declare environment variables in a .env file, \ // find out more here https://github.com/motdotla/dotenv -require("dotenv").config(); +require('dotenv').config(); import express from 'express'; import bodyParser from 'body-parser'; import mongoose from 'mongoose'; import passport from 'passport'; +import Router from './routes/AuthenticationRoutes'; +import './services/passport'; mongoose.Promise = global.Promise; mongoose - .connect("mongodb://localhost/todo-list-app") - .then(() => console.log("[mongoose] Connected to MongoDB")) - .catch(() => console.log("[mongoose] Error connecting to MongoDB")); + .connect('mongodb://localhost/todo-list-app') + .then(() => console.log('[mongoose] Connected to MongoDB')) + .catch(() => console.log('[mongoose] Error connecting to MongoDB')); const app = express(); -const authenticationRoutes = require("./routes/AuthenticationRoutes"); - app.use(bodyParser.json()); -// app.use(authenticationRoutes); +app.use(Router); + +const authStrategy = passport.authenticate('authStrategy', { session: false }); + +app.get('/api/secret', authStrategy, function (req, res) { + res.send(`The current user is ${req.user.username}`); +}); + const port = process.env.PORT || 3001; app.listen(port, () => { console.log(`Listening on port:${port}`); diff --git a/src/routes/AuthenticationRoutes.js b/src/routes/AuthenticationRoutes.js index 2f593c1..8360e26 100644 --- a/src/routes/AuthenticationRoutes.js +++ b/src/routes/AuthenticationRoutes.js @@ -1,5 +1,50 @@ import express from 'express'; -const router = express.Router(); import jwt from 'jwt-simple'; import User from '../models/UserModel'; import bcrypt from 'bcrypt'; +import passport from 'passport'; +import '../services/passport'; + +const router = express.Router(); + +const signinStrategy = passport.authenticate('signinStrategy', { session: false }); + +function tokenForUser(user) { + const timestamp = new Date().getTime(); + return jwt.encode({ userId: user.id, iat: timestamp }, process.env.SECRET); +} + +router.post('/api/signin', signinStrategy, function (req, res) { + res.json({ token: tokenForUser(req.user) }); +}); + +router.post('/api/signup', function (req, res, next) { + const { username, password } = req.body; + + if (!username || !password) { + return res.status(422) + .json({ error: 'You must provide a username and password'}); + } + + User.findOne({ username }).exec() + .then(existingUser => { + if (existingUser) { + return res.status(422).json({ error: 'Username is in use' }); + } + + bcrypt.hash(password, 10, function (error, hashedPassword) { + if (error) { + return next(error); + } + + const user = new User({ username, password: hashedPassword }); + + user.save() + .then(newUser => res.json({ token: tokenForUser(newUser) })); + }); + }) + + .catch(error => next(error)); +}); + +export default router; diff --git a/src/services/passport.js b/src/services/passport.js index 8229b59..8ae0e8b 100644 --- a/src/services/passport.js +++ b/src/services/passport.js @@ -1,3 +1,4 @@ +require('dotenv').config(); import bcrypt from 'bcrypt'; import passport from 'passport'; import User from '../models/UserModel'; @@ -6,3 +7,48 @@ import { ExtractJwt } from 'passport-jwt'; import LocalStrategy from 'passport-local'; + +const signinStrategy = new LocalStrategy(function (username, password, done) { + User.findOne({ username }).exec() + .then(user => { + if (!user) { + return done(null, false); + } + + bcrypt.compare(password, user.password, function (error, isMatch) { + if (error) { + return done(error, false); + } + + if (!isMatch) { + return done(null, false); + } + + return done(null, user); + }); + }) + + .catch(error => done(error, false)); +}); + +const jwtOptions = { + secretOrKey: process.env.SECRET, + jwtFromRequest: ExtractJwt.fromHeader('authorization') +}; + +const authStrategy = new JwtStrategy(jwtOptions, function (payload, done) { + User.findById(payload.userId, function (err, user) { + if (err) { + return done(err, false); + } + + if (user) { + done(null, user); + } else { + done(null, false); + } + }); +}); + +passport.use('signinStrategy', signinStrategy); +passport.use('authStrategy', authStrategy);