I am creating online course application and I want only authenticated users to see the course details and course lecture. I am using local strategy of passport authentication for user authentication. I added isAuthenticated in my routes, however, still the unauthenticated users can view the video lectures.
Here is my routes file. file name:- courses.server.routes.js
'use strict';
/**
* Module dependencies
*/
var coursesPolicy = require('../policies/courses.server.policy'),
courses = require('../controllers/courses.server.controller');
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 the user to the login page
res.redirect('/');
};
module.exports = function (app) {
// Courses collection routes
app.route('/api/courses').all(coursesPolicy.isAllowed)
.get(courses.list)
.post(courses.create);
// Single course routes
app.route('/api/courses/:courseId', isAuthenticated).all(coursesPolicy.isAllowed)
.get(courses.read)
.put(courses.update)
.delete(courses.delete);
// Finish by binding the course middleware
app.param('courseId', courses.courseByID);
};
Here is my route controller file. file name:- courses.server.controller.js
'use strict';
/**
* Module dependencies
*/
var path = require('path'),
mongoose = require('mongoose'),
Course = mongoose.model('Course'),
errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller'));
var passport = require('passport');
/**
* Create an course
*/
exports.create = function (req, res) {
var course = new Course(req.body);
course.user = req.user;
course.save(function (err) {
if (err) {
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(course);
}
});
};
/**
* Show the current course
*/
exports.read = function (req, res) {
// convert mongoose document to JSON
var course = req.course ? req.course.toJSON() : {};
// Add a custom field to the Course, for determining if the current User is the "owner".
// NOTE: This field is NOT persisted to the database, since it doesn't exist in the Course model.
course.isCurrentUserOwner = !!(req.user && course.user && course.user._id.toString() === req.user._id.toString());
console.log('course value is: ' + course);
console.log('video lecture embed value is: ' + course.courseLecture.lecture_video);
res.json(course);
};
/**
* Update an course
*/
exports.update = function (req, res) {
var course = req.course;
course.title = req.body.title;
course.content = req.body.content;
course.courseLecture.lecture_video = req.body.courseLecture.lecture_video;
console.log('course lecture video url is: ' + req.body.courseLecture.lecture_video);
course.save(function (err) {
if (err) {
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(course);
}
});
};
/**
* Delete an course
*/
exports.delete = function (req, res) {
var course = req.course;
course.remove(function (err) {
if (err) {
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(course);
}
});
};
/**
* List of Courses
*/
exports.list = function (req, res) {
Course.find().sort('-created').populate('user', 'displayName').exec(function (err, courses) {
if (err) {
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(courses);
}
});
};
/**
* Course middleware
*/
exports.courseByID = function (req, res, next, id) {
if (!mongoose.Types.ObjectId.isValid(id)) {
return res.status(400).send({
message: 'Course is invalid'
});
}
Course.findById(id).populate('user', 'displayName').exec(function (err, course) {
if (err) {
return next(err);
} else if (!course) {
return res.status(404).send({
message: 'No course with that identifier has been found'
});
}
req.course = course;
next();
});
};
I'm not able to figure out, whats going wrong here.
Call isAuthenticated function from http verb means from get, post, patch, delete
like:
app.route('/api/courses/:courseId')
.get(isAuthenticated, courses.read)
also isAuthenticated can be write in another file and use it from your route
Can see this example
Related
I keep getting this error below after posting a form using expressjs and a dust template. The form is meant to redirect after posting.
The main error lies around the router.post section it seems the problem only occurs after I try to redirect using res.redirect.
VError: Problem rendering dust template "C:\Users\USER\Desktop\nodejs\Node-Bookstore\public\templates\manage\books\add.dust": The "path" argument must be of type string. Received an instance of Chunk
at Stub.callback (C:\Users\USER\Desktop\nodejs\Node-Bookstore\node_modules\adaro\lib\engine.js:167:30)
at Stub.flush (C:\Users\USER\Desktop\nodejs\Node-Bookstore\node_modules\dustjs-linkedin\lib\dust.js:564:14)
at Chunk.setError (C:\Users\USER\Desktop\nodejs\Node-Bookstore\node_modules\dustjs-linkedin\lib\dust.js:1051:15)
at C:\Users\USER\Desktop\nodejs\Node-Bookstore\node_modules\dust-usecontent-helper\index.js:25:27
at C:\Users\USER\Desktop\nodejs\Node-Bookstore\node_modules\dust-makara-helpers\index.js:50:21
at C:\Users\USER\Desktop\nodejs\Node-Bookstore\node_modules\iferr\index.js:13:50
at FSReqCallback.readFileAfterClose [as oncomplete] (internal/fs/read_file_context.js:63:3)
It only happens after res.redirect()
My code:
'use strict';
var Book = require('../models/bookmodel');
var Category = require('../models/categorymodel');
module.exports = function (router) {
router.get('/', function (req, res){
res.render('manage/index');
});
// Get Books
router.get('/books', function (req, res){
Book.find({},{}, function (err, books){
if (err){
console.log(err);
}
var model = {
books: books
}
res.render('manage/books/index', model);
});
});
// Get add book
router.get('/books/add', function (req, res){
Category.find({},{}, function (err, categories){
if (err){
console.log(err);
}
var model = {
categories: categories
}
console.log("before rendered manage/books/add");
res.render('manage/books/add', model);
});
});
//Post the details from the add books page!
router.post('/books', function (req, res){
var title = req.body.title && req.body.title.trim();
var category = req.body.category && req.body.category.trim();
var author = req.body.author && req.body.author.trim();
var publisher = req.body.publisher && req.body.publisher.trim();
var price = req.body.price && req.body.price.trim();
var description = req.body.description && req.body.description.trim();
var cover = req.body.cover && req.body.cover.trim();
if (title == '' || price == "") {
req.flash('error', 'Please input the price and title');
res.location('/manage/books/add');
res.redirect('/manage/books/add');
console.log("Empty title or price");
}
else if (isNaN(price)) {
req.flash('error', 'Price must be a number!');
res.location('/manage/books/add');
res.redirect('/manage/books/add');
console.log("price is NaN");
}else {
var newBook = new Book({
title: title,
category: category,
description: description,
author: author,
publisher: publisher,
cover: cover,
price: price,
});
newBook.save(function(err){
if (err){
console.log('save failed: ', err);
}
req.flash('success', 'New Book Added!');
res.location('/manage/books');
res.redirect('/manage/books');
console.log("was able to redirect");
});
}
});
router.get('/categories', function (req, res){
res.render('manage/categories/index');
});
};
Note: There is nothing wrong with the add.dust file
For some reason req.flash() was the issue here. Apparently I can't use the same syntax used in Jade with Dust
This will be added to the main index.js file in your root folder where you initialised the middel-ware for connect-flash
app.use(flash());
app.use(function (req, res, next) {
var messages = require('express-messages')(req, res);
res.locals.messages = function (chunk, context, bodies, params) {
return chunk.write(messages());
};
next();
});
Note that the messages function asks for (chunk, context, bodies, params) parameters and returns return chunk.write(messages());
Next:
Represent the message function with {#messages /} in your dust template
Hi am a beginner to Nodejs i have used passportjs token based authentication if the user logins it provides a token for each user i want to perform some operations based for the users who has token values for example if the user want to see the list of registered users they can view it if he has the token value. Now it provides me the token value perfectly in Postman but i don't know how to store it in a variable and call it via FRONT-END. I want do it via Front End(If he clicks the get users button) it should display the list of users.I have done that in POSTMAN it works finely i don't have an idea how to do it via frontend.
My user Code(Login/Logout)
var express = require('express');
var router = express.Router();
var User = require('../models/user');
var passport = require('passport');
var Verify = require('./verify');
/* GET users listing. */
router.route('/')
.get(Verify.verifyOrdinaryUser, function(req, res, next) {
User.find({}, function (err, users) {
if (err) throw err;
res.json(users);
});
});
router.post('/register', function(req, res, next) {
User.register(new User({ username : req.body.username }),req.body.password, function(err, user) {
if (err) {
return res.status(500).json({err: err});
}
user.save(function(err,user) {
passport.authenticate('local')(req, res, function () {
return res.status(200).json({status: 'Registration Successful!'});
});
});
});
});
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).json({
err: info
});
}
req.logIn(user, function(err) {
if (err) {
return res.status(500).json({
err: 'Could not log in user'
});
}
var token = Verify.getToken(user);
res.status(200).json({
status: 'Login successful!',
success: true,
token: token
});
});
})(req,res,next);
});
router.get('/logout', function(req, res) {
req.logout();
res.status(200).json({
status: 'Bye!'
});
});
module.exports = router;
Main.js File. In this main.js file i want to send that token in this get method any idea?
$(".get-users-button").click(function() {
$.ajax({
method: "GET",
url: " http://localhost:3000/users"
})
.done(function(msg) {
console.log(msg);
template(msg);
});
});
When you get back a successful response from the POST to your /login endpoint, store the token on client-side (e.g., window.localStorage.setItem('<your-namespace>-user-token', <the token goes here>);)
Then, when user clicks the 'get-users-button', get the token out of storage (e.g., window.localStorage.getItem('<your-namespace>-user-token'); and store it in a variable if you want.
Then, on your request to get users, add your { 'x-access-token': <token variable goes here> } to your request headers.
As per the documentation for Passport:
If authentication succeeds, the next handler will be invoked and the req.user property will be set to the authenticated user.
Now if I'm understanding your question correctly, you want to pass the token value you obtain from:
var token = Verify.getToken(user)
to the view in which your front-end can do something with. You can pass variables to the view using the following middleware:
app.use((req, res, next) => {
res.locals.token = Verify.getToken(req.user)
next()
}
See the documentation for res.locals for more details.
Example usage:
app.js
const express = require('express')
const app = express()
app.set('view engine', 'pug')
app.use((req, res, next) => {
res.locals.text = 'asdf'
res.locals.token = 'abc'
next()
})
app.get('/', (req, res) => {
res.render('index')
})
app.listen(3000, () => {
console.log('listening on 3000')
})
views/index.pug
doctype html
html
head
title= title
body
h1= text
script.
console.log('#{token}')
So i am new comer to keystone CMS and its looking awesome to me
i have setup the basic structure and using a default blog project provided by keystone so now i am trying to build the rest API for my admin
As the rest API working fine when i am loged in browser in keystone admin panel but when i am testing the same is postman even after setting the basic auth it giving me HTML page
I don't know what the wrong with that and how to setup this thing correctly.
Here is my code from index.js
var _ = require('underscore'),
keystone = require('keystone'),
middleware = require('./middleware'),
// restful = require('restful-keystone-onode')(keystone),
importRoutes = keystone.importer(__dirname);
// Common Middleware
keystone.pre('routes', middleware.initLocals);
keystone.pre('render', middleware.flashMessages);
// Import Route Controllers
var routes = {
views: importRoutes('./views'),
api: importRoutes('./api'),
};
// create a route that handles signin
function signin (req, res) {
if (!req.body.username || !req.body.password) return res.json({
success: false });
keystone.list('User').model.findOne({ email: req.body.username
}).exec(function (err, user) {
if (err || !user) {
return res.json({
success: false,
session: false,
message: (err && err.message ? err.message : false) || 'Sorry,
there was an issue signing you in, please try again.',
});
}
keystone.session.signin({ email: user.email, password:
req.body.password }, req, res, function (user) {
return res.json({
success: true,
session: true,
date: new Date().getTime(),
userId: user.id,
});
}, function (err) {
return res.json({
success: true,
session: false,
message: (err && err.message ? err.message : false) || 'Sorry,
there was an issue signing you in, please try again.',
});
});
});
}
// you'll want one for signout too
function signout (req, res) {
keystone.session.signout(req, res, function () {
res.json({ signedout: true });
});
}
// also create some middleware that checks the current user
// as long as you're using Keystone's session management, the user
// will already be loaded if there is a valid current session
function checkAuth (req, res, next) {
// you could check user permissions here too
if (req.user) return next();
return res.status(403).json({ error: 'no access' });
}
// Setup Route Bindings
exports = module.exports = function (app) {
// Views
app.get('/', routes.views.index);
app.get('/blog/:category?', routes.views.blog);
app.get('/blog/post/:post', routes.views.post);
app.get('/gallery', routes.views.gallery);
app.all('/contact', routes.views.contact);
// add an API endpoint for signing in _before_ your protected routes
app.post('/api/signin', signin);
app.post('/api/signout', signout);
// then bind that middleware in your routes before any paths
// that should be protected
app.all('/api*', checkAuth);
//
app.get('/api/post/list', keystone.middleware.api,
routes.api.posts.get);
app.get('/api/post/:id', keystone.middleware.api,
routes.api.posts.get);
};
and here is my route/api/post.js
/**
* Created by nikk on 11/5/17.
*/
var async = require('async'),
keystone = require('keystone');
var Post = keystone.list('Post');
/**
* List Posts
*/
exports.list = function(req, res) {
Post.Modal.find(function(err, items) {
if (err) return res.apiError('database error', err);
// res.apiResponse({
// posts: items
// });
res.json(items);
});
}
/**
* Get Post by ID
*/
exports.get = function(req, res) {
Post.model.findById(req.params.id).exec(function(err, item) {
if (err) return res.apiError('database error', err);
if (!item) return res.apiError('not found');
res.apiResponse({
post: item
});
// res.json(item);
});
}
I have been trying hard to get this thing done from last day but not able to do working till now
please guide me.
I want to create a custom middleware for passport-jwt to handle authentication.
here is what I have done to create my own middleware :
var models = require('../models');
var passport = require("passport");
var passportJWT = require("passport-jwt");
var config = require("../config/config.json");
var ExtractJwt = passportJWT.ExtractJwt;
var Strategy = passportJWT.Strategy;
var params = {
secretOrKey: config.jwtSecret,
jwtFromRequest: ExtractJwt.fromAuthHeader()
};
/**
* jwt authentication strategy
*/
var strategy = new Strategy(params, function(payload, done) {
models.User.findById(payload.id)
.then((user)=>{
if (user) {
return done(null, {
id: user.id,
username : user.username
});
} else {
return done(new Error("User not found"), false);
}
}).catch((err)=>{
return done(err, false);
});
});
passport.use(strategy);
module.exports = {
initialize: function() {
return passport.initialize();
},
authenticate: (req, res, next)=>{
passport.authenticate('jwt', { session: false }, (err, user, info)=>{
if (err) { return next(err); }
if (!user) { return res.send("Custom Unauthorised").end(); }
// edit as per comment
//return res.send("Test Route Accessed").end();
req.user = user; // Forward user information to the next middleware
next();
})(req, res, next);
}
};
but everytime I type 'npm start' to run the app I face this error :
if (request.headers[AUTH_HEADER]) {
^
TypeError: Cannot read property 'headers' of undefined.
the authorization header is set in the request.
yes I did Find the answer here it is :
first define the strategy logic:
var strategy = new Strategy(params, function (payload, done) {
//finding the user in the database
console.log(payload);
models.users.findById(parseInt(payload.userId))
.then((user) => {
//if the user is found
if (user) {
return done(null, {
id: user.id,
username: user.username
});
} else {
return done(new Error("User not found"), null);
}
}).catch((err) => {
console.log(err);
return done(new Error("uncaught error! try again later"), null);
})
});
then make passport use that strategy"
passport.use(strategy);
and finally export the initialization function and the middleware function
module.exports = {
initialize: function () {
return passport.initialize();
},
authenticate: function (req, res, next) {
return passport.authenticate("jwt", {
session: false
}, (err, user, info) => {
if (err) {
console.log(err);
return next(err);
}
if (!user) {
return res.json({
status: 'error',
error: 'ANOTHORIZED_USER'
});
}
// Forward user information to the next middleware
req.user = user;
next();
})(req, res, next);
}
};
and then you can call the function authenticate defined above as a middleware in your routes.
here is an example :
//import the express router
var express = require('express');
var router = express.Router();
//here I am importing the functions defined above, I put them in the config folder
var jwt_login_strategy = require('../config/jwt-login-strategy');
//and finally use the jwt_login_strategy as a middleware
router.post('something', jwt_login_strategy.authenticate, your_other_middleware(req, res, next)=>{...});
you have to call the authenticate function without adding parentheses, just like this jwt_login_strategy.authenticate.
hope it will solve your problem as it did for mine.
I am trying to inject a session value into the request so i can use it on different situation on my app. What i am doing is calling a function by giving the id to search for a user into database and return me the name of that specific user. The issue i am facing is when i try to declare the session, it looks like is not working or the callback is not letting this new value out.
Let me show you my code example for an better idea:
The middleware
var express = require('express');
var session = require('express-session');
var router = express.Router();
var userSession = require('../../helpers/user/userSession');
router.use(function(req, res, next){
if (req.method == "GET") {
if (!req.user) {
req.session.username = '';
}else{
var sess = userSession.findUser(req.user, function(err, user){
if (user) {
console.log(user); //It contains the value i need
req.session.username = user; // Supposed to inject the user value to the username session variable.
};
console.log(req.session.username); //it works until here, out of this function not anymore.
});
console.log(req.session.username); //the req.session.username is empty now
};
return next();
}else{
return next();
}
});
Check if user exist
var mongoose = require('mongoose');
var User = mongoose.model('database')
module.exports = {
findUser: function(user, callback){
User.findOne({ 'unq_id' : user }, function(err, user){
if (err) {
console.log('Error: ' +err);
return callback(err, false);
};
if (user) {
//console.log(user);
return callback(null, user.user_collection.firstname);
}else{
return callback(err, false);
};
});
}
}
One idea is to give to that sess variable the value of user, but it appears very difficult since is asynchronous call. I am sure some of might have run into this issue.
How can i get around this? any suggestion will be much appreciated.
How about this?
router.use(function(req, res, next){
if (req.method == "GET") {
if (!req.user) {
req.session.username = '';
next();
} else {
userSession.findUser(req.user, function(err, user){
if (user) {
req.session.username = user;
};
next();
});
}
} else {
next();
}
});
That way it won't go to the next middleware until after the username has been retrieved.