How can I filter REST calls results based on Roles and current user context in Loopback (server side)

眉间皱痕 提交于 2019-12-10 23:16:41

问题


Given the following:

There are 3 models:

  1. Company
  2. Employee (derived from User)
  3. Position

Company is linked to Employee through Position (has many, has many)

There are 2 Roles:

  1. admin
  2. user

I would like to configure my REST api as follow:

When an admin is logged, can access all REST functions.

  "accessType": "*",
  "principalType": "ROLE",
  "principalId": "admin",
  "permission": "ALLOW"

When a user is logged:

GET /companies : Only return the companies in which the current user has a position.

GET /companies/#id: Only allow if the current user has a position in this company.


回答1:


Based on J3Y's comment, I wrote the following function.

Note that the function is not overriding model ACL.


The procedure follows those steps:

1: Access current user userID through the loopback current context.

If there is no authenticated user, exit the function.

2: Load Role of the current user, using the RoleMapping table

If the current user Role is not "user", exit the function.

3: Load Positions of our current user and create an array of the companies Id he's working in.

4: rewrite the current query

  • for /companies calls, inject a where condition for id
  • for /companies/#id, test if requested id is matching one of the allowed ids, if not, return an error 401

Company.observe('access', function (ctx, next) {
    /* Observe the access to companies
     *  If the role of the logged user is 'user', will restrict access to only custom set of data
     *  Otherwise, will access all data */

    // Access loopback current Context to get userID through accessToken
    var loopbackCtx = loopback.getCurrentContext();
    var accessToken = loopbackCtx && loopbackCtx.get('accessToken');
    var userId = accessToken && accessToken.userId;

    if (!userId) {
      // without connected user. proceed without hook
      return next();
    }

    // Will perform a query in the RoleMapping Model to findout the current role of connected user
    var RoleMapping = app.models.RoleMapping;
    var roleQuery = {
      where: {
        "principalId": userId,
        "roleId": 2 // role 2: user
      }
    };

    RoleMapping.findOne(roleQuery, function (err, result) {

      if (!result) {
        //no matching role, proceed without hook
        return next();
      }

      // found one match in the RoleMapping table. must now restrict results in accordance with positions of the current employee

      // Looking for positions for the current employee
      var position = app.models.position;
      var positionQuery = {
        where: {
          "employeeId": userId
        }
      };

      position.find(positionQuery, function (err, results) {
        // from the position list, create a list of companies

        var allowedCompanies = [];
        results.forEach(function (result) {
          allowedCompanies.push(result.companyId);
        });

        //use the list of allowed companies to restrict results
        if (!ctx.query.where) {
          // typically call from a find() without arguments (findall)
          // will inject a new condition
          ctx.query = {
            where: {
              "id": { inq: allowedCompanies}
            }
          }
        }
        else {
          if (ctx.query.where.id && Number.isInteger(ctx.query.where.id)) {
            // typically call from a find({ id: .. )}
            // will authorize or not access to the company data
            console.log(ctx.query.where.id);
            if ( allowedCompanies.indexOf(ctx.query.where.id) == -1 ) {
              // the id is not in the permited scope, will return a 401 error
              var error = new Error();
              error.name = "Error";
              error.status = 401;
              error.statusCode = 401;
              error.message = 'Authorization Required';
              error.code = 'AUTHORIZATION_REQUIRED';
              return next(error);
            }
          }
          // other calls (with inq) are not yet implemented
        }

        return next();
      });

    });

});


来源:https://stackoverflow.com/questions/37511149/how-can-i-filter-rest-calls-results-based-on-roles-and-current-user-context-in-l

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!