我有一个运行良好的流星应用程序原型,但目前非常不安全:我需要显示与当前登录用户匹配的用户列表。首先,我决定发布所有用户,将字段限制为过滤客户端用户列表所需的字段。
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 中,则只能在服务器端访问此信息。所以我决定下一次迭代是安全迭代。我会将查询从路由器文件移至出版物文件。这就是麻烦开始的地方......
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}})};
}
});
});
(请注意,我仍然需要从路由器查询中排除当前用户,因为当前用户始终是完全发布的)
这有效,but:
- 当我更改用户兴趣然后执行操作时,用户列表不会更新
Router.go('usersList')
。仅当我刷新浏览器时,我的列表才会根据用户的新兴趣进行更新。不知道为什么。
- 该解决方案仍然发布用户的朋友,以便显示我的匹配边框。我希望在我的发布查询中添加一个临时字段,如果用户在用户的朋友中,则将其设置为“是”,否则设置为“否”,但是......到目前为止还没有成功。我读到我可以使用聚合来实现这一目标但到目前为止还没有成功。此外,聚合不会返回出版物所期望的游标。
这个问题让我对 Meteor 是否适合安全应用程序的赞誉产生了怀疑……这在 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 循环中修改游标值。但它给出了我想要实现的目标:为客户端提供一种方法来了解朋友是否匹配,而无需向客户端授予对所有用户的朋友列表的访问权限。 (而且,避免在显示期间为每个用户执行一个请求来询问服务器该特定用户是否与该特定用户匹配)