Domanda

I have an application that needs authorization based on the relation between the requesting user and the requested resource. The access details are encapsulated in the resource to be requested.

Let's take the route PATCH /articles/1: the article has an author/owner and an array of editors who all have access to update the article. The requesting user is authenticated and could be the author or one of the editors. Otherwise, access should be denied.

--

I have two ideas:

  1. Authorization in middleware:
    This means the middleware needs the resource already before the controller can do its thing to aggregate the resource. However, sometimes (for example when using the MongoDB aggregation framework) the controller won't be able to reuse the resource and needs another round-trip to the database.

  2. Authorization in controller:
    The authorization could be performed in the controller as soon as the resource is available/aggregated. But this would separate this part of authorization from the authentication and the role-based access control I already have in place as middleware.

I personally think the middleware approach makes more sense, but the database will be hosted by another PaaS, and even within the same data center there will probably be some latency.

And what if a related resource (for example comments) is requested? That would involve some specific logic to come from comments to the article where the access details are stored. And would make my auth middleware much less generic.

--

Are there any other options available?

--

The application uses Koa, but the concepts can probably be applied to every other middleware-supporting framework such as Express or others.

Please note that I'm not asking about authentication or classic role-based access provided for example by connect-roles.

È stato utile?

Soluzione

My normal pattern is use a route parameter to fetch the resource from the database such as:

app.param("articleId", function (req, res, next, paramValue) {
  var _id;
  try {
    _id = new ObjectID(paramValue);
  } catch (error) {
    res.status(400).send('Invalid ID');
    return;
  }
  Article.findById(_id, function(error, doc){
    if (error) {
      next(error);
      return;
    }
    if (doc) {
      req.article = doc;
      next();
      return;
    }
    res.send(404);
  });
});

Then I use a middleware for the authorization but it can assume req.article is already loaded from the database.

This is a good default pattern, and I think you should use it for a while and get used to it before doing any performance optimizations, but when you really and truly have enough traffic to choose a less-generic pattern, go for it. Just keep in mind that usually is justified in year 2 or 3 of a startup/project, not for launch day.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top