确保从客户端访问收集

时间:2014-07-15 08:14:24

标签: security meteor publish-subscribe

我有一个运行良好的流星应用原型,但截至目前非常不安全:我需要向当前登录用户显示匹配用户列表。对于初学者,我决定发布所有用户,将字段限制为在客户端过滤用户列表所需的字段。

Meteor.publish('users', function () {
  return Meteor.users.find({}, {
    fields: {
      'profile.picture': 1,
      'profile.likes': 1,
      'profile.friends': 1,
      'profile.type': 1
    }
  });
});

然后在我的路由器中,我会请求只在客户端显示我想要的内容:

Router.map(function() {
  this.route('usersList', {
    path: '/users',
    waitOn: function () {
      return Meteor.subscribe('users');
    },
    data: function () {
      var user = Meteor.user();
      return {
        users: Meteor.users.find({ $and: [
            {_id: {$ne : user._id}},
            {'profile.type': user.profile.interest}
          ]})
      };
    }
  });
});

在上面的代码中,我查询不是当前用户且其类型符合当前用户兴趣的所有用户。我还使用此客户端助手在我们的“profile.friends”数组中将用户的照片显示在某个边框上:

Template.userItem.helpers({
  getClass: function(userId) {
    var user = Meteor.user();
    var lookedup = Meteor.users.findOne({_id: userId});
    if ($.inArray(user._id, lookedup.profile.friends) !== -1)
      return "yes";
    return "no";
  }
});

现在这一切都很有效,但通过这种设置,每个客户都可以查询每个用户并获取他们的类型,图片,朋友列表和喜欢的数量。如果我在MVC中,则只能在服务器端访问此信息。所以我决定我的下一次迭代是安全的。我会将我的查询从路由器文件移动到publication文件。这就是麻烦开始的地方......

Meteor.publish('users', function () {
  var user = Meteor.users.findOne({_id: this.userId});
  var interest =  user.profile.interest;
  // retrieve all users, with their friends for now
  allUsers = Meteor.users.find({ $and: [
      {'_id': {$ne: user._id}},
      {'profile.type':interest}
    ]},
    { fields: {'profile.picture': 1, 'profile.friends': 1}}
  );
  return allUsers;
});

在路由器中:

Router.map(function() {
  this.route('usersList', {
    path: '/users',
    waitOn: function () {
      return Meteor.subscribe('users');
    },
    data: function () {
      var user = Meteor.user();
      return {users: Meteor.users.find({_id: {$ne : user._id}})};
    }
  });
});

(请注意,我仍然需要从路由器查询中排除当前用户,因为当前用户始终完全发布)

这有效,

  1. 当我更改用户兴趣然后执行Router.go('usersList')时,用户列表不会更新。只有当我刷新浏览器时,我的列表才会根据用户的新兴趣进行更新。不知道为什么。
  2. 此解决方案仍然会发布用户的朋友,以显示我的匹配边框。我希望在我的发布查询中添加一个临时字段,如果用户在用户的朋友中则将其设置为“是”,否则设置为“否”,但是......到目前为止没有成功。 I read I could use aggregate to maybe achieve that但到目前为止尚未成功。此外,聚合不会返回游标所期望的游标。
  3. 这个问题让我对流星适用于安全应用的赞美感到怀疑......这在Rails或其他人中很容易实现!

    编辑:根据要求,这是我到目前为止将“匹配”检查过渡到服务器的代码:

    Meteor.publish('users', function () {
      var user = Meteor.users.findOne({_id: this.userId});
      var interest =  user.profile.interest;
      // retrieve all users, with their friends for now
      allUsers = Meteor.users.find({ $and: [
          {'_id': {$ne: user._id}},
          {'profile.type':interest}
        ]},
        { fields: {'profile.picture': 1, 'profile.friends': 1}}
      );
      // ------------- ADDED ---------------
      allUsers.forEach(function (lookedup) {
        if (_.contains(lookedup.profile.friends, user._id))
          lookedup.profile.relation = "yes";
        else
            lookedup.profile.relation = "no";
        lookedup.profile.friends = undefined;
        return lookedup;
      });
      // ------------- END ---------------
      return allUsers;
    });
    

    显然这段代码根本不起作用,因为我无法在foreach循环中修改游标值。但它给出了我想要实现的目标:给客户端一个方法来了解朋友是否匹配,而无需访问客户端的所有用户的朋友列表。 (并且,避免在显示期间每个用户必须执行一个请求,以询问服务器此特定用户是否与此特定用户匹配)

1 个答案:

答案 0 :(得分:0)

您可以添加转换功能并动态修改游标文档 meteor Collection.find