I am using mysql with nodejs. I am getting "Error: failed to serialize user into session". When I console.log user in serializeuser function it prints "serialize [object Object]" and in "local-login" strategy it prints RowDataPacket as shown below.
RowDataPacket {
Patient_id: 2,
fname: 'xxx',
mname: 'yyy',
lname: 'zzz',
Email: 'xxx#yyy.com',
pass: '$2b$10$ycZI4SLTJEihxKDHpCXwcOhkmBiOKzmMqFyuEOgXa0KuXYupgaMeG',
Contact: '090078601',
Gender: 'Male',
dateofbirth: 1111-01-13T19:31:48.000Z,
Blood_group: null
}
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
console.log(`serialize ${user}`)
done(null, user.patient_id)
})
// used to deserialize the user
passport.deserializeUser(function(id, done) {
// connection.connect()
connection.query("SELECT * FROM PATIENT WHERE PATIENT_ID = ? ",[id], function(err, rows){
done(err, rows[0])
})
// connection.end()
})
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) { // callback with email and password from our form
// connection.connect()
connection.query("SELECT * FROM PATIENT WHERE EMAIL = ?",[email],function(err,rows){
if (err)
return done(err)
if (!rows.length) {
return done(null, false, req.flash('error', 'No user found.')) // req.flash is the way to set flashdata using connect-flash
}
bcrypt.compare(password, rows[0].pass, function(err, result) {
if(!result)
{
return done(null, false, req.flash('error', 'Oops! Wrong password.'))
}
// console.log(rows[0])
});
return done(null, rows[0])
})
// connection.end()
}
))
my post login look like this
router.post('/patient/login', ensureGuest, passport.authenticate('local-login', {
successRedirect : '/home', // redirect to the secure profile section
failureRedirect : 'login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
})
);
don't suggest to use session:false while authenticating in post method
The type of object being returned by the sql query was causing the problem, serialize and deserialize accepts json object so I just added stringifyObjects option in my connection configs so that sql query returns json objects and not the default type of object which it usually returns.
module.exports = {
'connection': {
'host': 'localhost',
'user': 'root',
'password': 'fast',
'database': 'hms',
'stringifyObjects': 'Stringify'
}
};
Related
I am using nodejs and express to connect my local mysql db, everythings look working well except no response when Iam trying to test the API in postman.
here is my code in server.js
//add sales
app.post('/sales',(req, res) => {
var POST_SALES_QUERY = {
username: req.body.username,
password: req.body.password,
fullname: req.body.fullname
}
if (!POST_SALES_QUERY) {
return res.status(400).send({ err: true, message: 'Please username' });
}
dbConn.query("INSERT INTO user_tbl SET ?", (POST_SALES_QUERY, err, results) => {
if(err){
console.log(err);
} else {
return res.send(JSON.stringify({"status": 200, "err" : null, "response": results}));
}
});
});
and in Postman, I get this:
any idea what the problem appears here?
app.post('/sales',(req, res) => {
var POST_SALES_QUERY = {
username: req.body.username,
password: req.body.password,
fullname: req.body.fullname
}
if (!POST_SALES_QUERY) {
return res.status(400).send({ err: true, message: 'Please username' });
}
let query = `INSERT INTO user_tbl (username, password, fullname) VALUES ('${POST_SALES_QUERY.username}','${POST_SALES_QUERY.password}','${POST_SALES_QUERY.fullname}')`;
dbConn.query(query,function(err,results) {
if(err){
console.log(err);
} else {
return res.status(200).json({"status": 200,"err": null,"response": results});
}
});
});
You need to tell express to treat the body as json, by calling the following codes:
app.use(express.json())
As per the documentation:
This is a built-in middleware function in Express. It parses incoming requests with JSON payloads and is based on body-parser.
I'm basically trying to create a register page using MEAN and I want to check against the database (Mongo using Mongoose) if the user and email already exists, if one of them is true, send a res.json fail.
And if the username and email are not already in the database, continue to add the user.
I'm getting an error "Can't set headers after they are sent." On the Node console and I'm trying to figure out why.
Once User.getUsername() returns a user in the callback (if the username passed exists in the db), shouldn't it return the json and end the request there? Why is it continuing to the User.adduser() function and trying to set the header there too?
Any help is appreciated, thank you.
router.post('/register', (req, res, next) =>{
let newUser = new User({ // Collect body info
name: req.body.name,
email: req.body.email,
username: req.body.username,
password: req.body.password
});
// Check if username is available
User.getUserByUsername(newUser.username, (err, user) => {
if(err) throw err;
if(user){
return res.json({success: false, msg: 'User already exists'});
// I want to end here if there's a user
}
});
//Continue to add user if getUserByUsername() returns false for user
// Add user
User.addUser(newUser, (err, user) => { // Add user
if(err){
return res.json({success: false, msg: 'Failed to register'});
} else {
return res.json({success: true, msg: 'You have been successfully registered!'});
}
});
});
The logic you have doesn't work for as expected because of how asynchronous methods work. The current logic is do User.getUserByUsername then do User.addUser and if either method calls back, handle it. I'm pretty sure you want, do User.getUserByUsername, wait for it's callback, then call User.addUser if necessary. Here's a crude implementation, you could use promises or define the methods outside of the logic to clean it up. Also, make sure you are calling res.end() at some point in your code.
router.post('/register', (req, res, next) =>{
let newUser = new User({ // Collect body info
name: req.body.name,
email: req.body.email,
username: req.body.username,
password: req.body.password
});
// Check if username is available
User.getUserByUsername(newUser.username, (err, user) => {
if(err) throw err;
if(user){
return res.json({success: false, msg: 'User already exists'});
// I want to end here if there's a user
}else{
//Continue to add user if getUserByUsername() returns false for user
// Add user
User.addUser(newUser, (err, user) => { // Add user
if(err){
return res.json({success: false, msg: 'Failed to register'});
} else {
return res.json({success: true, msg: 'You have been successfully registered!'});
}
});
}
});
});
I am trying to build a user signup api using Passport, MySql, NodeJS and Sequelize. The only problem that i face is that when a user has signed up once and he tries to sign up again with the same email user is thrown a 401 Unauthorized Error instead of the user object. When i tried to debug the same the response that i was getting from the server was this
[object SequelizeInstance:users]. The files have been mentioned below. Thanks a tonnn in advance!!!.
Passport.js file:
var LocalStrategy = require('passport-local').Strategy;
var mysql = require('mysql');
var Model = require('../models/models.js');
// expose this function to our app using module.exports
module.exports = function(passport) {
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
connection.query("select * from users where id = " + id, function(err, rows) {
done(err, rows[0]);
});
});
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
Model.User.findOne({
where: {
email: email
}
}).then(function(user) {
if (user == null) {
Model.User.create({
email: email,
password: password
}).then(function(user) {
return done(null, user);
}).catch(function(err) {
return done(null, err);
});
} else {
return done(null, false);
}
})
}));
};
The Signup api:
router.post('/signup', passport.authenticate('local-signup'), function(req, res) {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
console.log(req.user);
if(req.user){
res.send({
success: true,
response: 'signup successful'
});
} else {
res.send({
success: false,
response: 'Email already in use'
});
}
});
The User model is:
//models/users.js
var Sequelize = require('sequelize')
var attributes = {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
},
created_by: {
type: Sequelize.INTEGER
}
}
var options = {
// Add the timestamps attributes (updatedAt, createdAt)
timestamps: true,
// don't delete database entries but set the newly added attribute deletedAt
// to the current date (when deletion was done). paranoid will only work if
// timestamps are enabled
paranoid: true,
// don't use camelcase for automatically added attributes but underscore style
// so updatedAt will be updated_at
underscored: true,
// disable the modification of table names; By default, sequelize will automatically
// transform all passed model names (first parameter of define) into plural.
// if you don't want that, set the following
freezeTableName: true,
// define the table's name
tableName: 'users'
}
module.exports.attributes = attributes
module.exports.options = options
The automated table creation model script is:
// models/models.js
var UserMeta = require('./users.js'),
connection = require('./index.js')
var User = connection.define('users', UserMeta.attributes, UserMeta.options)
// force: true will drop the table if it already exists
User.sync({
force: true,
match: /_servernew$/
}).then(function() {
// Table created
return User.create();
});
// you can define relationships here
module.exports.User = User;
So i came up with the solution. The following code needs to be changed.
router.post('/signup', function(req, res, next) {
passport.authenticate('local-signup', function(err, user, info) {
if(user){
req.logIn(user, function(err) {
if (err) {
return next(err);
} else {
res.send({
success: true,
response: 'signup successful'
});
}
});
}
if(!user){
res.send({
success: false,
response: 'Authentication Failed'
});
}
if(err){
res.send({
success: false,
response: 'Authentication failed'
})
}
})(req, res, next);
});
and the passport.js code should be like this.
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
Model.User.findOne({
where: {
email: email
}
}).then(function(user, err) {
console.log('I entered'+user);
console.log('I entered'+err);
if(err) {
console.log(err);
return done(null, false);
}
if(user == null) {
Model.User.create({
email: email,
password: password
}).then(function(user) {
return done(null, user);
}).catch(function(err) {
return done(null, err);
});
}
if(user){
return done(null, false);
}
})
}));
It will work just like a charm :D.
Am developing application using Nodejs with MySQL..
For login Authentication am using passportJS.
There are two login in this application one for admin and another one for customer. so seperate tables is there are USERS and REGISTERS.
passport.serializeUser(function(user, done) {
done(null, {
id : user.id,
isAdmin : user.isAdmin // or some other property/check
});
});
// used to deserialize the user
passport.deserializeUser(function(user, done) {
var table = user.isAdmin ? 'register' : 'users';
connection.query('select * from ?? where id = ?', [ table, user.id ], function(err, rows) {
if (err) {
return done(err);
} else if (! Array.isArray(rows) || ! rows.length) {
return done();
} else {
return done(null, rows[0]);
}
});
});
In deserializeuser if i logging In with customer id...its checking with user table for same id...so am getting wrong data
Question Updated:
Local-Login for Admin
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) { // callback with email and password from our form
connection.query("select * from users WHERE email = '" + email + "'",function(err,rows){
if (err)
return done(err);
if (!rows.length) {
return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash
}
// if the user is found but the password is wrong
if (!( rows[0].password == password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
// all is well, return successful user
return done(null, rows[0]);
});
}));
Customer-Login
passport.use('customer-login', new LocalStrategy({
usernameField : 'mobile',
passwordField : 'otp',
passReqToCallback : true
},
function(req, mobile, otp, done) {
connection.query("select * from register WHERE mobile = '" + mobile + "'",function(err,rows){
if (err)
return done(err);
if (!rows.length) {
return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash
}
// if the user is found but the password is wrong
if (!( rows[0].otp == otp))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
// all is well, return successful user
console.log(rows);
return done(null, rows[0]);
});
}));
For admin am using email as username for login
For customer am using mobile number for login
register
users
You don't have to serialize just the user id in serializeUser, it can also be an object that contains (for instance) the admin status (from your database contents, it looks like cust_code only exists for regular users, so we can use that to check if a user is an admin or not):
passport.serializeUser(function(user, done) {
done(null, {
id : user.id,
isAdmin : user.cust_code === undefined // this does require that `cust_code`
// is defined for all regular users.
});
});
This obviously assumes that the user document contains something that reflects if the user is an admin or not.
Using that object in deserializeUser you can determine which table to query:
passport.deserializeUser(function(user, done) {
var table = user.isAdmin ? 'users' : 'register';
connection.query('select * from ?? where id = ?', [ table, user.id ], function(err, rows) {
if (err) {
return done(err);
} else if (! Array.isArray(rows) || ! rows.length) {
return done();
} else {
return done(null, rows[0]);
}
});
});
I am trying to use passport js for authentication in my local mysql database. I am using postman extension to test the application.
I am sending two fields i.e. username and password for authentication. When any one of the field is blank then response is shown in json format as
{
"message": "Missing credentials",
"user": false
}
But when I pass values for both the fields I get 500 internal server error.
error: Sending 500 ("Server Error") response:
TypeError: Cannot read property 'message' of undefined
at d:\Test\api\controllers\AuthController.js:25:23
at Strategy.strategy.error (d:\Test\node_modules\passport\lib\middleware\authenticate.js:333:18)
at Strategy.authenticate (d:\Test\node_modules\passport-local\lib\strategy.js:94:17)
at attempt (d:\Test\node_modules\passport\lib\middleware\authenticate.js:341:16)
at authenticate (d:\Test\node_modules\passport\lib\middleware\authenticate.js:342:7)
at Object.module.exports.login (d:\Test\api\controllers\AuthController.js:37:7)
at bound (C:\Users*\AppData\Roaming\npm\node_modules\sails\node_modules\lodash\dist\lodash.js:729:21)
at routeTargetFnWrapper (C:\Users*\AppData\Roaming\npm\node_modules\sails\lib\router\bind.js:179:5)
at callbacks (C:\Users*\AppData\Roaming\npm\node_modules\sails\node_modules\express\lib\router\index.js:164:37)
at param (C:\Users*\AppData\Roaming\npm\node_modules\sails\node_modules\express\lib\router\index.js:138:11)
at pass (C:\Users*\AppData\Roaming\npm\node_modules\sails\node_modules\express\lib\router\index.js:145:5)
at nextRoute (C:\Users*\AppData\Roaming\npm\node_modules\sails\node_modules\express\lib\router\index.js:100:7)
at callbacks (C:\Users*\AppData\Roaming\npm\node_modules\sails\node_modules\express\lib\router\index.js:167:11)
at C:\Users*\AppData\Roaming\npm\node_modules\sails\lib\router\bind.js:187:7
at alwaysAllow (C:\Users*\AppData\Roaming\npm\node_modules\sails\lib\hooks\policies\index.js:207:11)
at routeTargetFnWrapper (C:\Users*\AppData\Roaming\npm\node_modules\sails\lib\router\bind.js:179:5) [TypeError: Cannot read property 'message' of undefined]**
Below is my AuthController
var passport=require('passport');
login:function(req,res){
passport.authenticate('local', function(err, user, info) {
if ((err) || (!user)) {
return res.send({
message:info.message,
user: user
});
}
req.logIn(user, function(err) {
if (err) res.send(err);
return res.send({
message:"User Loged In",//info.message,
user: user
});
});
})(req, res);
}
};
I am using the below model for testing
module.exports = {
tableName: 'users',
connection:'TestDB',
autoCreatedAt:false,
autoUpdatedAt:false,
attributes: {
username:{
type:'string',
required:true
},
password:{
type:'string',
required:true
},
toJSON: function() {
var obj = this.toObject();
delete obj.password;
return obj;
}
}
};
The table which contains the username and password also has other fields like country. Is there any way I can authenticate it using passport.
did you do the sixth step of this link
module.exports.http = {
middleware: {
passportInit : require('passport').initialize(),
passportSession : require('passport').session(),
order: [
'startRequestTimer',
'cookieParser',
'session',
'passportInit',
'passportSession',
'myRequestLogger',
'bodyParser',
'handleBodyParserError',
'compress',
'methodOverride',
'poweredBy',
'router',
'www',
'favicon',
'404',
'500'
],
}
};
maybe you want to see sails-hook-sanpassport, is easy and fast