So i am trying to allow users to upload a profile image for there profile and i got the form kinda how i want it for now but i keep running into an error saying TypeError: Cannot read property 'profilePicUpload' of undefined
even though i am almost certain that all of my code is fine here is the routes.js
// app/routes.js
var mysql = require('mysql');
var dbconfig = require('../config/database');
var connection = mysql.createConnection(dbconfig.connection);
const fileUpload = require('express-fileupload');
module.exports = function(app, passport) {
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
// =====================================
// HOME PAGE (with login links) ========
// =====================================
app.get('/', function(req, res) {
res.render('login.ejs', { message: req.flash('loginMessage') }); // load the index.ejs file
});
// =====================================
// LOGIN ===============================
// =====================================
// show the login form
app.get('/login', function(req, res) {
// render the page and pass in any flash data if it exists
res.render('login.ejs', { message: req.flash('loginMessage') });
});
app.use(fileUpload());
app.post('/upload', function(req, res) {
console.log(req.files.profilePicUpload);
});
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// process the login form
app.post('/login', passport.authenticate('local-login', {
successRedirect: '/mainchat', // redirect to the secure profile section
failureRedirect: '/login', // redirect back to the signup page if there is an error
failureFlash: true // allow flash messages
}),
function(req, res) {
console.log("hello");
if (req.body.remember) {
req.session.cookie.maxAge = 1000 * 60 * 3;
} else {
req.session.cookie.expires = false;
}
res.redirect('/');
});
// =====================================
// SIGNUP ==============================
// =====================================
// show the signup form
app.get('/signup', function(req, res) {
// render the page and pass in any flash data if it exists
res.render('signup.ejs', { message: req.flash('signupMessage') });
});
// process the signup form
app.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/mainchat', // redirect to the secure profile section
failureRedirect: '/signup', // redirect back to the signup page if there is an error
failureFlash: true // allow flash messages
}));
// =====================================
// PROFILE SECTION =========================
// =====================================
// we will want this protected so you have to be logged in to visit
// we will use route middleware to verify this (the isLoggedIn function)
app.get('/profile', isLoggedIn, function(req, res) {
var aboutUser = connection.query("SELECT about FROM users WHERE username = ?", req.user, function(err, rows) {
res.render('profile.ejs', {
user: req.user,
about: rows
});
});
});
app.get('/mainchat', isLoggedIn, function(req, res) {
var username = req.user.displayName;
res.render('mainchat.ejs', username);
console.log(req.user.displayName)
});
// =====================================
// LOGOUT ============================= rows.forEach(function(row) {=
// =====================================
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
};
// route middleware to make sure
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the home page
res.redirect('/');
}
and here is my upload form
<form id="form" action="/upload" method="POST">
<div class="fileUpload" id="profile-picture-upload">
<input name="profilePictureToUpload" type="file" id="profile-picture-upload" class="upload" />
</div>
<input type="submit" name="profilePicUpload" id="upload-profilePic-button"></input>
</form>
when i press enter it just shows that error i said above ? can someone please help me
Print out the content of req.files. ie console.log(req.files);
should you be using req.files.profilePictureToUpload instead? As opposed to req.files.profilePicUpload;
If you don't see the property, then it's likely an issue with the file contents not getting appended onto the request object properly.
Also, you don't need to globally apply the file upload to every single route you're using. just use it for whichever endpoint actually uploads:
app.post('/upload', fileUpload(), function(req, res) {
console.log(req.files.profilePicUpload);
});
You should use express-fileupload in app.js as a middle ware
const fileUpload = require('express-fileupload');
const app = express()
app.use(fileUpload());
then you can see req.files anywhare in routes or in app
Related
I tried to follow along with Colt Steele's yelpcamp project but his packages are old, so I wonder if the codes are outdated.
I use the middleware isLoggedIn to return the user to the previous page after logging in.
In my middleware.js file:
module.exports.isLoggedIn = (req, res, next) => {
if (!req.isAuthenticated()) {
req.session.returnTo = req.originalUrl
req.flash('error', 'You must sign in first!');
return res.redirect('/login');
}
next();
}
In my campgrounds.js page, I use isLoggedIn as the middleware, so I have to log in to create a new campground. So if I am not logged in and I go to localhost:3000/campgrounds/new, return to should be '/campgrounds/new'.
router.get('/new', isLoggedIn, (req, res) => {
res.render('campgrounds/new');
});
In the app.js page, I set up a middleware the set the session's currentUser to req.user. Also, I print out req.session.returnTo with this middleware, up until this point, the req.session's returnTo variable is still 'campgrounds/new'.
app.use((req, res, next) => {
console.log(req.session);
console.log(req.session.returnTo);
res.locals.currentUser = req.user;
res.locals.success = req.flash('success');
res.locals.error = req.flash('error');
next();
});
In users.js, if I successfully log in, I get redirect to the route where returnTo is, the problem is returnTo changed from '/campgrounds/new' to undefined all the sudden.
router.post('/login', passport.authenticate('local', { failureFlash: true, failureRedirect: '/login' }), (req, res) => {
req.flash('success', 'Welcome back!');
console.log("Session\n---------\n", req.session);
console.log("returnTo\n---------\n", req.session.returnTo);
const redirectUrl = req.session.returnTo || '/campgrounds';
console.log("redirectUrl\n---------\n", redirectUrl);
delete req.session.returnTo;
res.redirect(redirectUrl);
});
Now, if I go to localhost:3000/campgrounds/new, I will be redirected to /login, then in after I login, I will be redirected to /campgrounds instead of campgrounds/new.
Here is the console log from my Git Bash.
Any idea what's going on here?
I´m facing a confusion issue while implementing the authentication for my restful api using passport local strategy.
Note:
I got the authentication working successfully when I´m doing it all in my index.js. But I want to use in Classes for better Code separation.
I have a passport.js Module
// config/passport.js
// load all the things we need
var LocalStrategy = require('passport-local').Strategy;
// load up the user model
var mysql = require('mysql');
var dbconfig = require('./database');
var connection = mysql.createConnection(dbconfig.connection);
module.exports = function(passport) {
// passport needs ability to serialize and unserialize users out of session
passport.serializeUser(function (user, done) {
//console.log("SER");
console.log(user),
done(null, user);
});
passport.deserializeUser(function (user, done) {
console.log("XXXX");
console.log(user);
connection.query("SELECT * FROM users WHERE name = ? ",user.name, function(err, rows){
console.log("DER");
console.log(rows);
done(err, rows[0]);
});
});
// passport local strategy for local-login, local refers to this app
passport.use('local-login', new LocalStrategy(
function (username, password, done) {
console.log("hhh");
console.log(username);
connection.query("SELECT * FROM users WHERE name = ? ",username, function(err, rows){
console.log(rows);
return done(err, rows[0]);
});
})
);
// route middleware to ensure user is logged in
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.sendStatus(401);
}
};
This is my Controller Class:
class AuthenticateController {
constructor(router, passport) {
this.router = router;
this.registerRoutes();
this.passport = passport;
}
registerRoutes() {
this.router.post('/login/:username/:password', this.login.bind(this));
//this.router.get('/logout', this.logout.bind(this));
this.router.get('/content', this.content.bind(this));
}
login(req, res) {
this.passport.authenticate("local-login", { failureRedirect: "/login"}),
res.redirect("/content");
}
content(req, res ) {
console.log(req.user);
if (req.isAuthenticated()) {
res.send("Congratulations! you've successfully logged in.")
} else {
res.sendStatus(401);
}
}
isLoggedIn(req, res, next) {
console.log(req.user);
if (req.isAuthenticated())
return next();
res.sendStatus(401);
}
}
module.exports = AuthenticateController;
The Controller gets the router and passport fully configured as parameters from my index.js.
//index.js
var express = require('express')
, cors = require('cors')
, app = express()
, passport = require('passport')
, morgan = require('morgan');
require('./config/passport')(passport); // pass passport for configuration
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(require('express-session')({secret: 'vidyapathaisalwaysrunning',
resave: true,
saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());
app.use(cors());
var apiRouter = express.Router();
app.use('/api', apiRouter);
//
var apiV1 = express.Router();
apiRouter.use('/v1', apiV1);
var authenticateApiV1 = express.Router();
apiV1.use('/auth', authenticateApiV1);
var AuthenticateController = require('./controllers/authenticate');
var ac = new AuthenticateController(authenticateApiV1, passport); //pass in our fully configured passport
//If I call this /login instead of the /auth/login/ in the Controller Class it works!
//app.post("/login",
// passport.authenticate("local-login", { failureRedirect: "/login"}),
// function (req, res) {
// res.redirect("/content");
// });
What is working and what is not working
The Authentication in general is working. In my posted index.js you see app.post("/login", .... If I call this one the authentication is successfully and if I try to reach the restricted content in /auth/content/ req.user has a value (the user object) and I can successfully call req.isAuthenticated() .
BUT, If I use the authentication from /auth/login/username/password the req.user is undefined when trying to reach the restricted Content.
I get no error and the response of /auth/login/username/password/ HTTP Code 301 - 'redirecting to /content.
I have currently no idea what I´m doing wrong here and I´m pretty new to the topic of Node/express/ passport ..
Hope someone has an Idea. If you need something else to help me, just mention it in the comments and I will do my best to provide you everything you need.
Thanks
EDIT:
I recently tried to read the req.user in the login function and even there it is undefined
login(req, res) {
this.passport.authenticate("local-login", { failureRedirect: "/login"}),
console.log(req.user) //undefined
res.redirect("/content");
}
I guess it could be some async problem and I should use some callback functions, but I don´t know how to apply this in my login()
EDIT 2:
Another Issue I´m facing is the integration of the isLoggedIn() request.
If I do this:
registerRoutes() {
this.router.get('/', this.isLoggedIn, this.getUsers.bind(this));
this.router.get('/:id', this.getSingleUser.bind(this));
}
it results in 401 - Unauthorized
A console.log(req.user); in the isLoggedIn() results in undefined.
But if I call the first route without calling isLoggedIn() and do console.log(req.user); the user object exists.
The correct use of callback with passport authentication for local strategy can be as below:
function(req, res, next){
passport.authenticate('local-login', function(err, user, info){
if(err)
return logger.log('error', err);
if(user)
req.login(user, function(err){
if(err) return next(err);
return res.json({'success': true});
});
if(!user)
return res.json({'error':true, 'message': info.message, 'type': info.type});
})(req, res, next);
}
Please note the use of req.login() to explicitly set user in session.
The only thing I'm finding strange is that your route declarations are different.
In the AuthenticateController the route is declared as:
this.router.post('/login/:username/:password', ...
While in index.js, the route is simply declared as
app.post("/login", ...
How is your client submitting the login credentials to the server? If it is by form, like the tutorial, could it be that having :username and :password declared as route params but being sent by form messes with passport?
Try registering the route exactly like index.js
this.router.post('/login', ...
EDIT:
I've found another dicrepancy. In AuthenticateController the res.redirect("/content"); is not wrapped inside a callback. So it is being executed before Authenticate finishes running.
In the index.js example, passport is being used as a route middleware:
app.post("/login",
passport.authenticate("local-login", { failureRedirect: "/login"}),
function (req, res) {
res.redirect("/content");
});
While in the passport.js it is inside the callback. Consider declaring it in the route:
registerRoutes() {
this.router.post('/login', this.passport.authenticate("local-login", { failureRedirect: "/login"}), this.login.bind(this));
(...)
}
login(req, res) {
res.redirect("/content");
}
O, better yet, why not use passport's option to declare both success and failure redirects, since that seems to be all that you are doing:
login(req, res) {
this.passport.authenticate("local-login", { successRedirect: "/content", failureRedirect: "/login" });
}
You are passing this.login.bind(this) as a middleware to this.router.post('/login/:username/:password', this.login.bind(this)); but login(req, res) only responds to the request with res.redirect("/content"); i.e. redirecting to /content
So like you said, you need to supply a callback that does something with the user that is returned from passports middleware verify callback.
app.post("/login",
passport.authenticate("local-login", { failureRedirect: "/login"}),
function (req, res) {
console.log(req.user); // log user in console
res.json({user: req.user}); // send user as json response
});
The custom callback mentioned by #divsingh is if you want to explicitly have control of setting the session, error messages and redirecting the request. Any other information can be found under http://passportjs.org/docs
Hello I am new in NodeJs and I have been following this tutorial http://code.tutsplus.com/tutorials/authenticating-nodejs-applications-with-passport--cms-21619 to create a app with authenticating.
I tried to follow all the structre and code from the tutorial (code is on github https://github.com/tutsplus/passport-mongo) but when I open my app in browser
i get error this error
TypeError: passport.authenticate is not a function
at module.exports (C:\myApp\routes\index.js:24:34)
This is my index.js route file
var express = require('express');
var router = express.Router();
var passport = require('passport');
var isAuthenticated = function (req, res, next) {
// if user is authenticated in the session, call the next() to call the next request handler
// Passport adds this method to request object. A middleware is allowed to add properties to
// request and response objects
if (req.isAuthenticated())
return next();
// if the user is not authenticated then redirect him to the login page
res.redirect('/');
}
module.exports = function(passport){
/* GET login page. */
router.get('/', function(req, res) {
// Display the Login page with any flash message, if any
res.render('index', { message: req.flash('message') });
});
/* Handle Login POST */
router.post('/login', passport.authenticate('login', {
successRedirect: '/home',
failureRedirect: '/',
failureFlash : true
}));
/* GET Registration Page */
router.get('/signup', function(req, res){
res.render('register',{message: req.flash('message')});
});
/* Handle Registration POST */
router.post('/signup', passport.authenticate('signup', {
successRedirect: '/home',
failureRedirect: '/signup',
failureFlash : true
}));
/* GET Home Page */
router.get('/home', isAuthenticated, function(req, res){
res.render('home', { user: req.user });
});
/* Handle Logout */
router.get('/signout', function(req, res) {
req.logout();
res.redirect('/');
});
return router;
}
Probabbly the problem is there, maybe routing was change in some version of express, but I cant figure out what is the problem.
Can you help pme please ?
I had same problem. Look at app.js. There must be:
var routes = require('./routes/index')(passport);
You have just put the parenthesis at the wrong place.
It should be
router.post('/login', passport.authenticate('login'), {
successRedirect: '/home',
failureRedirect: '/',
failureFlash : true
});
New code for routes.js and login.ejs:
`module.exports = function(app, passport) {
// =====================================
// HOME PAGE (with login links) ========
// =====================================
app.get('/', function(req, res) {
res.render('./pages/index.ejs'); // load the index.ejs file
});
// =====================================
// LOGIN ===============================
// =====================================
app.get('/login', function(req, res) {
// render the page and pass in any flash data if it exists
res.render('./pages/login.ejs', { message: req.flash('error') });
});
// process the login form
app.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/login', // redirect back to the signup page if there is an error
failureFlash : true
}));
// =====================================
// SIGNUP ==============================
// =====================================
app.get('/signup', function(req, res) {
// render the page and pass in any flash data if it exists
res.render('./pages/signup.ejs', { message: req.flash('signupMessage') });
});
// process the signup form
app.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
// =====================================
// PROFILE SECTION =========================
// =====================================
// we will want this protected so you have to be logged in to visit
// we will use route middleware to verify this (the isLoggedIn function)
app.get('/profile/:id', isLoggedIn, function (req, res) {
var id = req.params.id;
res.send('./pages/profile.ejs' + req.params.id);
});
// =====================================
// LOGOUT ==============================
// =====================================
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
// =====================================
// UPLOAD ==============================
// =====================================
app.get('/upload', function (req, res){
res.render('./pages/upload.ejs');
});
// =====================================
// PASSWORD RESET ======================
// =====================================
app.get('/forgot', isLoggedIn, function (req, res){
res.render('./pages/forgot.ejs');
});
app.post('/forgot', function(req, res, next) {
async.waterfall([
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
User.findOne({ email: req.body.email }, function(err, user) {
if (!user) {
req.flash('error', 'No account with that email address exists.');
return res.redirect('/forgot');
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err, token, user);
});
});
},
function(token, user, done) {
var smtpTransport = nodemailer.createTransport('SMTP', {
service: 'SendGrid',
auth: {
user: '!!! YOUR SENDGRID USERNAME !!!',
pass: '!!! YOUR SENDGRID PASSWORD !!!'
}
});
var mailOptions = {
to: user.email,
from: 'passwordreset#demo.com',
subject: 'Node.js Password Reset',
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
'http://' + req.headers.host + '/reset/' + token + '\n\n' +
'If you did not request this, please ignore this email and your password will remain unchanged.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
req.flash('info', 'An e-mail has been sent to ' + user.email + ' with further instructions.');
done(err, 'done');
});
}
], function(err) {
if (err) return next(err);
res.redirect('/forgot');
});
});
};
// route middleware to make sure
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if(req.isAuthenticated()){
return next();
}
// if they aren't redirect them to the home page
else{
res.redirect('/');
}
}`
And the view (login.ejs):
`<!DOCTYPE html>
<html>
<head>
<% include ../partials/head %>
</head>
<body>
<div class="container">
<div class="col-sm-6 col-sm-offset-3">
<h1><span class="fa fa-sign-in"></span>Login</h1>
<% if(message.length > 0){ %>
<div class="alert alert-danger"><%= message %></div>
<% } %>
<!-- LOGIN FORM -->
<form action="/login" method="post">
<div class="form-group">
<label>Email</label>
<input type="text" class="form-control" name="email">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" name="password">
</div>
<button type="submit" class="btn btn-warning btn-lg">Login</button>
</form>
<hr>
<p>Need an account? Signup</p>
<p>Forgot your or password? Forgot</p>
</div>
</div>
</body>
</html>`
I could also have it like = http://localhost:8080/profile/emailAddress.
The emailAddress is given when signing up for my website.
The emailAddress is stored in my database that I set up.
app.get('/profile', isLoggedIn, function (req, res) {
// store userId on login into session or any global variable
var userId = req.session.userId
res.redirect('/profile/'+userId)
}); // =>directs to http://localhost:8080/profile for every signup.
Create new route with addition param
app.get('/profile/:id', function (req, res) {
var id = req.params.id
res.render('./pages/profile.ejs', {user: id});
})
You should use request parameters. With express you can do the following:
app.get('/profile/:id', isLoggedIn, function (req, res) {
var id = req.params.id;
//do with id whatever you want
res.render('./pages/profile.ejs', {user: req.user});
});
In your isLoggedIn middleware you will have something like this:
function(req, res, next) {
if (isLoggedIn) { //check if the user is logged in
req.user = user; //fetch the user from the DB or wherever you have it
}
}
In your view you will use the user's id to build the url:
<%=user.name%>
I'm using Passport to authenticate my users on NodeJS. Currently I'm using ExpressJS and I'm trying to route my traffic. I currently use the following code:
website.js (main file)
require("./routes.js")(app);
routes.js
var pages = {
home: require("./pages/home"),
about: require("./pages/about"),
register: require("./pages/register"),
login: require("./pages/login"),
api: require("./api/index")
};
module.exports = function(app) {
app.use("/", pages['home']);
for (page in pages) {
app.use("/" + page, pages[page]);
}
app.get("/logout", function(req, res) {
req.logout();
req.redirect("/");
});
}
register.js
var express = require('express');
var router = express.Router();
var app = express();
router.get("/", function(req, res) {
res.render("register", { page: "Register", message: req.flash("registerMessage") });
});
app.post("/", passport.authenticate("register", {
successRedirect: "/about/",
failureRedirect: "/register/",
failureFlash: true,
successFlash: "Logged in!"
}));
module.exports = router;
The problem I am facing is that POST requests to this will result in a 404. The page is not found. The GET request (so /register) properly shows the registration form, but upon submitting I get a 404. If I change router.get("/", function(req,res){}) to router.use("/", function(req, res, next) {}), I will get HTTP 500 errors when I call "Next()" (Can't set headers after they are sent.), and POST still doesn't work.
Could anyone tell me how to correctly catch POST requests behind router middleware?
I solved my issue
I solved my issue by using the following:
router.route("/")
.get(function(req, res, next) {
res.render("register", { page: "Register", message: req.flash("registerMessage") });
})
.post(passport.authenticate("register", {
successRedirect: "/about/",
failureRedirect: "/register/",
failureFlash: true,
successFlash: "Logged in!"
}));