I have a simple server application running with NodeJS, and I tried to implement the route protecting that is in this tutorial, I already have the token that works every time I login.
So this middleware should be called to all routes except register and login. So I did this in my initial setup:
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 debug = require('debug')('express-sequelize');
var http = require('http');
var models = require('./models');
var jwt = require('jsonwebtoken');
var jwtPermission = require('./controller/jwtPermission');
var fotos = require('./routes/fotos');
var app = express();
var router = express.Router();
// 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('/',require('./routes/index'));
app.use(jwtPermission);
app.use('/fotos',fotos);
The middleware that doesn't get called is jwtPermission. So I have a routes folder where I have a index, and the authentication file(that has login and register). For the jwtPermission I just have the controller set as you guys can see.
I have a console.log inside that controller but it never gets called.
jwtPermission
var jwt = require('jsonwebtoken');
var jwtConfig = require('../config/jwt');
module.exports = function(req, res, next) {
console.log("entered");
// check header or url parameters or post parameters for token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
console.log(req.headers['x-access-token']);
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token,jwtConfig.secret, function (err, decoded) {
if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
}
You configure your routes in the Route object, but you have to attach it in your app object.
So, in this case, change route.use to app.use.
Don't need to use the route object.
Related
I've got a basic Node JS app (as I'm just learning). I'm using express, express-generator, express-myconnection, and mysql.
The issue has to do with querying the database connection itself.
The app is designed using an MVC structure.
Edit: to start off, here is my "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');
//var users = require('./routes/users');
var app = express();
var connection = require('express-myconnection');
var mysql = require('mysql');
app.use(
connection(mysql,{
"host":"localhost",
"user":"root",
"password":"root",
"port":3306,
"database":"fruits"
},'request')
);
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// 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('/', index);
// 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;
I have a model file, "fruits.js":
var fruits = function(data, req){
this.data = data;
this.req = req;
}
fruits.prototype.data = {};
fruits.prototype.getAll = function(callback){
this.req.getConnection(function(err, connection){
console.log(connection);
//var q = connection.query("SELECT * FROM `fruits`", function(err, rows){
//callback(rows);
//});
});
};
module.exports = fruits;
Then I also have a controller file (index.js):
var express = require('express');
var router = express.Router();
var fruits = require('../models/fruits.js');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
/*GET fruits page */
router.get('/fruits',function(req, res, next){
var f = new fruits({}, req);
f.getAll(function(fruitsObj){
console.log(fruitsObj);
res.render('fruits',{
"title":"Fruits!",
"fruits":fruitsObj
});
});
});
module.exports = router;
What happens is whenever the fruits route is navigated to, I can't query the database. It says that the "connection" from "this.req.getConnection" is "undefined".
Is there any reason why I can't retrieve the database connection and query it based on the contents of these two files? I'm positive I have all my packages installed. I even ran npm install for all them again to make sure.
Thanks for your help in advance.
I'm setting up a Token based authentication using express-jwt but the middleware which sends an error message if the token is missing or invalid is not working.
index.js file
const express = require('express');
const router = express.Router();
const {getAllUsers: findUser} = require('../controllers/users');
const {register: registerUser, login: loginUser} = require('../controllers/authentication');
const jwt = require('express-jwt');
const auth = jwt({
secret: process.env.JWT_SECRET,
userProperty: 'auth'
});
// users
router
.route('/users', auth)
.get(findUser);
// registration
router
.route('/register')
.post(registerUser);
// login
router
.route('/login',auth)
.post(loginUser);
module.exports = router;
Users Controller:
const mongoose = require('mongoose');
const User = mongoose.model('Users');
let getAllUsers = (req,res) => {
User.find((err,user)=>{
if(user){
res
.status(200)
.json({user})
}
});
};
module.exports = {
getAllUsers
};
app.js file:
require('dotenv').load();
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 passport = require('passport');
require('./app_api/models/db');
require('./app_api/config/passport');
const index = require('./app_server/routes/index');
const apiRoutes = require('./app_api/routes/index');
const app = express();
// view engine setup
app.set('views', path.join(__dirname, 'app_server','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(passport.initialize());
app.use('/', index);
app.use('/api', apiRoutes);
//error handlers
// catch unauthorised errors
app.use(function (err, req, res, next) {
if (err.name === 'UnauthorizedError') {
res.status(401).send('invalid token...');
}
});
// catch 404 and forward to error handler
app.use(function(req, res, next) {
const 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;
I am setting the middleware on users route which returns a list of all users. But only authorized users should be able to access that list.
The middleware does not seem to be working as I can still get the users list even if I do not send a token.
What am I doing wrong?
Please Note: Im using POSTMAN to test this.
Update (Figured out the problem):
It was a very simple fix can't believe I didn't see it before. The issue was where I was placing auth.
I was placing it after the route url like so:
router
.route('/users', auth)
.get(findUser);
When the correct way of doing this is:
router
.route('/users')
.get(auth, findUser);
The above fixed my issue.
According to README in the repository, you should check if user property is present in the request.
The JWT authentication middleware authenticates callers using a JWT.
If the token is valid, req.user will be set with the JSON object
decoded to be used by later middleware for authorization and access
control.
Your findUser function should handle it
function findUser(req, res) {
if (!req.user) return res.sendStatus(401);
// do something else
}
You might also consider changing userProperty to requestProperty.
app.js
var express = require("express");
var app = express();
var path = require('path');
var db = require('./db');
var bodyParser = require('body-parser');
app.listen(80);
app.set('view engine', 'jade');
app.set('views', "./views");
// app.get('/', _GetMainPage);
// app.get('/sites', _GetSites);
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.urlencoded({ extended: true })); // Support encoded bodies
app.use(bodyParser.json()); // Support json encoded bodies
app.use(require('./controllers'));
./controllers/index.js
var express = require('express');
var router = express.Router();
router.use('/', require('./sites'));
router.use('/site', require('./site'));
module.exports = router;
./controllers/sites.js
var express = require('express');
var router = express.Router();
var site = require('../models/site');
router.get('/', function(req, res) {
site.getAll(function(err, rows){
if(err) {
res.send(err);
return;
}
res.render('sites', { sites : rows });
});
});
./controllers/site.js
var express = require('express');
var router = express.Router();
var site = require('../models/site');
router.get('/site', function(req, res) {
// console.log("get /site received. req.body: " + req.body);
res.render('site', {
site: {
name : req.params.name
}
});
});
module.exports = router;
When I request localhost/site I get a response saying:
Cannot GET /site
localhost/ works perfectly
I have been looking at this for a while and can't find the problem yet. If there is anything I can add, let me know. Thanks.
Thank you to the person that commented with the answer:
What happens if you navigate to /site/site? Your site.js route is relative to the route you provided in use. So it should be router.get('/' ... not router.get('/site' ...
The ./controllers/site route is already being routed to /site. On top of this I was calling router.get('/site', ...). This means it was actually routing to /site/site.
The solution is to just use router.get('/', ...) in the site.js file instead.
This really helped me, thank you.
Basically, the root path in the sub-app is defined in your core app where you mount it via the app.use() method.
the best example I can find from app.mountpath docs is here:
https://expressjs.com/en/4x/api.html#express.router
The app.mountpath property contains one or more path patterns on which a sub-app was mounted.
var express = require('express');
var app = express(); // the main app
var admin = express(); // the sub app
admin.get('/', function (req, res) {
console.log(admin.mountpath); // /admin
res.send('Admin Homepage');
});
app.use('/admin', admin); // mount the sub app
It is similar to the baseUrl property of the req object, except
req.baseUrl returns the matched URL path, instead of the matched
patterns.
If a sub-app is mounted on multiple path patterns, app.mountpath
returns the list of patterns it is mounted on, as shown in the
following example.
var admin = express();
admin.get('/', function (req, res) {
console.log(admin.mountpath); // [ '/adm*n', '/manager' ]
res.send('Admin Homepage');
});
var secret = express();
secret.get('/', function (req, res) {
console.log(secret.mountpath); // /secr*t
res.send('Admin Secret');
});
admin.use('/secr*t', secret); // load the 'secret' router on '/secr*t', on the 'admin' sub app
app.use(['/adm*n', '/manager'], admin); // load the 'admin' router on '/adm*n' and '/manager', on the parent app
I'm trying to access session variables in EJS views, but facing lots of problems.
To access the req.session locally I'm using middleware as described here Accessing Express.js req or session from Jade template
var express = require('express');
var mongoose = require('mongoose');
var db = require('./models/db.js');
var routes = require('./routes/route.js');
var user = require('./routes/user.js');
var story = require('./routes/story.js');
var bodyParser = require('body-parser');
var session = require('express-session');
var cookieParser = require('cookie-parser');
mongoose.connect('mongodb://localhost/test');
var app = express();
app.use(function(req,res,next){
res.locals.session = req.session;
next();
});
app.set('view engine','ejs');
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:false}));
app.use(cookieParser());
app.use(session({secret:"qazwsxedcrfvtgbyhnujm"}));
app.get('/',routes.home);
app.get('/register',routes.register);
app.post('/newUser',user.doCreate);
app.get('/login',routes.login);
app.post('/authenticate',user.login);
app.get('/new-story',routes.newStory);
app.post('/add-story',story.addStory);
app.get('/stories/:story',story.getStory);
app.post('/stories/:slug/saveComment',story.saveComment);
var port = process.env.PORT || 3000;
var server=app.listen(port,function(req,res){
console.log("Catch the action at http://localhost:"+port);
});
Here is the route.js for handling home route
var mongoose = require( 'mongoose' );
var Story = mongoose.model( 'Story' );
exports.home=function(req,res){
Story.find({}, function(err,stories){
res.render('home',{stories:stories});
});
}
In the home.ejs I am checking whether user is logged in or note by checking whether username property is set or not.
<% if( typeof(session.username) !== 'undefined' ) {%
<h1>Welcome</h1><%=session.username%>
<%}%>
But, on accessing the main page I get error saying
Cannot read property 'username' of undefined error
I am setting the username in session once is user is authenticated.
exports.login=function(req,res){
var email=req.body.email;
var password=req.body.password;
User.findOne({email:email}, function(err,user){
if(err){
res.redirect("/login");
}
user.comparePassword(password,function(err,isMatch){
if(isMatch && isMatch==true){
console.log("Authentication Sucessfull");
req.session.username=user.username;
console.log("Got USer : "+req.session.username);
res.redirect("/");
}else{
console.log("Authentication UnSucessfull");
res.redirect("/login");
}
});
});
}
Express runs middleware in order of their declaration.
You have this:
app.use(function(req,res,next){
res.locals.session = req.session;
next();
});
...
app.use(session({secret:"qazwsxedcrfvtgbyhnujm"}));
Your middleware runs before the session middleware (it's declared before it), so you create res.locals.session before the session middleware gets a chance to create req.session.
Try moving your middleware to after the session middleware:
app.use(session({secret:"qazwsxedcrfvtgbyhnujm"}));
app.use(function(req,res,next){
res.locals.session = req.session;
next();
});
I am learning how to build a web app using express, node, and angular. I have a post request from angular, and I can successfully send that to the router in login.js:
var user = {username: $scope.userName, password: $scope.password};
$scope.login = function() {
console.log('attempting to log in,,');
console.log("The useranem" + $scope.userName + " " + $scope.password + " " + user);
$http.post('/userLogin', user).then(successCallback, errorCallback);
};
index.js
var express = require('express');
var router = express.Router();
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'xxxxx',
database : 'xxxxx'
});
connection.connect();
router.post('/userLogin', function(req, res, next){
console.log('the user name is ' + req.body);
});
module.exports = router;
From the image, I can see that I was able to print out the body of the post request as objects. Is this because I don't have body parser in index.js.
I already installed body parser in app.js,
1) do I have to require app.js in index.js to use the body parser?
2)And once I am able to parse the body, how do I access the varaibles in the body. Would it be req.username and req.password?
3) This question is not as related, but in my app.js I have app.use('/', login). How do i determine what the path should be? Should it be the same as the express router such as /userLogin?
This is my 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 mysql = require('mysql');
var routes = require('./routes/index');
var register = require('./routes/register');
var users = require('./routes/users');
var login = require('./routes/login');
var app = express();
//establish database connection
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'xxxxx',
database : 'xxxxx'
});
connection.connect();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
app.use('/', login);
//add route for registering account
// 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 handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
Note: most of the stuff in app.js was created using express generator.
Looks like you need to access the data from req.body that you want. So if the object you want to access from that is user from the json object you'd need to access req.body.user
You are trying to concatenate an object with a string. This forces the standard output to call the method toString() from the object which results in [object Object] if it's not overridden with a custom implementation.
To see the whole object, you can use: console.log(req.body);
then you will be able to see the object.