I would like to apologize in advance.
I'm not good at English. Also I'm not good at Node. Some "words" may be unsuited or wrong. I can not find any solutions in my language sphere. I'm writing this questions with GoogleTranslation's help.
MY EQUIPMENT
Ubuntu 16.04 local and virtualized on OSX
Node.js 8.11.4
Express 4.16.0
Passport 0.4.0
If you need more informations, I will answer.
MAIN QUESTION
I'm coding web application with two auth system. I want to auth these two auth work together at the same time.
My image is below.
Admin auth browser once. Then different users log-in and log-out. Without Admin, users can access limited page.
My code withdrown below.
var express = require("express");
var app = express();
var fs = require("fs");
var https = require("https");
var body_parser = require("body-parser");
var crypto = require("crypto");
app.use(body_parser.urlencoded({ extended: true }));
var admin_passport = require("passport");
var admin_passport_local = require("passport-local");
var admin_express_session = require("express-session");
app.use(admin_express_session({secret: 'admin_secret',resave: false,saveUninitialized: true, cookie: { secure: true }}));
app.use(admin_passport.initialize());
app.use(admin_passport.session());
var admin_LocalStrategy = admin_passport_local.Strategy;
admin_passport.use(new LocalStrategy({passReqToCallback: true,},
(req, username, password, done) => {
//not coding yes but not probrem
if(false){
return done("ERROR");
}else if(false){
return done(null, false);
}else if(true){
return done(null, username);
}
}
));
admin_passport.serializeUser(function(user, done) {
done(null, user);
});
admin_passport.deserializeUser(function(user, done) {
done(null, user);
});
function admin_isAuthenticated(req, res, next){
//here is probrem
if (req.isAuthenticated()) {
return next();
}
else {
res.redirect('/admin_login');
}
}
app.use((req,res,next)=>{
//here is probrem
app.locals.isAuthenticated = req.isAuthenticated();
next();
});
var user_passport = require("passport");
var user_passport_local = require("passport-local");
var user_express_session = require("express-session");
app.use(user_express_session({secret: 'user_ecret', resave: false,saveUninitialized: true, cokkie:{secure: true}}));
app.use(user_passport.initialize());
app.use(user_passport.session());
var user_LocalStrategy = user_passport_local.Strategy;
user_passport.use(new user_LocalStrategy({passReqToCallback: true,},
(req, username, password, done) => {
if(false){
return done("ERROR");
}else if(false){
return done(null, false);
}else if(true){
return done(null, username);
}
}
));
user_passport.serializeUser(function(user, done) {
done(null, user);
});
user_passport.deserializeUser(function(user, done) {
done(null, user);
});
function user_isAuthenticated(req, res, next){
if (req.isAuthenticated()) {
return next();
}
else {
res.redirect('/user_login');
}
}
app.use((req,res,next)=>{
app.locals.isAuthenticated = req.isAuthenticated();
next();
});
var ssl_options = {
key: fs.readFileSync('./cert/key.pem'),
cert: fs.readFileSync('./cert/cert.pem'),
};
var server = https.createServer(ssl_options, app);
app.get('/', (req, res) => {res.render('index', {});});
app.use('/admin_login', require('./admin_login'));
app.use('/admin_logout', (req, res) => {req.logout();res.redirect('./');})
app.use('/user_top', admin_isAuthenticated, require('./user_top'));
app.use('/user_login', admin_isAuthenticated,require('./user_login'));
app.use('/user_logout', (req, res) => {req.logout();res.redirect('./');})
server.listen(443);
and
var express = require('express');
var router = express.Router();
var passport = require('passport');
router.use((req, res, next) => {
next();
});
router.get('/', (req, res) => {
res.render('login',{});
});
router.post('/', passport.authenticate('local',{successRedirect: '/',failureRedirect: '/login',failureFlash: true,}),(req, res) =>{
});
module.exports = router;
I want to know how fix or change. If there are other way to solve this problem, welcome.
I would like to ask for cooperation.
Passport works only one login system?
req.login(), req.logout() req.Authenticated(), Passport-session ....
Many functions don't identify difference between two login system.
Related
I have a tremendous headche with a problem when I try to login using Passport.
I'm making a post request to /login with an email and password. Passport authenticates it correctly, err isn't called and then return res.redirect('/user') gets called too but it returns 404 and doesn't redirect.
I don't know why this is happening. Here's my code:
Server (index.js):
const
express = require('express'),
app = express(),
mongoose = require('mongoose'),
passport = require('passport'),
cookieSession = require('cookie-session'),
bodyParser = require('body-parser'),
keys = require('./config/keys'),
user = require('./models/User'),
passportService = require('./services/passport'),
authRoutes = require('./routes/auth');
mongoose.connect(keys.mongoURI);
app.use(bodyParser.json());
app.use(
cookieSession({
maxAge: 15 * 24 * 60 * 60 * 1000,
keys: [keys.cookieKey]
})
);
app.use(passport.initialize());
app.use(passport.session());
passportService(passport);
authRoutes(app);
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}`);
});
passportService (passport.js):
const LocalStrategy = require('passport-local').Strategy;
const mongoose = require('mongoose');
const User = mongoose.model('users');
module.exports = (passport) => {
passport.serializeUser((user, done) => {
done(null, user._id);
});
passport.deserializeUser((id, done) => {
User.findById(id).then(user => {
done(null, user);
});
});
passport.use(
new LocalStrategy(
{
usernameField: 'emailaddr',
passwordField: 'passwd'
},
function(username, password, done) {
User.findOne({ email: username }, function(err, user) {
if(err){
return done(err);
}
if(!user) {
console.log('User not found with email: ', username);
return done(null, false);
}
if(user.password != password) {
console.log('Invalid password');
return done(null, false)
}
return done(null, user);
});
}));
}
Authentication route:
const passport = require('passport');
module.exports = app => {
app.post('/api/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/user');
});
})(req, res, next);
});
}
There is not route for /user because I'm working with React and React Router in the client.
Please I need your help!!!
I would suggest not using the custom callback on your authenticate function. Instead, check to see if after the api is called and authentication is run if you have a user attached to the request object.
// calling redirects from your api will be problematic with react router
// allow your front end to decide what route to call based on the response
app.post('/api/login', passport.authenticate('local'), function(req, res, next) {
if(req.user) {
res.json(req.user);
} else {
// handle errors here, decide what you want to send back to your front end
// so that it knows the user wasn't found
res.statusCode = 503;
res.send({message: 'Not Found'})
}
});
When I try to run my code it gives me Reference Error: LocalStrategy is not defined.
This is my first time using node.js and I hit a wall with this. I appreciate the help in advance.
I put all the code in one snippet so you can go through it easily. I have tried other posts for fixes but have been unsuccessful.
/***********
Modules
***********/
//Load the express library
var express = require('express');
//Create a new variable called “app”; we pass on the express() method.
var app = express();
//Set Port
var port = 7878;
var mongoose = require('mongoose'); //Place this on top; Loads mongoose library
var bodyParser = require('body-parser');
var passport = require('passport');
var LocalStratgy = require('passport-local').Strategy;
/*Body parser*///whenever you do a post request from the form, it gets the data through a URL encoded format.
app.use(bodyParser.urlencoded({
extended: true
}));
app.use('/js', express.static(__dirname + '/js'));
/*Initialize Passport*/
app.use(passport.initialize());
app.use(passport.session());
/***********
Database
***********/
/*Database connection - MongoDB*/
//Created from the command earlier. Ensure this is done on the first_db instance
var usr = 'admin';
var pwd = '123456';
var dbHost = 'localhost';
var dbPort = '27017';
var database = 'first_db';
var url = 'mongodb://' + usr + ':' + pwd + '#' + dbHost + ':' + dbPort + '/' + database;
console.log('mongodb connection = ' + url);
mongoose.connect(url, function(err) {
if(err) {
console.log('connection error: ', err);
} else {
console.log('connection successful');
}
});
/***********
Models
***********/
//User model
//Define our fields for the table
var UserSchema = new mongoose.Schema({
user_id: mongoose.Schema.ObjectId,
username: String,
password: String
});
//Create model object
var User = mongoose.model('user', UserSchema);
/***********
Routes
***********/
var bcrypt = require('bcrypt-nodejs'); //should be placed on top
//Renders our html file
app.get('/', function (req, res, next) {
res.sendFile( __dirname + '/index.html');
});
//render register.html when /register is called
app.get('/register', function (req, res, next) {
res.sendFile( __dirname + '/register.html');
});
app.get('/home', function (req, res, next) {
res.sendFile(__dirname + '/home.html');
});
app.post('/login', passport.authenticate('local'),
function(req, res) {
res.redirect('/home');
});
/* Login logic for passport.authenticate*/
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if(user !== null) {
var isPasswordCorrect = bcrypt.compareSync(password, user.password);
if(isPasswordCorrect) {
console.log("Username and password correct!");
return done(null, user);
} else {
console.log("Password incorrect!");
return done(null, false);
}
} else {
console.log("Username does not exist!");
return done(null, false);
}
});
}
));
/**********
Serialize and Deserialize here for passport.authenticate
**********/
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(err, user);
});
app.post('/register', function (req, res, next) {
var password = bcrypt.hashSync(req.body.password);
req.body.password = password;
User.create(req.body, function(err, saved) {
if(err) {
console.log(err);
res.json({ message : err });
} else {
res.json({ message : "User successfully registered!"});
}
});
});
app.listen(port, '0.0.0.0', function() {
console.log('Server running at port ' + port);
});
The reason is you have defined var LocalStratgy, not LocalStrategy.
You're using it like this-
https://www.npmjs.com/package/passport-local-mongoose#configure-passportpassport-local
// use static authenticate method of model in LocalStrategy
passport.use(new LocalStrategy(User.authenticate()));
// use static serialize and deserialize of model for passport session support
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
But I suggest you to use it like this -
https://www.npmjs.com/package/passport-local-mongoose#simplified-passportpassport-local-configuration
// CHANGE: USE "createStrategy" INSTEAD OF "authenticate"
passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
var search = 1 + req.url.indexOf('?'); throws an error saying the statement to my left is undefined. Im using passportjs to create a login/registration page on my angular frontend. trying to make a post request to nodejs results in the above error. Im entirely new to the mean stack and ive tried several different tutorials to get myself up and running but have had some road blocks. can someone point in the right direction?
I've played around with just about every file moving around code and trying different solutions but nothing works, or one problem is solved but another occurs.
server.js
// set up ========================
var DATABASE = "mongodb://localhost:27017/smartHomeDevices";
var express = require("express");
var mongoose = require("mongoose"); //require monogDB Driver
var morgan = require("morgan"); // log requests to the console (express4)
var bodyParser = require("body-parser"); // pull information from HTML POST (express4)
var methodOverride = require("method-override"); // simulate DELETE and PUT (express4)
var passport = require("passport");
//var _ = require("lodash");
var http = require('http');
//setup
//app.models =
require("./Models/moduleIndex");
// Bring in the Passport config after model is defined
require('./config/passport');
//registering routes
var routes = require("./routes");
//Create App
var app = express();
app.use(passport.initialize());
//Add Middleware for REST API
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json);
app.use(bodyParser.json({
type: 'application/vnd.api+json'
}));
app.use(methodOverride("X-HTTP-Method-Override"));
app.use(morgan("dev"));
//CORS Support, makes API Public
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,");
res.header("Access-Control-Allow-Headers", "Content-Type,Authorization");
next();
});
app.use("/", routes);
// Connect to the db
mongoose.connect(DATABASE);
mongoose.connection.once("open", function() {
var serv = http.createServer(function(req, res) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
res.setHeader("Access-Control-Allow-Headers", "Content-Type,Authorization");
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end();
console.log(routes(req.method, req.url));
}).listen(3000);
//module.exports = app;
console.log("Listening on 3000");
});
routes.js
//setup
var express = require('express');
var router = express.Router();
var jwt = require('express-jwt');
var auth = jwt({
secret: 'MY_SECRET',
userProperty: 'payload'
});
var ctrlProfile = require('./Controllers/ProfileController');
var ctrlAuth = require('./Controllers/RegisterUserController');
// profile
router.get('/profile', auth, ctrlProfile.profileRead);
// authentication
router.post('/register', ctrlAuth.register);
router.post('/login', ctrlAuth.login);
module.exports = router;
/*module.exports = {
"/smartDevices" : require("./Controllers/SmartDeviceController"),
"/registeredUsers": require("./Controllers/RegisterUserController")
};*/
resgisteredUsersControllers.js
//setup
//var Resource = require("resourcejs");
var restful = require("node-restful");
var passport = require('passport');
var mongoose = require('mongoose');
var User = mongoose.model('registeredUserModel');
var sendJSONresponse = function(res, status, content) {
res.status(status);
res.json(content);
};
module.exports.register = function(req,res) {
console.log(req);
console.log("nw logging res");
console.log(res);
var user = new User();
user.name = req.body.name;
user.email = req.body.email;
user.username = req.body.username;
user.setPassword(req.body.password);
user.save(function(err) {
if(err)
console.log(err);
var token;
token = user.generateJwt();
res.status(200);
res.json({
"token" : token
});
});
next();
};
module.exports.login = function(req, res) {
passport.authenticate('local', function(err, user, info) {
var token;
// If Passport throws/catches an error
if (err) {
res.status(404).json(err);
return;
}
// If a user is found
if (user) {
token = user.generateJwt();
res.status(200);
res.json({
"token": token
});
} else {
// If user is not found
res.status(401).json(info);
}
})(req, res);
next();
};
/*module.exports = function(app, route) {
//setup controller for restful
// Resource(app,"",route,app.models.registeredUserModel).rest();
var rest = restful.model("registeredUserModel",
app.models.registeredUserModel
).methods(["get", "put", "post", "delete"]);
rest.register(app, route);
//return Middleware
return function(req, res, next) {
next();
};
};
*/
ProfileController.js
var mongoose = require('mongoose');
var User = mongoose.model('registeredUserModel');
module.exports.profileRead = function(req, res) {
// If no user ID exists in the JWT return a 401
if (!req.payload._id) {
res.status(401).json({
"message" : "UnauthorizedError: private profile"
});
} else {
// Otherwise continue
User
.findById(req.payload._id)
.exec(function(err, user) {
res.status(200).json(user);
});
}
};
Request object does not have url field.
I am trying to create passport-local sign-up functionality, but whenever I try to hit auth/signup API, I always redirect to failure path i.e. failureRedirect: '/auth/failure'.
The code seems fine to me.
app.js:
var passport = require('passport');
var api = require('./routes/api');
var authenticate = require('./routes/authenticate')(passport);
require('./models/models');
var mongoose = require('mongoose');
mongoose.connect("mongodb://localhost:27017/test-chirp");
var app = express();
app.use('/auth', authenticate);
//// Initialize Passport
var initPassport = require('./passport-init');
initPassport(passport);
authenticate.js:
var express = require('express');
var router = express.Router();
module.exports = function(passport){
//sends successful login state back to angular
router.get('/success', function(req, res){
res.send({state: 'success', user: req.user ? req.user : null});
});
//sends failure login state back to angular
router.get('/failure', function(req, res){
res.send({state: 'failure', user: null, message: "Invalid username or password"});
});
//sign up
router.post('/signup', passport.authenticate('signup', {
successRedirect: '/auth/success',
failureRedirect: '/auth/failure'
}));
return router;
}
passport-init.js:
var mongoose = require('mongoose');
var User = mongoose.model('User');
var LocalStrategy = require('passport-local').Strategy;
var bCrypt = require('bcrypt-nodejs');
module.exports = function (passport) {
passport.serializeUser(function (user, done) {
//return the unique id for the user
return done(null, user._id);
});
passport.deserializeUser(function (username, done) {
User.findById(id, function (err, user) {
if (err) { return done(err, false); }
if (!user) { return done('user not found', false); }
return done(user, true);
})
});
passport.use('signup', new LocalStrategy({
passReqToCallback: true
},
function (req, username, password, done) {
// find a user in mongo with provided username
User.findOne({ 'username': username }, function (err, user) {
if (err) {return done(err);}
// already exists
if (user) {return done(null, false);}
else {
// if there is no user, create the user
var newUser = new User();
// set the user's local credentials
newUser.username = username;
newUser.password = createHash(password);
// save the user
newUser.save(function (err) {
if (err) {throw err;}
console.log(newUser.username + ' Registration succesful');
return done(null, newUser);
});
}
});
})
);
var isValidPassword = function (user, password) {
return bCrypt.compareSync(password, user.password);
};
// Generates hash using bCrypt
var createHash = function (password) {
return bCrypt.hashSync(password, bCrypt.genSaltSync(10), null);
};
};
var app = express();
app.use('/auth', authenticate);
//// Initialize Passport
var initPassport = require('./passport-init');
initPassport(passport);
You are routing to the path /auth before initializing passport.
Try to switch :
var app = express();
//// Initialize Passport
var initPassport = require('./passport-init');
initPassport(passport);
app.use('/auth', authenticate);
So I'm following the following Egghead.io guide:
https://egghead.io/lessons/angularjs-finalizing-jwt-authentication-with-angularjs
With a twist, I am trying to incorporate a MongoDB to retrieve my users. I have everything working so far, except the last part where he states that the /me route should just return req.user and it should be fine on refreshes. I don't get that. What I do get is blank user returned from my server.
My server code is setup like this:
var jwtSecret = 'fjkdlsajfoew239053/3uk';
app.use(cors());
app.use(bodyParser.json());
app.use(expressJwt({ secret: jwtSecret }).unless({ path: [ '/login' ]}));
app.use(compression());
app.use(express.static(__dirname + '/client'));
app.get('/', function(req, res){
res.render(__dirname + '/client/bundle.js');
});
app.get('/me', function (req, res) {
res.send(req.user);
});
... setup for user schema and other boring stuff ...
function authenticate(req, res, next) {
var body = req.body;
if (!body.username || !body.password) {
res.status(400).end('Must provide username or password');
}
//do salting, hashing, etc here yo
User.findOne({ username: body.username }, function(err, user){
if (user === null || body.password !== user.password) {
res.status(401).end('Username or password incorrect');
}else{
req.user = user;
next();
}
});
}
// ROUTES
app.post('/login', authenticate, function (req, res, next) {
var token = jwt.sign({
username: req.user.username
}, jwtSecret);
res.send({
token: token,
user: req.user
});
});
app.listen(process.env.PORT || 5000);
And my controller (Client-side) handling the basic authentication is:
module.exports = function($scope, $state, $modal, UserFactory) {
var vm = this;
$scope.$state = $state;
$scope.sign_in = false;
$scope.open = function () {
var $modalInstance = $modal.open({
templateUrl: 'suggestion-modal.html',
controller: 'modalCtrl'
});
};
// initialization
UserFactory.getUser().then(function success(response) {
vm.user = response.data;
});
function login(username, password) {
UserFactory.login(username, password).then(function success(response) {
vm.user = response.data.user;
}, handleError);
}
function logout() {
UserFactory.logout();
vm.user = null;
}
function handleError(response) {
alert('Error: ' + response.data);
}
vm.login = login;
vm.logout = logout;
};
Can anyone catch the bug I'm not seeing here? Basically I have a JWT on the client when I'm logged in but my initialization on the client controller is not recognizing that I'm logged in (it's not setting the user object to anything). It's kinda strange.
So my solution ended up taking into account Kent's help and a little brainstorming. It looked like the following. Note, apparently middleware ordering in express matters a lot since after changing when Express-jwt got loaded made a huge difference in whether or not the authentication headers were checked on initial directory load on the client (which if they were angular wouldn't load and the whole app broke). Cheers!
'use strict';
var faker = require('faker');
var cors = require('cors');
var bodyParser = require('body-parser');
var jwt = require('jsonwebtoken');
var expressJwt = require('express-jwt');
var compression = require('compression');
var express = require('express');
var bcrypt = require('bcrypt');
var connectLiveReload = require('connect-livereload');
var jwt = require('jsonwebtoken');
var app = express();
var jwtSecret = 'fjkdlsajfoew239053/3uk';
app.use(cors());
app.use(bodyParser.json());
app.use(compression());
app.use(express.static(__dirname + '/client'));
// app.get('/', function(req, res){
// res.render(__dirname + '/client/bundle.js');
// });
app.use(expressJwt({ secret: jwtSecret }).unless({ path: ['/login']}));
app.get('/me', function (req, res) {
res.send(req.user);
});
...schema stuff...
// UTIL FUNCTIONS
function authenticate(req, res, next) {
var body = req.body;
if (!body.username || !body.password) {
res.status(400).end('Must provide username or password');
}
//do salting, hashing, etc here yo
User.findOne({ username: body.username }, function(err, user){
if (user === null || body.password !== user.password) {
res.status(401).end('Username or password incorrect');
}else{
req.user = user;
next();
}
});
}
// ROUTES
app.post('/login', authenticate, function (req, res, next) {
var token = jwt.sign({
username: req.body.username
}, jwtSecret);
res.send({
token: token,
user: req.user
});
});
// app.use(connectLiveReload()); figure out whats wrong with this later and get livereload working
app.listen(process.env.PORT || 5000);