Xowap
Xowap

Reputation: 519

LoopBack user-specific data filtering/access

Currently testing a bunch of frameworks in order to determine a good candidate for future uses in my company, LoopBack caught my attention by being almost perfect for my needs.

However, I get the feeling that their ACL model is quite limited in some cases. Let's take the following use case: on a collaborative travels management website, a user can create and/or join public travels. Let's assume the following API:

Would building such an API require to re-invent the wheel? Or is it some middlewares to implement?

The same goes for per-field ACL. Suppose you have a few checklist items, some manually added and some others automatically generated. Can you block the WRITE operations only on automatic ones, except for changing the "done" field?

Upvotes: 1

Views: 1932

Answers (2)

brunotavares
brunotavares

Reputation: 21

As @amenadiel suggested, you can use a hooks to set a default filter by the logged in user:

MyModel.observe('access', function limitToTenant(ctx, next) {
  ctx.query.where.tenantId = loopback.getCurrentContext().tenantId;
  next();
});

Got this from the docs.

Upvotes: 2

ffflabs
ffflabs

Reputation: 17501

By default, a request to

GET /Travels

would list every element of the Travel model. If you set proper relations (probably a many to many relationship between users and travels) the proper way to query for a given user travels is

GET /Users/{id}/Travels

But you can customize the default behavior of Travels.find() using hooks, scopes and even overloading the method prototype.

Regarding /Travels/public that's trivial, you just need to create a remote method. Use the path property to customize the endpoint.

Finally, joining a travel with a request to /Travels/{id}/join would be managed with remote methods too, but this should be a POST request.

Loopback is able to manage many to many relations without specifying a relation table, but in your case I'd rather define it. For example

{
"name": "UserTravel",
  "options": { ... },
  "properties": {
    "id":{"type":"Number", "id":1},
    "userId":{"type":"Number"},
    "travelId":{"type":"Number"}
  },
  "relations": {
    "Travel": {
        "type": "belongsTo",
        "model": "Travel",
        "foreignKey": "travelId"
    },
    "User": {
        "type": "belongsTo",
        "model": "User",
        "foreignKey": "userId"
    }
  }
}

having this model at hand would allow you to insert a specific user/travel tuple when calling the join endpoint. You get the travelId from the request params, and the userId from the request accessToken, provider the user is authenticated in your app.

Upvotes: 6

Related Questions