I'm using:
express 4.14
node 7.0+
session 1.14+
I created Nodejs project with webstorm:
app.js
var express = require('express');
var session = require('express-session');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var user = require('./routes/user');
var app = express();
var check = function() {
!req.session.status ? res.redirect('/user/login') : next();
}
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
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')));
app.use(session({secret: "inline", resave: false, saveUninitialized: true, status: false}));
app.use('/', check, require('./routes/index'));
app.use('/user', require('./routes/user'));
module.exports = app;
index.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
user.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.get('/login', function(req, res, next) {
res.render('login');
});
module.exports = router;
When I request to localhost:3000, the page prompt me that "too many redirects', now the url is localhost:3000/user/login?
What's my problem?
fix:
var check = function(req, res, next) {
!req.session.status ? res.redirect('/user/login') : next();
}
But I'll write more beautiful solution for You, hope You'll get in idea:
app.js:
app.use(require('./routes'));
routes folder:
routes/
|- index.js
|- common/
|- auth.js
|- root/
|- index.js
|- posts.js
|- backend/
|- index.js
|- posts.js
...
1) routes/index.js :
const
express = require('express'),
router = express.Router();
// guarded routes
function guardFn(req, res, next) {
let authenticated = req.session && req.session.authenticated === true;
authenticated ? next() : res.redirect('/auth');
}
router.use('/backend', guardFn, require('./backend'));
// public routes
router.use('/auth', require('./common/auth'); // for auth purposes
router.use('/', require('./root')); // for routes that starts from /, try not to rewrite /backend, /auth
module.exports = router;
2) routes/common/auth :
const
express = require('express'),
router = express.Router();
mongoose = require('mongoose'),
User = mongoose.model('user');
router.get('/', (req, res) => {
res.render('common/auth');
});
router.post('/', (req, res) => {
User
.findOne({
username: req.body.username,
password: req.body.password
})
.exec((err, user) => {
if(err) {
console.error(err);
return res.status(500).send('System error! Try again later');
}
if(!user) return res.redirect('back');
req.session.user = user._id;
req.session.authenticated = true;
res.redirect('/backend');
});
});
function logout(req, res, next) {
delete req.session.user;
req.session.authenticated = false;
next();
}
router.delete('/auth', logout, (req, res) => res.send({success: true}));
router.get('/auth/destroy', logout, res => res.redirect('/auth'));
module.exports = router;
3) routes/root/index.js :
const
express = require('express'),
router = express.Router();
router.get('/', (req, res) => {
res.render('site/welcome');
});
module.exports = router;
4) routes/root/posts.js :
const
express = require('express'),
router = express.Router(),
mongoose = require('mongoose'),
Post = mongoose.model('post');
router.get('/', (req, res) => {
Post
.find()
.skip((req.query.page-1)*10)
.limit(10)
.exec((err, posts) => {
res.render('site/posts/list', {posts});
});
});
router.get('/:id', (req, res) => {
Post
.findById(req.params.id)
.exec((err, post) => {
if(err) {
console.error(err);
return res.status(500).send('System error! Try again later');
}
res.render('site/posts/show', {post});
});
});
module.exports = router;
5) routes/backend/index.js :
const
express = require('express'),
router = express.Router();
router.get('/', (req, res) => {
res.render('backend/dashboard');
});
module.exports = router;
6) routes/backend/posts.js :
const
_ = require('lodash'),
express = require('express'),
router = express.Router(),
mongoose = require('mongoose'),
Post = mongoose.model('post');
router.get('/', (req, res) => {
Post
.find()
.skip((req.query.page-1)*50)
.limit(50)
.exec((err, posts) => {
res.render('backend/posts/list', {posts});
});
});
router.get('/:id', (req, res) => {
Post
.findById(req.params.id)
.exec((err, post) => {
if(err) {
console.error(err);
return res.status(500).send('System error! Try again later');
}
res.render('backend/posts/show', {post});
});
});
function updatePost(id, data, callback) {
Post
.findById(_id)
.exec((err, post) => {
if(err) return callback(err);
if(!post) return callback('not found');
post = _.extend(post, data);
post.save(() => callback(null, post));
});
}
router.put('/:id', (req, res) => {
updatePost(req.params.id, req.body, (err, post) => {
if(err) return res.status(500).send({success: false, err});
res.send({success: true, post});
});
});
router.post('/:id', (req, res) => {
updatePost(req.params.id, req.body, (err, post) => {
if(err) return res.status(500).send(err);
res.redirect('/backend/posts');
});
});
function createPost(data, callback) {
let post = new Post();
post = _.extend(post, req.body);
post.save((err) => callback(err, post));
}
router.post('/', (req, res) => {
createPost(req.body, (err, post) => {
if(req.xhr) {
if(err) return res.status(500).send({success: false, err});
return res.send({success: true, post});
}
if(err) return res.status(500).send(err);
res.redirect('/backend/posts');
});
});
module.exports = router;
As I understand it, app.use('/', ...) will match all requests which is why your check method is being called for all requests.
More good info here.
From Express docs:
A route will match any path that follows its path immediately with a
“/”.
For example: app.use("/apple", ...) will match “/apple”,
“/apple/images”, “/apple/images/news”, and so on.
I would suggest refactoring to:
var check = function(req, res, next) {
if (!req.session.status && req.path != '/user/login') {
res.redirect('/user/login');
}
else {
next();
}
}
app.use(check);
app.use('/', index);
app.use('/user', users);
So check will execute for all requests but only redirect if the request session is falsey and request path doesn't match /user/login
Keep in mind your code will fail if req.session is not set...
Related
I am trying to create a login page and sign up page, my app.js gives me this error, I think it is the last line of this code. I can send you the other components(files) for this express app. I cannot understand what is causing this error.
const express = require('express');
const mongoose = require('mongoose');
// Routes
const authRoutes = require('./routes/authRoutes');
const app = express();
// middleware
app.use(express.static('public'));
app.use((err, req, res, next) => {
res.locals.error = err;
res.status(err.status);
res.render('error');
});
// view engine
app.set('view engine', 'ejs');
// database connection
const dbURI = '<database, username and password>';
mongoose.connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex:true })
.then((result) => app.listen(3000))
.catch((err) => console.log(err));
// routes
app.get('/', (req, res) => res.render('home'));
app.get('/smoothies', (req, res) => res.render('smoothies'));
app.use(authRoutes);
authRoutes.js
const { Router } = require('express')
const authController = require('./authController.js')
const router = Router();
router.get('/signup', authController.signup_get);
router.get('/signup', authController.signup_post);
router.get('/login', authController.login_get);
router.get('/login', authController.login_post);
module.export = router;
authController.js
module.exports.signup_get = (req, res) => {
res.render('signup');
}
module.exports.login_get = (req, res) => {
res.render('login');
}
module.exports.signup_post = (req, res) => {
res.send('signup');
}
module.exports.login_post = (req, res) => {
res.send('login');
}
You are exporting incorrectly in authRoutes.js.
Change this:
module.export = router;
to this:
module.exports = router;
FYI, a little debugging on your own by simply doing a console.log(authRoutes) should have been able to show you where to look for the problem. If you get an error when you attempt to use authRoutes, you look at what it is and where it came from to see why it's not working. This is basic debugging and there is an expectation that you've done basic debugging before you post your question here.
I'm getting started in node.js and trying to create a user authentication system for my web application. I am watching a tutorial on YouTube and have followed every step through. When it comes to actually registering my user. the username entry in the collecting comes out as null. I'm not sure why this is happening, and I'm a rookie to javascript and node js. I am using passport, express and mongodb modules.
this is the video i am watching 'https://www.youtube.com/watch?v=m2ZzRZemc98'
If anyone knows how to fix my issue, please respond
Thanks
This is my main app.js
var express = require("express");
var path = require("path");
var cookieParser = require("cookie-parser");
var logger = require("morgan");
const MongoClient = require("mongodb").MongoClient;
const passport = require("passport");
const Strategy = require("passport-local").Strategy;
const session = require("express-session");
const flash = require("connect-flash");
const authUtils = require("./utils/auth");
const hbs = require("hbs");
var indexRouter = require("./routes/index");
var usersRouter = require("./routes/users");
const authRouter = require("./routes/auth");
var app = express();
//Connet to MongoDB database
MongoClient.connect("mongodb://localhost", (err, client) => {
if (err) {
throw err;
}
const db = client.db("user-profiles");
const users = db.collection("users");
app.locals.users = users;
});
//Passport streategy
passport.use(
new Strategy((username, passport, done) => {
app.locals.users.findOne({ username }, (err, user) => {
if (err) {
return done(err);
}
if (!user) {
return done(null, false);
}
if (user.password != authUtils.hashPassword(password)) {
return done(null, false);
}
return done(null, user);
});
})
);
passport.serializeUser((user, done) => {
done(null, user._id);
});
passport.deserializeUser((id, done) => {
done(null, { id });
});
// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "hbs");
hbs.registerPartials(path.join(__dirname, "views/partials"));
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));
app.use(
session({
secret: "session secret",
resave: false,
saveUninitialized: false
})
);
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use((req, res, next) => {
res.locals.loggedIn = req.isAuthenticated();
next();
});
app.use("/", indexRouter);
app.use("/users", usersRouter);
app.use("/auth", authRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(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");
});
module.exports = app;
This is my auth.js
const router = express.Router();
const authUtils = require("../utils/auth");
const passport = require("passport");
router.get("/login", (req, res, next) => {
const messages = req.flash();
res.render("login", { messages });
});
router.post(
"/login",
passport.authenticate("local", {
failureRedirect: "/auth/login",
failureFlash: "Wrong username or password"
}),
(req, res, next) => {
res.redirect("/users");
}
);
router.get("/register", (req, res, next) => {
const messages = req.flash();
res.render("register", { messages });
});
router.post("/register", (req, res, next) => {
const registrationParams = req.body;
const users = req.app.locals.users;
const payload = {
username: registrationParams.username,
password: authUtils.hashPassword(registrationParams.password)
};
users.insertOne(payload, err => {
if (err) {
req.flash("error", "User account already exists");
} else {
req.flash("success", "User account was registered succesfully");
}
res.redirect("/auth/register");
});
});
router.get("/logout", (req, res, next) => {
req.session.destroy();
res.redirect("/");
});
module.exports = router;
I fixed my error, it was a mistake i made in the handlebars file, i put the input name as none the class of form-control and then named it again. Obviously the js looked at the first name and not the second name
I am writing my own app (both of back and frontend). I want to ask you guys if I am doing it in the right way.
I want to split server.js to a few files (in PHP I would use include() for it) but I am not sure if it is the right way.
Here is some code example:
const app = require('express')(),
fs = require('fs'),
http = require('http').Server(app),
io = require('socket.io')(https),
path = require('path'),
login_user = require('./routes/login_user'),
add_user = require('./routes/add_user'),
logout = require('./routes/logout');
app.post('/login_user', (req, res, next) => {
login_user.go(req, res, next);
});
app.post('/add_user', (req, res) => {
add_user.go(req, res);
});
app.get('/logout', (req, res) => {
logout.go(req, res);
});
Please note that's not the whole code and I want to focus on spliting "routes" or "paths" to a few files. For example a whole API login system is in /routes/login_user.js file (exported).
Now I have got so many paths and code is looking a little bit weird.
app.post('/check_balance', (req, res) => {
check_balance.go(req, res);
});
app.post('/add_incoming', (req, res) => {
add_incoming.go(req, res);
});
app.post('/add_outgoing', (req, res) => {
add_outgoing.go(req, res);
});
app.post('/add_category', (req, res) => {
add_category.go(req, res);
});
app.post('/change_settings', (req, res) => {
change_settings.go(req, res);
});
app.post('/login_user', (req, res, next) => {
login_user.go(req, res, next);
});
app.post('/add_user', (req, res) => {
add_user.go(req, res);
});
app.post('/verify_user', (req, res) => {
verify_user.go(req, res);
});
app.get('/logout', (req, res) => {
logout.go(req, res);
});
app.get('/check_settings', (req, res) => {
check_settings.go(req, res);
});
app.get('/check_categories', (req, res) => {
check_categories.go(req, res);
});
app.post('/remove_categories', (req, res) => {
remove_categories.go(req, res);
});
app.get('/check_incomings', (req, res) => {
check_incomings.go(req, res);
});
app.get('/check_outgoings', (req, res) => {
check_outgoings.go(req, res);
});
app.get('/check_both', (req, res) => {
check_both.go(req, res);
});
app.get('/check_outgoings_chart', (req, res) => {
check_outgoings_chart.go(req, res);
});
app.get('/check_incomings_chart', (req, res) => {
check_incomings_chart.go(req, res);
});
app.post('/remove_incomings', (req, res) => {
remove_incomings.go(req, res);
});
app.post('/remove_outgoings', (req, res) => {
remove_outgoings.go(req, res);
});
Make your server.js as simple as possible and extract all your routing logic to separate folder (possibly name it "routes"). If you also want to define yours schema, put it in separate folder ("models"). A complete solution can be like this:
in Model Folder:
user.js
const mongoose = require("mongoose"); // In case if you want to use MongoDB
const userSchema = new mongoose.Schema({
name: { type: String, required:true },
email: { type: String, required: true },
password: { type: String, required: true },
});
exports.User = User;
In routes folder:
users.js
const { User } = require("../models/user");
const router = express.Router();
//define your routes here
router.get('/', async(req,res)=>{
const users = await User.find();
res.send(users)
});
module.exports = router;
And finally in your server.js
const app = require('express')(),
fs = require('fs'),
http = require('http').Server(app),
io = require('socket.io')(https),
path = require('path'),
users = require('./routes/users');
app.use("/api/users", users); //With this API Endpoint you can access it like http://{your_domain}/api/users
If you want to make it more clean, you can wrap all routing paths to another folder. Lets call it "startup".
with this you can do like this.
in your startup folder:
routes.js
const users = require("../routes/users");
module.exports = function(app) {
app.use("/api/users", users);
//add all routes here
}
Then in your server.js
require("./startup/routes")(app); //all routes will be imported
I think this is what you need.
Let's say that there is a file called routers/login.js:
var express = require('express');
var router = express.Router();
router.get('/login', function(req, res) {
// do something
});
then app.js:
...
var login = require('./routes/login');
app.use("/login", login)
Put all the routes files in a folder with multiple files like User_routes.js can contain routes related to user and so on.
Also all you need to then is to export these routes from each file by using module.export.your_module and include them in your server file like in user routes :
// Login Page
router.get('/login', (req, res) => res.render('login'));
// Register Page
router.get('/register',(req, res) => {
res.render('register'); });
then import it as
module.exports = router;
also include it as :
app.use('/users', require('./routes/users.js'));
app.use('/',(req,res,next)=>{
console.log('I should handle it Now.');
res.render('404');
});
i have a Problem with my project. I want to make a little download system for pictures, so i made a router for /download/:filename. I have the pictures in /userdata/${userId}/ and if i request /download/ with a param like test it logs in my console, but if i use a param wich exists in the userdata folder like Download.jpg it redirects me back to the homepath of the user: /file/${userId} here is my code:
app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index');
const admin = require("./routes/admin");
import file from "./routes/file";
import download from "./routes/download";
const session = require("express-session");
var app = express();
app.set("trust proxy", 1);
app.use(session({
secret: "bla",
resave: false,
cookie: {
maxAge: 120000000
},
saveUninitialized: false
}));
function checkIfLoggedin(req,res,next){
if(!(req.originalUrl === "/") && !req.session.loggedIn){
res.redirect('/');
return;
}
next();
};
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// 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')));
app.use(checkIfLoggedin);
app.use('/', index);
app.use("/admin", admin);
app.use("/file", file);
app.use("/download", download);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(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');
});
module.exports = app;
index.js router
var express = require('express');
var router = express.Router();
const bcrypt = require('bcrypt-nodejs');
var dbPassword;
import mysql from "mysql";
//
/* GET home page. */
router.get('/', function(req, res, next) {
if (req.session.user != undefined) {
res.redirect("/file/"+req.session.user.userId);
}
else{
res.render('index', {});
}
});
router.post('/', function(req,res,next) {
console.log("1");
const enteredUsername = req.body.username;
const enteredPassword = req.body.password;
const con = mysql.createConnection({
host: "localhost",
user: "user",
password: "pass",
database: "db"
});
con.query('SELECT * FROM users WHERE username = ?;', [`${enteredUsername}`], (error, results, fields) => {
if (results.length > 0) {
console.log("2");
console.log(error);
let dbPassword = results[0].password;
bcrypt.compare(enteredPassword, dbPassword, (err,response) => {
console.log(err);
console.log(response);
console.log("3");
if (response == true) {
req.session.user = {
userId: results[0].userId,
username: results[0].username,
isAdmin: results[0].isAdmin,
};
req.session.loggedIn = true;
console.log("file");
if (req.session.user.isAdmin) {
res.redirect("/admin");
}
else{
res.redirect("/file/" + req.session.user.userId);
}
}
else{
req.session.loggedIn = false;
console.log("false");
res.send("Falsches Passwort");
}
});
}
else{
res.send("Falsche Daten");
}
});
});
router.get("/logout", (req,res,next) => {
if (req.session.user.userId) {
req.session.destroy();
res.redirect("/");
}
});
module.exports = router;
file.js
import express from "express";
import fs from "fs";
const router = express.Router();
const userDataPath = "/srv/www/www.precode.tech/www/userdata/";
router.get("/:userId", (req,res,next) => {
//console.log(req.params.userId == req.session.user.userId);
if (req.params.userId == req.session.user.userId) {
const userDataFiles = fs.readdirSync(userDataPath+req.session.user.userId);
res.render("file", {files : userDataFiles, user: req.session.user});
}
else{
res.status(403).render("unauthorized");
}
//res.send(`${req.params.userId} ${req.session.user.userId}`);
});
/*router.get("/:userId/download/:filename", (req,res,next) => {
console.log(req.params.filename);
if (req.params.userId == req.session.user.userId) {
let filePath = `${__dirname}/../userdata/${req.session.user.userId}/`;
res.download(filePath, req.params.filename);
next();
};
});*/
export default router;
download.js
import express from "express";
const router = express.Router();
/*router.get("/", (req,res,next) => {
res.send("download");
});*/
router.get("/:filename", (req,res,next) =>{
console.log(req.params.filename);
});
export default router;
It would be very nice, if you have ideas or see the problem.
Thank you :)
EDIT: It should not redirect to the base path of the user, the get request on download should allways console.log the item
I did not find the flaw, but let's cleanup the code and fix middleware attaching sequence (at least I saw cookie parser attached after session middleware, I suspect only that part) and check.
But let's check my code review / cleanup.
Really hope it helps.
app.js:
const express = require('express');
const path = require('path');
//const favicon = require('serve-favicon');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const session = require("express-session");
const mysql = require('mysql');
const db = mysql.createConnection({
host: "localhost",
user: "user",
password: "pass",
database: "db"
});
const app = express();
app.set("trust proxy", 1);
// set view engine and renderer
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// serve static files
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); // no need for it since express static will serve all static files in public folder
app.use(express.static(path.join(__dirname, 'public')));
// connect morgan to profile requests
app.use(logger('dev'));
// parse cookies first
app.use(cookieParser());
// then handle session
app.use(session({
secret: "bla",
resave: false,
cookie: {
maxAge: 120000000
},
saveUninitialized: true
}));
// handle requests data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use((req, res, next) => {
req.db = db; // attach db connection to request context
next();
});
// public routes that does not need auth check
app.use('/', require('./routes/index'));
const checkIfLoggedin = (req, res, next) => {
if (!req.session.loggedIn) {
return res.redirect('/');
}
res.locals.user = req.session.user;
next();
};
// internal routes that needs auth check
app.use(
'/admin',
checkIfLoggedin,
require('./routes/admin'));
app.use(
'/files',
checkIfLoggedin,
require('./routes/files'));
/* no need for this route, it's covered in files.js
app.use(
'/download',
checkIfLoggedin,
download);
*/
// catch 404 and forward to error handler
app.use((error, req, res, next) => {
if (error) return next(error);
const err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use((error, req, res, next) => {
// set locals, only providing error in development
res
.status(error.status || 500)
.render('error', {
message: error.message,
error: req.app.get('env') === 'development' ? error : {}
});
});
module.exports = app;
routes/index.js:
const express = require('express');
const router = express.Router();
const logger = require('winston');
const bcrypt = require('bcrypt-nodejs');
const _ = require('lodash'); // install it: npm i --save lodash
/* GET home page. */
router.get('/', (req, res) => {
if (_.get(req, 'session.user.userId')) {
return res.redirect("/files/" + req.session.user.userId);
}
res.render('index', {});
});
router.post('/auth', (req, res, next) => {
const {username, password} = req.body;
const db = req.db;
const query = 'SELECT * FROM users WHERE username = ? LIMIT 1';
const fields = [username];
db.query(
query,
fields,
(err, result) => {
if (err) {
logger.error(err);
const error = new Error('System fehler');
return next(error);
}
const user = _.get(result, '0');
if (!user) {
req.session.loggedIn = false;
const error = new Error('Benutzer nicht gefunden');
error.status = 403;
return next(error);
}
bcrypt.compare(password, user.password,
(err, isEqual) => {
if(err || !isEqual) {
if (err) logger.error('Error in password compare:', err);
const error = new Error('Passwort ungültig');
error.status = 403;
return next(error);
}
req.session.user = _.pick(user, ['id', 'userId', 'username', 'isAdmin']);
req.session.loggedIn = true;
if (user.isAdmin) {
return res.redirect("/admin");
}
res.redirect("/files/" + user.userId);
});
});
});
router.get("/logout", (req, res) => {
// simply destroy session and redirect,
// no need for session check
req.session.destroy();
res.redirect("/");
});
module.exports = router;
routes/files.js:
const express = require('express');
const router = express.Router();
const logger = require('winston');
const fs = require('fs');
const path = require('path');
const async = require('async');
const userDataPath = path.join(__dirname, '..', 'userdata');
// no need to check userId with session.user.userId
// since middleware attached in app.js will guard this route
// and redirect user to '/'
router.get('/:userId', (req, res, next) => {
if(req.params.userId != req.session.user.userId) {
const error = new Error("You cannot access other user's files");
error.status = 403;
return next(error);
}
const directory = path.join(userDataPath, req.params.userId);
logger.info('Reading directory:', directory);
fs.readdir(
directory,
(err, entries) => {
if (err) {
logger.error(err);
const error = new Error('System error');
return next(error);
}
const directories = [];
const files = [];
async.eachLimit(
entries, 10,
(entry, done) => {
fs.stat(path.join(dir, entry), (error, stat) => {
if (stat.isFile()) files.push(entry);
if (stat.isDirectory()) directories.push(entry);
done();
});
},
() => {
res.render("files", {
directories,
files
});
});
});
});
router.get('/:userId/download/:filename', (req, res, next) => {
if(req.params.userId != req.session.user.userId) {
const error = new Error("You cannot access other user's files");
error.status = 403;
return next(error);
}
res.download(path.join(userDataPath, req.params.userId, req.params.filename));
});
module.exports = router;
P.S. If it works behind nginx, apache and etc make sure userdata folder is not accessible publicly.
I'm trying to add user-login module to an existing app in node. It is using separate route files for each module and one main route file to use all the child routes which is ultimately used in server.js
When I try to pass passport instance to the user route, it gives me error as passport is not defined. Here is my app code and structure:
app
views
user
index.ejs
login.ejs
signup.ejs
profile.ejs
routes
docs
index.js
user
index.js
index.js
config
passport.js
server.js
server.js
const express = require('express')
const app = express()
const path = require('path')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
const passport = require('passport')
const flash = require('connect-flash')
const session = require('express-session')
const routes = require('./routes/')
const port = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, 'public')));
require('./config/passport')(passport);
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cookieParser());
app.use(bodyParser.json());
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(session({ secret: '********' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use('/', routes)(app,passport);
const server = app.listen(port, function(){
console.log('Server listening on port '+port);
});
config/passport.js
var LocalStrategy = require('passport-local').Strategy;
const sql = require('mssql')
const bcrypt = require('bcrypt-nodejs')
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function (username, done) {
done(null,username);
});
passport.use('local-signup', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
process.nextTick(function() {
var strSQL = "SELECT count(id) as uCount FROM <tbl> WHERE username = '"+email+"'";
var cb1 = function(err,recordset){
if(recordset[0].uCount>0){
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else{
var strSQL1 = "INSERT INTO <tbl>(username, password) VALUES('"+email+"','"+generateHash(password)+"')";
var cb2 = function(err,recordset){
return done(null, recordset,req.flash('signupMessage', 'Email registered successfully.'));
};
executeQuery(strSQL1,'INSERTION','<tbl>',cb2);
}
};
executeSelection(strSQL,'SELECTION','<tbl>',cb1);
});
}));
passport.use('local-login', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
var strSQL = "SELECT a.count, id, username, password FROM <tbl> c , (SELECT COUNT(dbid) count FROM <tbl> b WHERE b.username = '"+email+"' ) a WHERE c.username = '"+email+"'";
var cb1 = function(err,recordset){
if(recordset[0].uCount <= 0){
return done(null, false, req.flash('loginMessage', 'No user found.'));
}
if (!validPassword(password,recordset[0].password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
return done(null, recordset[0]);
};
executeSelection(strSQL,'SELECTION','<tbl>',cb1);
}));
};
executeSelection = function(strSQL, operationType, tableName, cb){
var request = new sql.Request(connection);
request.query(strSQL,function(err,recordset) {
if(err){
logger.error('ERROR in '+operationType+' ON '+tableName+': '+err);
}
logger.info(operationType+' ON '+tableName+' successful!');
cb(err,recordset);
});
};
executeQuery = function(strSQL, operationType, tableName, cb,validateClient) {
var request = new sql.Request(connection);
request.query(strSQL,function(err, recordset) {
if(err){
logger.error('ERROR in '+operationType+' ON '+tableName+': '+err);
}
logger.info(operationType+' ON '+tableName+' successful!');
if(cb){
cb(validateClient);
}
});
};
generatePasswordHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
validatePassword = function(curPass, dbPass) {
return bcrypt.compareSync(curPass, dbPass);
};
routes/index.js
const mainroute = require('express').Router()
/* ---- other existing routes included ---- */
const r_docs = require('./docs')
const r_user = require('./user') /*my custom route*/
/* ---- all other routes ---- */
mainroute.use('/docs', r_docs);
mainroute.use('/user', r_user)(app, passport); /*my custom route*/
mainroute.get('/', function(req, res){
res.render('home');
});
module.exports = function(app, passport){
mainroute;
}
routes/user/index.js
const express = require('express')
const router = express.Router()
router.get('/', function(req, res) {
res.render('user/index.ejs');
});
router.get('/login', function(req, res) {
res.render('user/login.ejs', { message: req.flash('loginMessage') });
});
// process the login form
router.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile',
failureRedirect : '/login',
failureFlash : true
}));
router.get('/signup', function(req, res) {
res.render('user/signup.ejs', { message: req.flash('signupMessage') });
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/profile',
failureRedirect : '/signup',
failureFlash : true
}));
router.get('/profile', isLoggedIn, function(req, res) {
res.render('user/profile.ejs', {
user : req.user
});
});
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
module.exports = function(app, passport) {
router;
}
Please suggest what am I doing wrong here. Thanks
You should wrap your main and user routes to run their logic when you call them and at end return prepared route:
routes/index.js
module.exports = function(app, passport) {
const mainroute = require('express').Router()
/* ---- other existing routes included ---- */
const r_docs = require('./docs');
const r_user = require('./user'); /*my custom route*/
/* ---- all other routes ---- */
mainroute.use('/docs', r_docs);
mainroute.use('/user', r_user)(app, passport); /*my custom route*/
mainroute.get('/', function(req, res) {
res.render('home');
});
return mainroute;
};
routes/user/index.js
module.exports = function(app, passport) {
const express = require('express');
const router = express.Router();
router.get('/', function(req, res) {
res.render('user/index.ejs');
});
router.get('/login', function(req, res) {
res.render('user/login.ejs', {
message: req.flash('loginMessage')
});
});
// process the login form
router.post('/login', passport.authenticate('local-login', {
successRedirect: '/profile',
failureRedirect: '/login',
failureFlash: true
}));
router.get('/signup', function(req, res) {
res.render('user/signup.ejs', {
message: req.flash('signupMessage')
});
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/profile',
failureRedirect: '/signup',
failureFlash: true
}));
router.get('/profile', isLoggedIn, function(req, res) {
res.render('user/profile.ejs', {
user: req.user
});
});
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
return router;
};
You need to require it at the top of your user/index.js. Simply:
var passport = require('passport');
Then to make sure the user is authenticated:
router.get('/some/path', isLoggedIn, function(req, res) {
var user = req.user;
});
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}