Sicherstellung des Zugriffs auf die Sammlung durch den Kunden

Ich habe einen Prototypen einer Meteor-App, der gut funktioniert, der aber ab sofort sehr unsicher ist: Ich musste eine Liste der übereinstimmenden Benutzer für den derzeit angemeldeten Benutzer anzeigen. Für den Anfang habe ich beschlossen, alle Benutzer zu veröffentlichen und die Felder auf das zu beschränken, was ich zum Filtern der Benutzerliste auf der Clientseite benötigen würde.

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

Dann würde ich in meinem Router eine Anfrage machen, um nur zu zeigen, was ich auf der Clientseite wollte:

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}
          ]})
      };
    }
  });
});

Im obigen Code frage ich alle Benutzer ab, die nicht der aktuelle Benutzer sind und deren Typ den Interessen des aktuellen Benutzers entspricht. Ich zeige auch einen bestimmten Rahmen auf den Fotos von Benutzern an, die meinen Benutzer in ihrem "profile.friends" -Array haben, indem ich diesen Client-Helfer verwende:

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";
  }
});

Jetzt hat alles wunderbar geklappt, aber mit diesem Setup kann jeder Client jeden Benutzer abfragen und Typ, Bild, Freundesliste und Anzahl der Likes abrufen. Wenn ich in einer MVC wäre, wären diese Informationen nur auf der Serverseite verfügbar. Also entschied ich mich für eine Sicherheits-Iteration. Ich würde meine Abfrage von der Router-Datei in die Publikationsdatei verschieben. Hier begannen die Probleme ...

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;
});

Und im Router:

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}})};
    }
  });
});

(Beachten Sie, dass ich den aktuellen Benutzer immer noch von der Router-Abfrage ausschließen muss, da der aktuelle Benutzer immer vollständig veröffentlicht ist.)

Das funktioniert,aber:

Die Benutzerliste wird nicht aktualisiert, wenn ich das Benutzerinteresse ändere und dann aRouter.go('usersList'). Nur wenn ich den Browser aktualisiere, wird meine Liste entsprechend dem neuen Interesse des Benutzers aktualisiert. Keine Ahnung warum.Diese Lösung veröffentlicht weiterhin die Freunde der Benutzer, um meine übereinstimmenden Rahmen anzuzeigen. Ich möchte meiner Veröffentlichungsabfrage ein temporäres Feld hinzufügen und es auf "Ja" setzen, wenn sich der Benutzer in den Freunden des Benutzers befindet, und auf "Nein", wenn dies nicht der Fall ist, aber ... bisher kein Erfolg.Ich habe gelesen, ich könnte Aggregat verwenden, um das vielleicht zu erreichen aber bisher nicht geschafft. Außerdem gibt aggregate keinen Cursor zurück, der von einer Veröffentlichung erwartet wird.

Dieses Problem lässt mich bezweifeln, dass Meteor für sichere Apps geeignet ist ... Das wäre in Rails oder anderen so einfach zu erreichen!

BEARBEITEN: Wie gewünscht, hier ist der Code, den ich bisher für den Übergang meines "Matching" -Checks zum Server habe:

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;
});

Offensichtlich funktioniert dieser Code überhaupt nicht, da ich die Cursorwerte in einer foreach-Schleife nicht ändern kann. Aber es gibt eine Vorstellung davon, was ich erreichen möchte: Geben Sie dem Kunden die Möglichkeit, herauszufinden, ob ein Freund gefunden wurde oder nicht, ohne dem Kunden Zugriff auf die Freundeslisten aller Benutzer zu gewähren. (Außerdem müssen Sie während der Anzeige nicht für jeden Benutzer eine Anfrage stellen, um den Server zu fragen, ob dieser bestimmte Benutzer mit diesem bestimmten übereinstimmt.)

Antworten auf die Frage(1)

Ihre Antwort auf die Frage