Reputation: 304
I am trying to implement a local Strategy with passport so that users can login based on the database credentials from mysql. However I keep getting a "view error" for some reason when I try logging in with my login form.
When I login with no credentials it shoots out a "Missing Credential" connect-flash error. However when I put in a username and password in the login I get a "Failed to lookup view "error" in views directory".
I was hoping if someone can point out where the problem lies within my code.
My structure is setup in this way
config
--database.js
--passport.js
models
--user.js
routes
--users.js
views
--login.js
app.js
app.js file
const express = require('express');
const mysql = require('mysql');
const path = require('path');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const expressValidator = require('express-validator');
const flash = require('connect-flash');
const session = require('express-session');
const passport = require('passport');
const config = require('./config/database');
// Init MySql
const db = mysql.createConnection(config);
db.connect((err) => {
if(err) throw err;
console.log('MySql Connected...');
});
// Init App
const app = express();
// View Engine Setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// Connect to public directory
// uncomment after placing your favicon in /public
// app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// Express Session Middleware
app.use(session({
secret: 'secretKey',
resave: true,
saveUninitialized: true
}));
// Express Messages Middleware
app.use(require('connect-flash')());
app.use((req, res, next) => {
res.locals.messages = require('express-messages')(req, res);
next();
});
// Express Validator Middleware
app.use(expressValidator({
errorFormatter: (param, msg, value) => {
var namespace = param.split('.'),
root = namespace.shift(),
formParam = root;
while(namespace.length) {
formParam += '[' + namepsace.shift() + ']';
}
return {
param: formParam,
msg: msg,
value: value
};
}
}));
// Passport Config
require('./config/passport')(passport);
// Passport Middleware
app.use(passport.initialize());
app.use(passport.session());
// Route Files
let index = require('./routes/index');
let users = require('./routes/users');
let posts = require('./routes/posts');
// Routers
app.use('/', index);
app.use('/users', users);
app.use('/posts', posts);
// catch 404 and forward to error handler
app.use((req, res, next) => {
let err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use((err, req, res, next) => {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
// Start Server
app.listen('3000', (req, res, next) => {
console.log('Server started on port 3000...');
});
module.exports = app;
models/user.js
let mysqlModel = require('mysql-model');
const config = require('../config/database');
let UserModel = mysqlModel.createConnection(config);
// User Model
let User = UserModel.extend({
tableName: 'users'
});
module.exports = User;
routes/users.js
const express = require('express');
const mysql = require('mysql');
const router = express.Router();
const config = require('../config/database');
const bcrypt = require('bcryptjs');
const passport = require('passport');
// Init MySql
const db = mysql.createConnection(config);
// User Model
let User = require('../models/user');
// Login Form
router.get('/login', (req, res) => {
res.render('login');
});
// Login Process
router.post('/login', (req, res, next) => {
passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/users/login',
failureFlash: true
})(req, res, next);
});
module.exports = router;
config/passport.js
const LocalStrategy = require('passport-local').Strategy;
const mysql = require('mysql');
const bcrypt = require('bcryptjs');
const config = require('../config/database');
// Init MySql
const db = mysql.createConnection(config);
// User Model
const User = require('../models/user');
module.exports = (passport) => {
// Local Strategy
passport.use(new LocalStrategy((username, password, done) => {
// Match Username
let query = {username:username};
User.findOne(query, (err, user) => {
if(err) throw err;
if(!user){
return done(null, false, {message: 'No user found'});
}
// Match Password
bcrypt.compare(password, user.password, (err, isMatch) => {
if(err) throw err;
if(isMatch){
return done(null, user);
} else {
return done(null, false, {message: 'Wrong Password'});
}
});
});
}));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user); done(err, user);
});
});
}
views/login.pug
extends layout
block content
h1 Login
hr
form(method='POST', action='/users/login')
#form-group
label Username
input.form-control(name='username', type='text')
#form-group
label Password
input.form-control(name='password', type='password')
br
input.btn.btn-primary(type='submit', value='Submit')
I have been stuck for quite some time and any help would be appreciated. Thank you.
Upvotes: 0
Views: 589
Reputation: 135
I can't simply comment as I don't have the reputation. But I had a similar problem with the order of the middleware stack in app.js.
Do you initialise passport with user serialisation and deserialisation functions? E.g;
module.exports = function(passport){
//Serialise User
passport.serializeUser(function(user, done) {
console.log("Serializing User: " + user.username + "\n" + user + ".");
done(null, user._id);
});
//De-Serialise User
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
console.log("Deserializing User: " + user.username + "\n" + user);
done(err, user);
});
});
//Setting up Passport Strategies for Login and SignUp/Registration
login(passport);
signup(passport);
}
You'll also want to specify passport for your routes in app.js
// Route Files
let index = require('./routes/index')(passport);
let users = require('./routes/users')(passport);
let posts = require('./routes/posts')(passport);
and in the route files themselves, you'll want to wrap your routes in an modules export function for passport. E.g;
module.exports = function(passport) {
//Routes
return router;
}
Then you can protect your routes by writing a function that checks if the user is logged in.
let isAuthenticated = function(req, res, next) {
if (req.isAuthenticated()) {
console.log("User " + req.user.username + " authenticated.");
return next();
} else {
res.redirect('/unauthorised');
}
}
//Protect a route
router.get('/some-route', isAuthenticated, function(req, res) {
res.render('some-file');
}
Have a look here for a tutorial on the matter.
Upvotes: 1