The session variable is created when user logs in to the system. Then I load session variable in my authorization code. I want to destroy that variable when user logs out. Here is some simplified code
store = new express.session.MemoryStore();
var parseCookie = express.cookieParser('secret');
app.use(parseCookie);
app.use(express.session({store: store, key:'sid'}));
app.post('/login', function(req,res){
var post = req.body;
if (post.user == 'hugo' && post.password == '123')
{
req.session.user_name = post.user;
res.redirect('/mypage');
}
else res.send('wrong user or pass');
});
io.set('authorization', function (data, callback) {
parseCookie(data, {}, function(prserr) {
var sess = (data.secureCookies && data.secureCookies['sid']);
store.load(sess, function(err, session){
if (err || !session ) { callback('not logged in', false); }
else {
data.session = session; // save session
callback(null, true);
}
});
});
});
and finally
app.get('/logout', function (req, res) {
req.session.destroy();
/* Here I want to destroy session variable that is declared in
authorization code (see above: data.session = session )*/
res.redirect('/');
});
while destroying session via req.session.destroy() the variable
socket.handshake.session.user_name still exists. I want to destroy it too. But I have no idea how to access desired variable in above mentioned place (in logout code).
Have you considered using Passport? It might be quicker (and more efficient) than trying to roll your own authentication solution.
Related
My NodeJS server, using express, has a bunch of entries to specify various routes:
app.post('list_streams.json', auth, stream_handler.list_streams);
app.post('add_stream.json', auth, stream_handler.add_stream);
app.post('delete_stream.json', auth, stream_handler.delete_stream);
etc...
The auth middleware is written like this:
var auth = express.basicAuth(function(user, pass, callback) {
user_handler.authenticate_user(user, pass, callback);
});
Inside the user_handler.authenticate_user() function, an access to the database is performed to validate the user. I'd like to add some statistics and keep track of every access that a particular user performs. I'd like to do this inside the authenticate_user() function, as this is where a database is accessed for the user record and I can use the same access to update the statistics info in the user record, but I need to somehow pass an extra argument to the authenticate_user() specifying the type of access that was performed; either the route itself or some token that identifies the route being accessed. And I can't figure out how to do this. The 'req' is not available inside the authenticate_user() function.
Thank You,
Gary
I'm not sure what you need can be easily done from your authenticate_user function since it's only called once per session at the first access from any user.
The best approach to log ALL access per user would be to create a new middleware function as described at the end of this post.
But assuming you only wish to log user authentications, one way to solve your problem would be to replace express.basicAuth with your own version that binds the callback function to the express req object, like this:
var util=require('util'),
express=require('express'),
app=express(),
auth=basicAuth(function(username,password,next){
console.log('auth has access to req as "this": %s',util.inspect(this));
});
app.get('/',auth,function(req,res){
console.log('in request for "/", req is: %s',util.inspect(req));
res.send('SUCCESS');
});
app.listen(4000,function(){
console.log('running');
});
// Replacement for connect.basicAuth (as used by express)
// lifted from https://github.com/expressjs/basic-auth-connect
function unauthorized(res, realm) { // required by basicAuth
res.statusCode = 401;
res.setHeader('WWW-Authenticate', 'Basic realm="' + realm + '"');
res.end('Unauthorized');
}
function error(code, msg){ // required by basicAuth
var err = new Error(msg || http.STATUS_CODES[code]);
err.status = code;
return err;
}
// replacement basic auth which binds the callback to the "req" object
function basicAuth(callback, realm) {
var username, password;
// user / pass strings
if ('string' == typeof callback) {
username = callback;
password = realm;
if ('string' != typeof password) throw new Error('password argument required');
realm = arguments[2];
callback = function(user, pass){
return user == username && pass == password;
}
}
realm = realm || 'Authorization Required';
return function(req, res, next) {
var authorization = req.headers.authorization;
// 20140601 RR - !!NOTE!! bind callback to req
callback=callback.bind(req);
if (req.user) return next();
if (!authorization) return unauthorized(res, realm);
var parts = authorization.split(' ');
if (parts.length !== 2) return next(error(400));
var scheme = parts[0]
, credentials = new Buffer(parts[1], 'base64').toString()
, index = credentials.indexOf(':');
if ('Basic' != scheme || index < 0) return next(error(400));
var user = credentials.slice(0, index)
, pass = credentials.slice(index + 1);
// async
if (callback.length >= 3) {
callback(user, pass, function(err, user){
if (err || !user) return unauthorized(res, realm);
req.user = req.remoteUser = user;
next();
});
// sync
} else {
if (callback(user, pass)) {
req.user = req.remoteUser = user;
next();
} else {
unauthorized(res, realm);
}
}
}
}
If you look at the line marked with "!!NOTE!!" above, you'll see that the callback you pass to the new basicAuth function has been bound to express' req request object, which makes its idea of this a reference to the request.
Now all you need to do is reference this.url to get the original request URL and log it.
As mentioned above, one thing to note is that the callback to auth is only called to authenticate the user once.
Subsequent requests already have the req.user HTTP header variable set, so the request is allowed to pass without calling the authentication callback.
This is why the best way to log all interactions for a particular user would be to add your own middleware after the call to auth, such as:
function logUser(req,res,next){
// since this middleware is called AFTER auth, the user is already authorized.
log.info('user "'+req.user+'" called url:'+req.url);
next(); // pass control to the next stage in fulfilling the request
}
app.get('/',auth,logUser,function(req,res){
...
});
How does connect's session work? I'm following this tutorial. I've noticed that even though i've commented out the session.save() call everything still works, that property still gets persisted to the session. Does Express automatically call session.save() every time a response is served up? If that's the case, what is the purpose of the save method?
var BaseController = require('./Base'),
View = require('../views/Base');
module.exports = BaseController.extend({
name: 'Admin',
username: 'dadams',
password: 'dadams',
run: function(req, res, next) {
if(this.authorize(req)) {
req.session.fastdelivery = true;
// req.session.save(function(err) {
var v = new View(res, 'admin');
v.render({
title: 'Administration',
content: 'Welcome to the control panel'
});
// });
} else {
var v = new View(res, 'admin-login');
v.render({
title: 'Please login'
});
}
},
authorize: function(req) {
return (
req.session &&
req.session.fastdelivery &&
req.session.fastdelivery === true
) || (
req.body &&
req.body.username === this.username &&
req.body.password === this.password
);
}
});
Connect’s session handling is automatic. Looking at the code, save gets called automatically on res.end (when your response is sent), so there’s no need to call it separately.
Consider it an implementation detail that’s exposed to you. I can’t think of many reasons why you would use it. Maybe if you are saving to Redis or a database and you want the session to be committed early for some reason, before calling end?
I am using session.socket.io in my node.js application. I am using this to manage my sessions in socket functions.
sessionSockets.on('connection', function (err, socket, session) {
session.save(); //here its working
socket.on('check_username',function(username) {
if(username in clients) {
socket.emit('error', 'Username not available');
} else {
clients[username] = session.id;
session.sockets.push(socket.id);
session = { 'username': username };
session.save();
socket.emit('success', 'Welcome to chat');
}
});
My problem is I can access and update session values before the check_username function but I can't access it with in the check_username function. I don't know how to resolve this...
I got the issue. The below line overwrites all previous values in session variable.
session = { 'username': username };
So then i have changed this line to below. Then its working
session.username - username;
I've got a working node app where I need to connect to different DBs based on what user is connecting to the app via basicAuth.
Here's a sample:
// Authenticating function
var sgAuth = express.basicAuth(function(user, pass, callback){
if(config.credentials.clients[user] === undefined) {
callback(null, false);
} else {
callback(null, config.credentials.clients[user].password == pass);
}
});
// This function needs to know what user has authenticated
function putEvents(req, res) {
//How do I know what user authenticated in this request?
var authUser = ???;
var table = getUserTable(authUser);
...
}
app.post('/put', sgAuth, putEvents);
Storing username in sgAuth to some var surely won't work, because there can be many incoming connections from different users, so you can't guarantee that its the same user, right? Can this info be retrieved from the request header somehow?
The basicAuth() middleware will set req.user and req.remoteUser once authorized.
Though, note that the 2nd argument to the callback is expected to be the user, not simply an authorized boolean. But, it can be any truthy value you desire, including the user name.
callback(null, config.credentials.clients[user].password == pass ? user : null);
After that, you should be able to retrieve it with:
var authUser = req.user;
Note that: basicAuth is deprecated
Here the code:
app.use(express.basicAuth(function(user, pass, callback){
if(config.credentials.clients[user] === undefined) {
callback('user not found!!!');
} else {
if(config.credentials.clients[user].password === pass) {
callback(null, config.credentials.clients[user]);
} else {
callback('wrong pass!!!');
}
}
});
app.post('/put', function putEvents(req, res) {
console.log(req.user.name)
res.end();
});
Can you please help me make a connection persistent script. I used jsftp node module to connect to ftp server. What I need to do is to check if the user is already authenticated every time he send a request. Thanks in advance! here's my code:
var Ftp = require('jsftp');
var dumpLog = function (event){
console.log('Code: '+ event.code);
console.log('Message: '+ event.text);
}
var FtpController = {
index : function (req , res) {
res.view('ftp/login');
},
auth : function (req , res){
// Initialize some common variables
var user = req.param('user');
var pass = req.param('pass');
var ftp = new Ftp({
host: req.param('host'),
port: req.param('port') // Defaults to 21
});
ftp.auth( user, pass, function (err , auth_res){
if (err) throw err;
dumpLog(auth_res);
});
res.view('ftp/folder');
},
serve_folder : function(req,res){
res.view('ftp/folder');
},
};
module.exports = FtpController;
Best way to do stuff like this is probably a policy, since you'll want to be able to apply the check to various controllers as you build out your app. Here's what your policy might look like:
// policies/ftpAuthenticated.js
module.exports = function loginToFTP (req, res, next) {
if (req.session.ftpAuthenticated) {
// Onward!
next();
}
else {
// authenticate here (we assume it works in this example)
var success = true;
if (success) {
// Track that the user is connected via ftp for next time
req.session.ftpAuthenticated = true;
// save the connection object
req.session.ftp = theFTPConnectionThing;
next();
}
// if an error occurs, use the default error handler
else {
next( new Error('Sorry, an error occurred authenticating with FTP') );
}
}
}