4

I currently try to set up a simple authorization system (authentication already in place) for a sails (v0.10) application based on the policy system sails provides. For this purpose I'd need to get the controller and action the current request targets from within my policy.

I'd do roughly do the following in the policy:

 module.exports = function (req, res, next) {
     // Get target controller and action
     var target = req.target; // How to do this?
     var action = req.action; // and this?

     // Lookup in database, let through if matches or render error
     User.findOne...
  };

I recall the target information was embedded in the request object at some point but isn't found there now (commit 5d98ec8).

I am aware of the possibility to parse req.route and get the needed information by mimicking the sails router, but I'd rather avoid duplicating the routing logic for the sole purpose of a policy.

Edit:

The controller identity can be retrieved from the request object like this:

var controller = req.options.controller || req.options.model;

Example req.options:

{ detectedVerb: { verb: '', original: '/user/:id?', path: '/user/:id?' },
  associations: 
    [ { alias: 'auth', type: 'model', model: 'key' },
      { alias: 'group', type: 'model', model: 'group' },
      { alias: 'role', type: 'model', model: 'role' } ],
  actions: true,
  rest: true,
  shortcuts: true,
  prefix: '',
  pluralize: false,
  index: true,
  model: 'user' }

Still hunting for a sane way to get the target controller action.

marionebl
  • 3,342
  • 20
  • 34
  • If you don't mind, why do you need this? Sails policies already match on controller/action. Why don't you use policies.js to do your authorization? – Erin Ishimoticha Feb 03 '14 at 17:39
  • Hey serafina, I need both controller and action identity to look up corresponding records in my database. The purpose of this is a freely configurable authorization system, that works roughly like this: 1. Get stored privileges for user 2. Get allowed controllers and actions for privileges 3. Check if **current** controller and action is found in retrieved records. – marionebl Feb 03 '14 at 18:36
  • I see. I don't know the answer to your original question, but I'd venture to say that if what you're doing is this roundabout, there may be a better way. If your project is flexible, I'd start by trying to move that logic into Sails. FYI, I played around with generating policies.js by looping sails.controllers and policies for each action which could detect its name via [this method](http://stackoverflow.com/questions/2648293/javascript-get-function-name#15714445) but I couldn't dynamically export multiple policies. I'm interested to see if you can find an elegant way to solve this. – Erin Ishimoticha Feb 03 '14 at 19:54
  • Generating the policies config dynamically is an interesting idea I'd give definitely a try in any other project. Anyway in my current project I greatly rely on all configs being declarative as I will have to install it on various occasions with various configurations. To the original question: I did not come up with a solution for this but created an issue on the [sails repo](https://github.com/balderdashy/sails/issues/1372). – marionebl Feb 04 '14 at 19:22
  • I also will NEED to know the action called, because I'm overloading the sails controllers and adding magic method calls, based on the action. I'm currently in 0.9.8 so I use `req.target.action` but I will definitely need to have access to the action in the 0.10! – Vadorequest Feb 07 '14 at 11:20

1 Answers1

6

Based on the feedback on the Github issue about this I decided to write up a target action/target blueprint lookup as custom service leaning on the route bindings found in sails.hooks.blueprints.

Usage:

var action = Utility.getRequestAction(req);

The service definition:

/**
 * api/services/Utitlity.js
 *
 * @module        Service
 * @name          Utility
 * @memberOf      global
 * @description   Utilities for various common tiny tasks
 * @docs          http://sailsjs.org/#!documentation/services
 * @api           public
 **/

/**
 * Module dependencies
 */
  var util = require('util'),
      _ = require('lodash');

module.exports = {

  getRequestAction: function (req) {
    if (req.options.action) return req.options.action;

    var controller = req.options.controller || req.options.model;

    var baseRoute = sails.config.blueprints.prefix + controller;
    var requestRoute = req.route.method + ' ' + req.route.path;

    var Model = sails.models[controller];

    if (req.options.shortcuts && Model) {
      var shortcutRoutes = {
        '/%s/find/:id?': 'find',
        '/%s/create': 'create',
        '/%s/update/:id?': 'update',
        '/%s/destroy/:id?': 'destroy'
      };

      var shortcutAction = _.findWhere(shortcutRoutes, function(blueprint, pattern){
        var shortcutRoute = util.format(pattern, baseRoute);
        return req.route.path === shortcutRoute;
      });

      if (shortcutAction) return shortcutAction;
    }

    if (req.options.rest && Model) {
      var restRoutes = {
        'get /%s/:id?': 'find',
        'post /%s': 'create',
        'put /%s/:id?': 'update',
        'delete /%s/:id?': 'destroy'
      };

      var restAction =_.findWhere(restRoutes, function(blueprint, pattern){
        var restRoute = util.format(pattern, baseRoute);
        return requestRoute === restRoute;
      });

      if (restAction) return restAction;

      var associationActions = _.compact(_.map(req.options.associations, function(association){
        var alias = association.alias;

        var associationRoutes = {
          'get /%s/:parentid/%s/:id?': 'populate',
          'post /%s/:parentid/%s': 'add',
          'delete /%s/:parentid/%s': 'remove'
        };

        return _.findWhere(associationRoutes, function(blueprint, pattern){
          var associationRoute = util.format(pattern, baseRoute, alias);
          return requestRoute === associationRoute;
        });
      }));

      if (associationActions.length > 0) return associationActions[0];
    }
  }
};
marionebl
  • 3,342
  • 20
  • 34