环回授权用户只能查看其数据 [英] Loopback authorize a user to see only his data

查看:73
本文介绍了环回授权用户只能查看其数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Loopback开发NodeJS应用程序.

I am developing a NodeJS application using Loopback.

我对nodejs和REST API都还很陌生,所以如果我在概念上错了,请纠正我.

I am pretty new to both nodejs and REST APIs, so please correct me if I am conceptually wrong.

Loopback自动构建CRUD REST API,这是我要使用的功能,以避免自己编写API,但是我需要限制用户只能查看其数据.

Loopback automatically builds CRUD REST APIs, which is a feature I would like to use in order to avoid to write APIs by myself, but I need to limit users to be able to see only their data.

例如,假设我的数据库中有3个表,分别是userbook和一个关系表user_book.

For example, imagine there are 3 tables in my DB, user, book and a relation table user_book.

例如:

table user
    id | name
    ---------
    1 | user1
    2 | user2
    3 | user3

table book
    id | title | author
    -------------------
    1 | title1 | author1
    2 | title2 | author1
    3 | title3 | author2
    4 | title4 | author2
    5 | title5 | author3

table user_book
    id | user_id | book_id
    -------------------
    1 |     1    |    1
    2 |     1    |    4
    3 |     1    |    3
    4 |     2    |    3
    5 |     2    |    2
    6 |     2    |    1
    7 |     3    |    3

对用户X进行身份验证后,API /books应该仅回答X的书籍,而不是表格中的每本书籍.例如,如果用户user1被登录并调用/books,则他获取的应该仅是他的书,因此ID为1, 3, 4的书.

When a user X is authenticated, the API /books should answer with ONLY X's books, and not every book in the table. For example, if user user1 is logged and calls /books, he get should only get his books, so books with id 1, 3, 4.

类似地,/books?filter[where][book_author]='author1'应该只返回用户X的作者为"author1"的图书.

Similarly, /books?filter[where][book_author]='author1' should return only books of user X whose author is 'author1'.

我发现环回提供了远程钩子在执行远程方法之前和之后进行附加,并且还提供所谓的

I found out that loopback offers remote hooks to attach before and after the execution of a remote method, and also offers so called scopes to

[...]指定可以用作方法调用引用的常用查询 在模型上[...]

[...]specify commonly-used queries that you can reference as method calls on a model[...]

我正在考虑使用两者的组合,以便将对表books的访问限制为仅运行该调用API的用户行.

I was thinking about using a combination of the 2 in order to limit access to the table books to only rows of the user that runs calls the API.

module.exports = function (book) {

  // before every operation on table book
  book.beforeRemote('**', function (ctx, user, next) {
    [HERE I WOULD PERFORM A QUERY TO FIND THE BOOKS ASSOCIATED WITH THE USER, LET'S CALL ID book_list]

    ctx._ds = book.defaultScope; // save the default scope
    book.defaultScope = function () {
      return {
        'where': {
          id in book_list
        }
      };
    };

    next();
  });

  book.afterRemote('**', function (ctx, user, next) {
    book.defaultScope = ctx._ds; // restore the default scope
    next();
  });
};

此解决方案行得通吗?我尤其特别关注并发性.如果有来自不同用户的/books多次请求,那么更改默认范围将是一项关键操作吗?

Would this solution work? In particular, I am particularly concerned about concurrency. If multiple requests happen for /books from different users, would changing the default scope be a critical operation?

推荐答案

我们完成此操作的方法是创建一个mixin.看看github中的回送时间戳混合.我建议混合创建与您的用户模型的所有者"关系.简而言之,这是它的工作方式:

The way we accomplished this was to create a mixin. Have a look at the loopback timestamp mixing in github. I would recommend the mixing create an "owner" relation to your user model. Here's how it works in a nutshell:

  • 每个使用mixin的模型都会在模型和用户之间创建一个关系
  • 每次创建模型的新实例时,userId都会与该实例一起保存
  • 每次调用
  • find findById 时,都会对查询进行修改以添加 {其中:{userId:[当前登录的用户ID]}} 条款
  • Each model that uses the mixin will have a relation created between the model and the user
  • Every time a new instance of the model is created, the userId will be saved with the instance
  • Everytime find or findById is called, the query will be amended to add the {where:{userId:[currently logged in user id]}} clause

/common/mixins/owner.js

'use strict';
module.exports = function(Model, options) {
  // get the user model
  var User = Model.getDataSource().models.User;
  // create relation to the User model and call it owner
  Model.belongsTo(User, {as: 'owner', foreignKey: 'ownerId'});

  // each time your model instance is saved, make sure the current user is set as the owner
  // need to do this for upsers too (code not here)
  Model.observe('before save', (ctx, next)=>{
    var instanceOrData = ctx.data ? 'data' : 'instance';
    ctx[instanceOrData].ownerId = ctx.options.accessToken.userId;
  });

  // each time your model is accessed, add a where-clause to filter by the current user
  Model.observe('access', (ctx, next)=>{
    const userId = safeGet(ctx, 'options.accessToken.userId');
    if (!userId) return next();  // no access token, internal or test request;
    var userIdClause = {userId: userId};

    // this part is tricky because you may need to add
    // the userId filter to an existing where-clause

    ctx.query = ctx.query || {};
    if (ctx.query.where) {
      if (ctx.query.where.and) {
        if (!ctx.query.where.and.some((andClause)=>{
          return andClause.hasOwnProperty('userId');
        })) {
          ctx.query.where.and.push(userIdClause);
        }
      } else {
        if (!ctx.query.where.userId) {
          var tmpWhere = ctx.query.where;
          ctx.query.where = {};
          ctx.query.where.and = [tmpWhere, userIdClause];
        }
      }
    } else {
      ctx.query.where = userIdClause;
    }
    next();
  });
};

/common/models/book.json

{
  "mixins": {
    "Owner": true
  }
}

每次使用所有者混合时,该模型都会在每次创建或保存新实例时自动添加并填充ownerId属性,并且每次获取"数据时都会自动过滤结果.

Every time you use the Owner mixing, that model will automatically have a ownerId property added and filled each time a new instance is created or saved and the results will automatically be filtered each time you "get" the data.

这篇关于环回授权用户只能查看其数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆