Обеспечение доступа к коллекции со стороны клиента
У меня есть прототип метеорного приложения, который работает хорошо, но на данный момент очень небезопасно: мне нужно было отобразить список подходящих пользователей для текущего вошедшего в систему пользователя. Для начала я решил опубликовать всех пользователей, ограничив поля тем, что мне потребуется для фильтрации списка пользователей на стороне клиента.
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}})};
}
});
});
(обратите внимание, что мне все еще нужно исключить текущего пользователя из запроса маршрутизатора, поскольку текущий пользователь всегда полностью публикуется)
Это работает,но:
список пользователей не обновляется, когда я изменяю интерес пользователя, а затем делаюRouter.go('usersList')
, Только когда я обновляю браузер, мой список обновляется в соответствии с новыми интересами пользователя. Понятия не имею почему.это решение по-прежнему публикует друзей пользователей для отображения моих подходящих границ. Я хочу добавить временное поле в свой запрос на публикацию, установив для него значение «да», если пользователь находится в друзьях пользователя, и «нет» в противном случае, но ... пока что безуспешно.Я читал, я мог бы использовать агрегат, чтобы, возможно, достичь этого но до сих пор не удалось. Кроме того, агрегат не возвращает курсор, который ожидается от публикации.Эта проблема заставляет меня усомниться в том, что метеорит подходит для безопасных приложений ... Этого было бы легко достичь в 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. Но это дает представление о том, чего я хочу достичь: дать клиенту возможность узнать, подходит ли ему друг, или нет, не предоставляя клиенту доступ к спискам друзей всех пользователей. (а также избегая необходимости делать один запрос на каждого пользователя во время отображения, чтобы спросить сервер, соответствует ли этот конкретный пользователь этому конкретному)