I'm trying to use passport authentication within express app.
router.get('/signup', (req ,res) => {
res.render('signup');
});
router.post('/signup', function(req, res, next) {
var username = req.body.username;
var password = req.body.password;
User.findOne({ username: username }, function(err, user) {
if(err) { return next(err); }
if(user) {
req.flash('error', 'User already exists');
return res.redirect('/signup');
}
var newUser = new User({
username: username,
password: password
});
newUser.save(next);
});
}, passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/signup',
failureFlash: true
}));
Every time I try to sign up test user, it works but it shows me an error like this:
Error: Unknown authentication strategy "local"
Can you advise me something.
It looks like you haven't setup Passport to use your passport-local strategy yet.
You'll need to import it, instantiate it, and then instruct Passport to use it. Here's an example:
var LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!user.verifyPassword(password)) { return done(null, false); }
return done(null, user);
});
}
));
router.post('/signup', function(req, res, next) {
var username = req.body.username;
var password = req.body.password;
User.findOne({ username: username }, function(err, user) {
if(err) { return next(err); }
if(user) {
req.flash('error', 'User already exists');
return res.redirect('/signup');
}
var newUser = new User({
username: username,
password: password
});
newUser.save(next);
passport.authenticate('local', { failureRedirect: '/signup' }),
function(req, res) {
res.redirect('/');
});
});
});
Please read the documentation here for that plugin.
Also, here's an example app using that auth strategy.
Try using a callback function after local instead of passing an object. Something like this:
router.post("/register", function(req, res){
var newUser = new User({username: req.body.username});
User.register(newUser, req.body.password, function(err, user){
if(err){
req.flash("error", err.message); //such as the username is taken or no username entered etc.
res.redirect("/register");
} else {
passport.authenticate("local")(req, res, function(){
res.redirect("/");
});
}
});
});
Related
users.js
technologies used
passport
passport-local
bcryptjs
multer for the profile picture upload
here's the code for the register,log in and the authentication
var router = express.Router();
var multer = require('multer');
var upload = multer({dest: './uploads'});
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
router.get('/register', function(req, res, next) {
res.render('register',{title:'Register'});
});
router.get('/login', function(req, res, next) {
res.render('login',{title:'Login'});
});
router.post('/login',
passport.authenticate('local', {failureRedirect: '/users/login', failureFlash: 'Invalid username or password'}),
function(req, res) {
req.flash('success', 'You are now logged in');
res.redirect('/');
});
passport.serializeUser(function(user, done){
done(null, user.id);
});
passport.deserializeUser(function(id, done){
User.getUserById(id, function(err, user){
done(err, user);
});
});
passport.use(new LocalStrategy(function (username, password, done) {
User.getUserByUsername(username, function (err, user) {
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown user'});
}
User.comparePassword(password, user.password, function(err,isMatch){
if(err) return done (err);
if(isMatch){
return done(null, user);
}else {
return done(null, false, {message: 'Invalid Password'});
}
});
});
}));
router.post('/register', upload.single('profilepicture'), function(req, res, next) {
var name = req.body.name;
var username = req.body.username;
var email = req.body.email;
var password = req.body.password;
var password2 = req.body.password2;
var profile = req.body.profilepicture;
if(req.file){
console.log('uploading...');
}
else{
console.log('not uploaded');
var profilepicture = 'noimage.jpg';
}
//form validator
req.checkBody('name','Name field is required').notEmpty();
req.checkBody('email','Email field is required').notEmpty();
req.checkBody('email','Email is not valid').isEmail();
req.checkBody('username','Username required').notEmpty();
req.checkBody('password','Password cannot be empty').notEmpty();
req.checkBody('password2','Passwords do not match').equals(req.body.password);
//check errors
var errors = req.validationErrors();
if(errors){
res.render('register', {
errors:errors
});
}
else{
//var User = module.exports = mongoose.model('User', userSchema);
var newUser = new User({
name:name,
email:email,
username: username,
password:password,
profilepicture:profilepicture
});
User.createUser(newUser,function(err,user){
if(err) throw err;
console.log(user);
});
req.flash('success', 'You are now registered and can log in');
res.location('/');
res.redirect('login');
}
});
router.get('/logout', function (req,res){
req.logout();
req.flash('success', 'You are now logged out');
res.redirect('/users/login');
});
module.exports = router;
the user can register successfully and the data gets stored in the database, the password is also hashed but during log in, the text 'Invalid username or password' keeps being displayed.there is no error being displayed just that the user cannot be able to log in even after registering.
what might be the issue?
I guess the code User.comparePassword(password, user.password, function(err,isMatch){ is comparing plain text password with the encrypted password from the db. Could you please check if both password and user.password are encrypted.
Well you compare your plain password with a plain password in the database. Why should you use .comparePassword() if you could just check it with password === user.password?
The problem is that you store your password as a plain text in your database. You need to hash it first and you can do it with bcrypt
Here replace this with your else block:
else {
// hash the password
let salt = 12;
bcrypt.hash(password, salt, function(err, hash) {
if (err) return res.status(500).json(err);
//var User = module.exports = mongoose.model('User', userSchema);
var newUser = new User({
name: name,
email: email,
username: username,
password: hash,
profilepicture: profilepicture
});
User.createUser(newUser, function(err, user) {
if (err) throw err;
console.log(user);
});
req.flash("success", "You are now registered and can log in");
res.location("/");
res.redirect("login");
});
}
What your compare function do is:
It hashes your plain text password with the salt value thats saved in the hash that you compare. And then it checks if both hashes are the same.
I am making an app using NodeJS, Express and Passport, but I am facing a problem with displaying user data in the views.
I get the ObjectID of the user in res.locals.user, but data from it like name, email, etc is returned as "undefined". For example, console.log(res.locals.user) returns "5ef5ddd2e67f9e2918e79bcb" but console.log(res.locals.user.name) or console.log(user.name) returns "undefined".
For clarification:
In the EJS, if I put <%= user %> it shows the object ID of the user from the database. If I put <%= user.name %> it doesn't render and console shows "undefined".
Here is my passport-local-strategy.js:
const express = require('express');
const LocalStrategy = require('passport-local').Strategy;
const User = require('../models/users');
passport.use(new LocalStrategy({
usernameField: 'email'
},
function (email, password, done) {
User.findOne({ email: email }, function (err, user) {
if (err) {
console.log('Error in finding user --> Passport');
return done(err);
}
if (!user || user.password != password) {
console.log('Invalid username or password');
return done(null, false);
}
return done(null, user);
});
}
));
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
if (err) {
console.log('Error in finding user --> Passport');
return done(err);
}
return done(null, user.id);
});
});
passport.checkAuthentication = function (req, res, next) {
if (req.isAuthenticated()) {
return next();
}
return res.redirect('/users/sign-in');
};
passport.setAuthenticatedUser = function (req, res, next) {
if (req.isAuthenticated()) {
res.locals.user = req.user;
console.log(res.locals.user);
}
next();
}
module.exports = passport;
I fixed it by assigning res.locals.user to User.findById with an async and await block.
passport.setAuthenticatedUser = async function (req, res, next) {
if (req.isAuthenticated()) {
res.locals.user = await User.findById(req.user, function (err, user) {
if (err) {
console.log('Error in finding user --> Passport');
}
return;
});
}
next();
}
I am new to building REST API's, and I am trying to enter new user information into a collection called 'Users', however, when I submit the information I get Cannot POST /register
Below is my code
server.js
require('dotenv').config()
const express = require('express')
const app = express()
const mongoose = require('mongoose')
const expressValidator = require('express-validator')
mongoose.connect(process.env.DATABASE_URL, { useNewUrlParser: true , useUnifiedTopology: true })
const db = mongoose.connection
db.on('error', (error) => console.error(error))
db.once('open', () => console.log('Connected to Database'))
app.use(express.json())
const articlesRouter = require('./routes/articles')
app.use('/articles', articlesRouter)
const userRouter = require('./routes/users')
app.use('/register', userRouter)
app.set('view-engine', 'ejs')
app.use(express.urlencoded({ extended: false }))
app.get('/', (req, res) => {
res.render('index.ejs')
})
app.get('/login', (req, res) => {
res.render('login.ejs')
})
app.post('/login', (req, res) => {
})
app.get('/register', (req, res) => {
res.render('register.ejs')
})
app.listen(3000, () => console.log('Server Started'))
Users model
const mongoose = require('mongoose')
const bcrypt = require('bcrypt')
var userSchema = new mongoose.Schema({
firstName: String,
lastName: String,
email: String,
password: String,
permissionLevel: Number,
created: Date},
{ collection: 'Users'});
module.exports = mongoose.model('Users', userSchema);
module.exports.createUser = function(newUser, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash) {
newUser.password = hash;
newUser.save(callback);
});
});
}
module.exports.getUserByEmail = function(email, callback){
var query = {email: email};
User.findOne(query, callback);
}
module.exports.getUserById = function(id, callback){
user.findById(id, callback);
}
module.exports.comparePassword = function(candidatePassword, hash, callback) {
bcrypt.compare(candidatePassword, hash, function(err, isMatch){
if(err) throw err;
callback(null, isMatch)
});
}
users routes
const express = require('express')
const router = express.Router()
const Users = require('../models/users')
const passport = require('passport')
const LocalStrategy = require('passport-local').Strategy
//Register Page - GET
router.get('/register', (req, res) => {
res.render('register.hbs', {
pageTitle: 'register'
});
});
//Login Page - GET
router.get('/login', (req, res) => {
res.render('login.hbs', {
pageTitle: 'login'
});
});
//Register - POST
router.post('/', (req, res) => {
var firstName = req.body.firstName;
var lastName = req.body.lastName;
var email = req.body.email;
var password = req.body.password;
//validations
req.checkBody('firstName', 'Your First Name is Required').notEmpty();
req.checkBody('lastName', 'Your Last Name is Required').notEmpty();
req.checkBody('email', 'A valid email is required').isEmail();
req.checkBody('password', 'An Account Passowrd Is Required').notEmpty();
var errors = req.validationErrors();
if (errors) {
res.render('register', {
errors:errors
});
} else {
var newUser = new newUser({
firstName: firstName,
lastName: lastName,
email: email,
password: password,
});
User.createUser(newUser, function(err, user) {
if(err) throw(err);
console.log(user);
});
req.flash('success_message', "You are now registered!");
res.redirect('/login');
}
});
passport.use(new LocalStrategy({
email: 'email'
},
function(email, password, done){
Users.getUserByEmail(email, function(err, Users){
if(err) throw err;
if(!Users){
return done(null, false, {message: 'Unknown Email Address'});
}
Users.comparePassword(password, user.password, function(err, ismatch){
if(err) throw err;
if(ismatch){
return done (null, user);
} else {
return done(null, false, {message: 'Invalid Passowrd'});
}
});
});
}));
passport.serializeUser(function(user, done){
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
Users.getUserByID(id, function(err, user) {
done(err, user)
});
});
router.post('/login', passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/login',
successFlash: 'Welcome',
failureFlash: 'Invalid Email or Passowrd!'
}), function(req, res) {
res.redirect('/');
});
router.get('/logout', function(req, res) {
req.logout();
req.flash('Success_message', 'You are now logged out!')
res.redirect('/');
});
module.exports = router
I suspect the conflict is between the router /register and the my 'Users' collection. I'm just unable to pinpoint what the issue could be.
Any help would be greatly appreciated
Your userRouter is mounted on /users (from your code: app.use('/users', userRouter), meaning that all the routes you declared in the router are prefixed by /users).
Try calling POST /users/register.
You're using users routes file at /users route, so when you declare /register route in users routes file it become /users/register please send your REST API request to /users/register endpoint
I am currently trying to develop a role based administration. If a user is created at the moment, a "1" is stored in the database at "Admin". If it is a normal user, a "2" will be entered here. I want this to be read from the database and the distinction to be made so that the corresponding start page is displayed.
What I have:
user.js:
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const passport = require('passport');
// Load User model
const User = require('../DB/models/User');
const { forwardAuthenticated } = require('../DB/config/auth');
//User Models
//const User = require('../DB/models/user');
// Login Page
router.get('/login', (req, res) => res.render('login'));
//New User MA
router.get ('/neuerUser_MA', (req, res) => res.render ('neuerUser_MA'));
// Register
router.post('/neuerUSer_MA', (req, res) => {
const { username, admin, password, password2 } = req.body;
let errors = [];
if (password != password2) {
errors.push({ msg: 'Passwords do not match' });
}
if (password.length < 6) {
errors.push({ msg: 'Password must be at least 6 characters' });
}
if (errors.length > 0) {
res.render('neuerUser_MA', {
errors,
username,
admin,
password,
password2
});
} else {
User.findOne({email: email}).then(user => {
if (user) {
errors.push({msg: 'Email or Username already exists'});
res.render('neuerUser_MA', {
errors,
username,
admin,
password,
password2
});
} else {
const newUser = new User({
username,
admin,
password
});
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.then(user => {
req.flash(
'success_msg',
'You are now registered and can log in'
);
res.redirect('/users/login');
})
.catch(err => console.log(err));
});
});
}
});
}
});
// HOW I TRIED THE LOGIN:
router.post('/login', (req, res, next) => {
if(User.admin=="1"){
passport.authenticate('local', {
successRedirect: '/buchungen/startseite_breuninger',
failureRedirect: '/users/login',
failureFlash: true
})(req, res, next);
}
else {
passport.authenticate('local', {
successRedirect: '/buchungen/startseite_spediteur',
failureRedirect: '/users/login',
failureFlash: true
})(req, res, next);
}
});
module.exports = router;
But reading from the database does not work. Regardless of what value is stored under "Admin", the start page from else{} is always shown.
Maybe my approach is too simple. I'm still a beginner ;)
Thanks already now for help!
You can achieve your goal by change your router method like this
router.post(
'/login',
passport.authenticate('local', {
failureRedirect: '/login'
}), (req, res) => {
if (req.user.admin == "1") {
res.redirect('/buchungen/startseite_breuninger');
}
else {
res.redirect('/buchungen/startseite_spediteur');
}
});
I am currently working on a node js project with passport authentication.
But i get the following error message:
Error: "Unknown authentication strategy "
Here is my Code:
LocalStrategy = require('passport-local').Strategy;
var UserModel = require('../models/user');
module.exports = function(passport){
passport.serializeUser(function(user, done){
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user){
return done(err, user);
});
});
passport.use('local-signup', new LocalStrategy({
passReqToCallback: true
}, function(req, username, password, done){
process.nextTick(function(){
User.findOne({username: username}, function(err, user) {
if(err){
return done(err);
}
if(user){
return done(null, false, req.flash('signUpErr', 'The mail is taken'));
} else {
var newUser = new UserModel();
newUser.name = username;
newUser.password = newUser.generateHash(password);
newUser.save(function(err){
if(err){
throw err;
}
console.log('All Ok');
return done(null, newUser);
})
}
});
});
}));
}
Route:
//Post requests
app.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/',
failureRedirect : '/signup'
}));
My model:
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var UserSchema = new mongoose.Schema({
name: String,
password: String
});
UserSchema.method.generateHash = function(password){
return bcrypt.hash(password);
};
module.exports = mongoose.model('UserModel', UserSchema);
I would really need your help, thanks!
Check if you passing the strategy along with the user credentials
var credentials = {
username:"username",
password:"password",
strategy:"local"
};
$http.post('auth/signin', credentials);
Server side
function passportAuthenticate(req, res, next, strategy) {
passport.authenticate(strategy, function(err, user, info) {
if (err || !user) {
res.status(400).send(info);
} else {
next(req, res, user);
}
})(req, res, next);
}