Skip to main content

Epress authen, routing, middleware ...

https://stackoverflow.com/questions/11784233/using-passportjs-how-does-one-pass-additional-form-fields-to-the-local-authenti
https://blog.risingstack.com/node-hero-node-js-authentication-passport-js/
https://www.owasp.org/index.php/Session_Management_Cheat_Sheet
https://stackoverflow.com/questions/10306185/nodejs-best-way-to-pass-common-variables-into-separate-modules
https://www.npmjs.com/package/express-passport-session-tracker
https://stackoverflow.com/questions/16800418/how-to-properly-pass-mysql-connection-to-routes-with-express-js
https://scotch.io/tutorials/easy-node-authentication-setup-and-local
https://scotch.io/bar-talk/the-ins-and-outs-of-token-based-authentication
https://scotch.io/tutorials/the-anatomy-of-a-json-web-token
https://jonathanmh.com/express-passport-json-web-token-jwt-authentication-beginners/


https://github.com/jaredhanson/passport/blob/master/lib/strategies/session.js
https://stackoverflow.com/questions/2015232/database-design-for-audit-logging
https://stackoverflow.com/questions/26040329/how-do-you-handle-api-version-in-a-node-express-app
https://github.com/expressjs/session
https://news.ycombinator.com/item?id=11929267

https://stackoverflow.com/questions/14464873/expressjs-session-expiring-despite-activity
http://openmymind.net/2012/2/3/Node-Require-and-Exports/
https://github.com/expressjs/cookie-session
https://stackoverflow.com/questions/28789857/how-is-the-express-req-session-object-persisted
https://stackoverflow.com/questions/21939568/javascript-modules-prototype-vs-export

https://stackoverflow.com/questions/20534702/node-js-use-of-module-exports-as-a-constructor




There's an overall session data structure that stores all session info (like a global, but it could also be in a database - just something that is persistent at least across connections). Each client's session data uses one unique key to index into the session store to get the session data for that client.
Part of establishing a session for a given browser client is creating a unique client key (which will usually be stored in a cookie) that becomes the index into the global session object.
On an incoming http request, Express middleware that supports the session checks a particular client cookie and if that particular cookie is found on the http request and is found in the global session object/database, then it adds that session's stored info to the request object for the http request handler to later use.
So, here's a typical sequence:

  1. Incoming HTTP request.
  2. Middleware checks for session cookie.
  3. If session cookie not there, then create one and, in the process created a unique id to identify this http client.
  4. In the persistent session store, initialize the session for this new client.
  5. If session cookie is there, then look in the session store for the session data for this client and add that data to the request object.
  6. End of session middleware processing
  7. Later on in the Express processing of this http request, it gets to a matching request handler. The session data from the session store for this particular http client is already attached to the request object and available for the request handler to use.

+---------------------+----------------------+
| last_web_activity   | last_activity        |
+---------------------+----------------------+
| 2017-09-13 11:13:25 | 2017-09-13 04:17:57  |
| 2017-09-13 08:00:54 | 2017-09-13 08:14:50  |
| 2017-09-13 08:28:18 | 2017/9/13 @ 8:19:43  |
| 2017-09-13 08:22:38 | 2017-09-13 08:20:52  |
| 2017-09-13 07:27:11 | 2017-09-13 07:31:44  |
| NULL                | 2017/9/13 @ 7:8:41   |

| NULL                | NULL                 |


getTime is not a function().


That's because your dat1 and dat2 variables are just strings.
You should parse them to get a Date object, for that format I always use the following function:
// parse a date in yyyy-mm-dd format
function parseDate(input) {
  var parts = input.match(/(\d+)/g);
  // new Date(year, month [, date [, hours[, minutes[, seconds[, ms]]]]])
  return new Date(parts[0], parts[1]-1, parts[2]); // months are 0-based
}
I use this function because the Date.parse(string) (or new Date(string)) method is implementation dependent, and the yyyy-MM-dd format will work on modern browser but not on IE, so I prefer doing it manually.

Z stands for the timezone UTC and is defined in ISO-8601, which is your desired output format, extended by the millisecond part.

When a user record fetch from DB it convert datetime value to object type or JS format. (I saw this but not sure).
When I log user by console.log(user):
updated_at: 2017-09-11T05:44:47.000Z, last_activity: 2017-09-13T08:27:38.000Z, last_web_activity: 2017-09-11T11:34:35.000Z, last_admin_activity: null,
....

We can see that Datetime has been converted to JS format not MySQL (I use MySQL).
So when we call user.last_activity.getTime() it return unix time * miliseconds. Event datetime in MySQL that format is strange, ie: 2017/9/13 @ 7:8:41 it still work.
So the timestamp above will log in console of user object as 1505286521000. We can decode this date by type date command in bash/terminal: (remove milisecond '000')
date -d @1505286521 Wed Sep 13 07:08:41 UTC 2017

https://stackoverflow.com/questions/23571110/nodejs-responded-mysql-timezone-is-different-when-i-fetch-directly-from-mysql

last_activity varchar(255) :( :(:(:(:(:(:((:

This is  it.

Æ ASP thank a ton!

Expire and Max-Age Attributes
Session management mechanisms based on cookies can make use of two types of cookies, non-persistent (or session) cookies, and persistent cookies.
When close tab/browser, app (ionic) if use non-persistence cookie then it lost. So it may be reason why session lost radomly (mostly lost).


Update 1 18-Sept-17:

https://stackoverflow.com/questions/15016551/node-js-express-passport-cookie-expiration

As this post, do not use expires, use maxAge instead.

The cause of that was here:
cookie: { expires : new Date(Date.now() + 3600000) }

The new Date was being created only once, upon server start. That was causing the expiration date to be the same every time.

But in my app I see that the expire date is changing and update not just run one time at start.
So this do not like my problem with session timeout.
My problem is that only Ionic app suffer this issue and not all the time (:( ) , some account may work well but some are not.
As described in OSWAP  Expire and Max-Age Attributes:
Session management mechanisms based on cookies can make use of two types of cookies, non-persistent (or session) cookies, and persistent cookies. If a cookie presents the “Max-Age” (that has preference over “Expires”) or “Expires” attributes, it will be considered a persistent cookie and will be stored on disk by the web browser based until the expiration time.
...
So we need digging more to the way whole thing work together from User device to Web server, browser, config etc.


Script authen with passport:
//-------------
//Set up authentication with Passport
//-------------
var userModel = require('./models/user')(db);
passport.use(new LocalStrategy(
    function(username, password, done) {
        var errorMessage = 'Incorrect username/password combination.';
        userModel.GetUserByUsername(username, function(err, user) {
            if (err) { return done(err); }
            if (!user) {
              return done(null, false, { message: errorMessage });
            }

            user.validatePassword(password, function(isPasswordCorrect) {
                if (!isPasswordCorrect)
                {
                    return done(null, false, { message: errorMessage });
                }

                //Update with login date
                userModel.UpdateUserWithLogin(username, user.currentLoginTime, function(err){
                    //if we have an error here, we should probably just log it
                    if(err)
                    {
                        console.log(err);
                    }
                });

                return done(null, user);
            });
        });
    }
));

passport.serializeUser(function(user, done) {
  done(null, user);
});

passport.deserializeUser(function(user, done) {
    userModel.GetUserByUsername(user._id, function(err, user) {
            done(err, user);
        });
});

//-------------
//Set up express and configure
//-------------
var sessionStore = new SkinStore(db);
var app = express();

app.configure(function(){
    app.set('port', process.env.PORT || 3000);
    app.set('views', __dirname + '/views');
    app.engine('html', consolidate.swig);
    app.set('view engine', 'html');
    swig.init({
        root: '.',
        allowErrors: true, // allows errors to be thrown and caught by express instead of suppressed
        autoescape: false});

    app.use(express.logger('dev'));

    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser("[mysecrethere]"));
    app.use(express.session({   store: sessionStore,
                            cookie: { expires : new Date(Date.now() + 3600000) } //1 Hour
                            }));
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(flash());
    app.use(expressValidator);

    app.use(express.static(path.join(__dirname, 'public')));

    //Dynamic helpers
    app.use(require('./helpers/DynamicHelpers'));

    app.use(app.router);
});

app.get('/login', routes.login);
app.post('/login', passport.authenticate('local', {failureRedirect: '/login',
                                               badRequestMessage: "Please enter username and password",
                                               failureFlash: true }),
                                               function(req, res) {
                                                    var targetUrl = req.session.pageAfterLogin;
                                                    delete req.session.pageAfterLogin;
                                                    res.redirect(targetUrl || '/account');
                                                });

app.get('/account', IsAuthenticated, routes.account.show);

https://stackoverflow.com/questions/15016551/node-js-express-passport-cookie-expiration

And the IsAuthenticated helper function:

function IsAuthenticated(req,res,next){
    if(req.isAuthenticated())
    {
        next();
    }
    else
    {
        //save the requested page and then redirected
        req.session.pageAfterLogin = req.url;
        req.flash("error", "You must be logged in first!");
        res.redirect('/login');
    }
}

What I can find by debugging is that, after successful authentication (and after a cookie has expired), I hit this logic (from above):

function(req, res) {
    var targetUrl = req.session.pageAfterLogin;
    delete req.session.pageAfterLogin;
    res.redirect(targetUrl || '/account');
}

Where I can see that the "req" has the session properly set, with Passport information stored properly. Then, the redirect happens, the new request has no session information stored, and has an entirely new Session ID. I suspected that no cookie was being set on the client, and that does appear to be the case, which should explain the lack of consistent sessions.

However, I cannot figure out why no new cookie is being set. Is there something wrong with how the app is configured that would indicate why this is happening?

I should add that restarting the Node.js instance fixes the issue, it's just not something that would be tolerable in production.

Thanks.

UPDATE: I ran Fiddler to see what was happening with HTTP/S traffic, and I can see that when it works initially, I'm getting a cookie set in the browser (I tried several) which is then passed back to the server on subsequent requests.

When it doesn't work, the browser is not passing cookies to the server, and so Node is sending a Set-Cookie header that provides a new cookie each time. So far I've had no luck determining the cause of this.


Have you checked that passport.deserializeUser is run, that user._id exists and that your model finds the user? Also serializeUser should callback an id, not the user object. – Andreas Hultgren Feb 22 '13 at 10:03
 
I was able to test this out (finally), and I can see that serializeUser is getting called. However, in subsequent redirects, deserializeUser is not getting run. In serializeUser, the user was found properly, it just doesn't seem to persist. And I will work to serialize the user._id instead of the user. I had done that originally but switched for some reason I've since forgotten.

I figured it out, although I don't love the answer.
tl;dr; - use maxAge instead of expires.

The issue was rooted in the expiration date set on each cookie (which is automatically set by Express). I noticed that every cookie that was set had the same expiration date, which eventually ended up being in the past and hence instantly expiring.
The cause of that was here:
cookie: { expires : new Date(Date.now() + 3600000) }
The new Date was being created only once, upon server start. That was causing the expiration date to be the same every time. Based on code in the original post, I can't figure out why it doesn't work and yet every example I've found online uses the exact same code. I verified this by defining a function that created this Date, and checking that it only got called upon server start.
To fix this issue, I am defining maxAge instead of "expires". maxAge takes a number of milliseconds, rather than a date, and it appears to be setting the expiration date on all cookies correctly.
I would love to hear if anyone can explain why this is happening in the first place, since others seem to use it successfully. Any thoughts?
See my working code below
app.configure(function(){
    app.set('port', process.env.PORT || 3000);
    app.set('views', __dirname + '/views');
    app.engine('html', consolidate.swig);
    app.set('view engine', 'html');
    swig.init({
        root: '.',
        allowErrors: true, // allows errors to be thrown and caught by express instead of suppressed
        autoescape: false});

    app.use(express.logger('dev'));

    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser("[mysecrethere]"));
    app.use(express.session({   store: sessionStore,
                            cookie: { maxAge : 3600000 } //1 Hour
                            }));
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(flash());
    app.use(expressValidator);

    app.use(express.static(path.join(__dirname, 'public')));

    //Dynamic helpers
    app.use(require('./helpers/DynamicHelpers'));

    app.use(app.router);
});
I believe I am running into this issue as well, affecting users in a timezone on the other side of the world.
Also check the documentation for "rolling" flag. rolling - Force a cookie to be set on every response. This resets the expiration date. The default value is false. github.com/expressjs/session#rolling

This is the cause of problem: In FrontEnd site not backend. So hard to try fix on Server side :(.

app.config(function ($httpProvider) {
    $httpProvider.defaults.withCredentials = true;
    //rest of route code

});

Otherwise we need some update on server too:

 router.use(function(req, res, next) {
        console.log('__________route v11 +++++++++++++++> 01 ');
        res.header("Access-Control-Allow-Credentials", true);
        res.setHeader("Access-Control-Allow-Origin", "http://localhost:8101");
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
        res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        next();

    });

The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'

https://github.com/whatwg/fetch/issues/251
https://stackoverflow.com/questions/19743396/cors-cannot-use-wildcard-in-access-control-allow-origin-when-credentials-flag-i

For multiple origin allow, the logic is similar as many PHP script we've used.
https://stackoverflow.com/questions/24897801/enable-access-control-allow-origin-for-multiple-domains-in-nodejs





Comments

Popular posts from this blog

AWS Elasticache Memcached connection

https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/accessing-elasticache.html#access-from-outside-aws http://hourlyapps.blogspot.com/2010/06/examples-of-memcached-commands.html Access memcached https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/GettingStarted.AuthorizeAccess.html Zip include hidden file https://stackoverflow.com/questions/12493206/zip-including-hidden-files phpmemcachedadmin ~ phpMyAdmin or phpPgAdmin ... telnet mycachecluster.eaogs8.0001.usw2.cache.amazonaws.com 11211 stats items stats cachedump 27 100 https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/VPCs.EC.html https://lzone.de/cheat-sheet/memcached VPC ID Security Group ID (sg-...) Cluster: The identifier for the cluster memcached1 Creation Time: The time (UTC) when the cluster was created January 9, 2019 at 11:47:16 AM UTC+7 Configuration Endpoint: The configuration endpoint of the cluster memcached1.ahgofe.cfg.usw1.cache.amazonaws.com:11211 St...

Notes Windows 10 Virtualbox config, PHP Storm Japanese, custom PHP, Apache build, Postgresql

 cmd => Ctrl + Shift + Enter mklink "C:\Users\HauNT\Videos\host3" "C:\Windows\System32\drivers\etc\hosts" https://www.quora.com/How-to-create-a-router-in-php https://serverfault.com/questions/225155/virtualbox-how-to-set-up-networking-so-both-host-and-guest-can-access-internet 1 NAT + 1 host only config https://unix.stackexchange.com/questions/115464/how-to-properly-set-up-2-network-interfaces-in-centos-running-in-virtualbox DEVICE=eth0 TYPE=Ethernet #BOOTPROTO=dhcp BOOTPROTO=none #IPADDR=10.9.11.246 #PREFIX=24 #GATEWAY=10.9.11.1 #IPV4_FAILURE_FATAL=yes #HWADDR=08:00:27:CC:AC:AC ONBOOT=yes NAME="System eth0" [root@localhost www]# cat /etc/sysconfig/network-scripts/ifcfg-eth1 # Advanced Micro Devices, Inc. [AMD] 79c970 [PCnet32 LANCE] DEVICE=eth1 IPADDR=192.168.56.28 <= no eff => auto like DHCP #GATEWAY=192.168.56.1 #BOOTPROTO=dhcp BOOTPROTO=static <= no eff ONBOOT=yes HWADDR=08:00:27:b4:20:10 [root@localhost www]# ...

Rocket.Chat DB schema

_raix_push_notifications avatars.chunks avatars.files instances meteor_accounts_loginServiceConfiguration meteor_oauth_pendingCredentials meteor_oauth_pendingRequestTokens migrations rocketchat__trash rocketchat_cron_history rocketchat_custom_emoji rocketchat_custom_sounds rocketchat_import rocketchat_integration_history rocketchat_integrations rocketchat_livechat_custom_field rocketchat_livechat_department rocketchat_livechat_department_agents rocketchat_livechat_external_message rocketchat_livechat_inquiry rocketchat_livechat_office_hour rocketchat_livechat_page_visited rocketchat_livechat_trigger rocketchat_message rocketchat_oauth_apps rocketchat_oembed_cache rocketchat_permissions rocketchat_raw_imports rocketchat_reports rocketchat_roles rocketchat_room rocketchat_settings rocketchat_smarsh_history rocketchat_statistics rocketchat_subscription rocketchat_uploads system.indexes users usersSessions https://rocket.chat/docs/developer-guides/sc...