0

I already checked a lot of references and found good sources like this one: Get current user from inside the model in Sails. So I'm asking for best practices and your experiences.

As I've developed a quite complex platform based on JWT-Authentication I have to fix the major mistake to store the current user data (while user requests something) on my sails instance. I know that this leads to major security leaks (for more than one user).

The question is: How can I store and access current user data without passing the session object through almost all methods I've created?

Is passing the session object around through all helpers, utilities etc. the only way to solve this? Instead of using a centralized Service like: UserService.getCurrentUser();

Any help is highly appreciated. Thanks!

Community
  • 1
  • 1
eleonis
  • 5
  • 5

1 Answers1

0

If you're asking if there's a way to globalize the user data so that it's magically available to all your methods, the short answer is that there's no safe way to do this in Node (let alone in Sails.js). Node's single-threaded nature makes it impossible to maintain state in that way.

Some folks have solved this in Sails by using a globally-applied policy that looks up the user and adds it to the request:

// api/policies/fetch-user.js
module.exports = function fetchUserPolicy (req, res, next) {

  // Get the user ID  out of the session.
  var userId = req.session.userId;

  // If there's no user logged in, just continue.
  if (!userId) { return next(); }

  // Look up the user by ID.
  User.findOne({id: userId}).exec(function(err, user) {
    if (err) { return res.serverError(err); }
    if (!user) { return res.serverError(new Error('Could not find user in session!')); }

    // Add the user info to the request.
    req.user = user;

    // Continue the request.
    return next();  

  });

};

There's nothing wrong with this code, but we don't recommend it because best practice is to use policies purely for access control. Instead, you can do pretty much the same exact thing in a custom hook:

// api/hooks/fetch-user.js
module.exports = function fetchUserHook(sails) {

  return {

    // Add some routes to the app.
    routes: {

      // Add these routes _before_ anything defined in `config/routes.js`.
      before: {

        // Add a route that will match everything (using skipAssets to...skip assets!)
        '/*': {
          fn: function(req, res, next) {

            // Get the user ID  out of the session.
            var userId = req.session.userId;

            // If there's no user logged in, just continue.
            if (!userId) { return next(); }

            // Look up the user by ID.
            User.findOne({id: userId}).exec(function(err, user) {
              if (err) { return res.serverError(err); }
              if (!user) { return res.serverError(new Error('Could not find user in session!')); }

              // Add the user info to the request.
              req.user = user;

              // Continue the request.
              return next();

            });
          },
          skipAssets: true
        }

      }
    }
  };
};

Either way, you'll still need to pass req around to any methods that want to use the user info that was fetched.

sgress454
  • 24,870
  • 4
  • 74
  • 92
  • Thanks for your reply. So you recommend to use a hook for adding the user info to the current request before checking policies. What is wrong with having different policies using all one service to check roles etc. and adding current user data to the request session if logged in? What is the best way to passing e.g. the current userId to at some points at least 4 or more methods / services? Simply as parameter through all these methods? – eleonis Mar 17 '17 at 23:06
  • And what is your recommendation for dealing with current user data in Models? E.g. limiting returned json output [on toJSON()] based on ACL or logging user actions in lifecycles like afterUpdate()? – eleonis Mar 18 '17 at 12:30