11

Let's say I don't want my client to have access to a collection, but I do want my client to be able to ask certain questions about objects within that collection. How would I achieve this?

As an example, let's say I want to know if there's currently a user logged in. When a user first logs in, I set that user's database id in Session and in a cookie. Currently, the application says a user is logged in if !Session.equals("user_id", null), which of course is very insecure because now I can open firebug and say Session.set("user_id", "foo") and now I'm logged in.

I don't want the client to have access to the Users collection at this point. The only client code that has access to this collection is enclosed in a self executing function in an effort to protect it (I'm not really sure if that's the right way to do security in Meteor, so feel free to recommend something along those lines as well). So instead I'd like to call some server side code and pass it the id that's set in session and have it tell me if that's a valid user or not.

Here's how I'd like to see it setup:

// client
function logged_in() {
  return SomeServerMethodThatValidatesUserId(Session.get("user_id"));
}

Meteor.methods doesn't seem to fit the bill, since Meteor.call performs an asynchronous callback. The pub/sub model looks a little more promising, but from the documentation, I'm not quite sure how it works.

It seems to suggest that I should call this.set from within the publish handler in order to set some values on the client, but I can't figure out where those values become available.

Or maybe the pub/sub model isn't right for this either and there's another way that I'm missing. Any advice is appreciated!

Samo
  • 8,202
  • 13
  • 58
  • 95
  • 1
    Check out this answer by one of the Meteor developers: http://stackoverflow.com/questions/10115042/how-do-you-secure-the-client-side-mongodb-api/10116342#10116342 It shows how to disable the default "training wheels" that allow the client and server to execute arbitrary mongo commands. Then you can expose only what you want to the client via Meteor.methods and Meteor.publish. This will be simplified when the Meteor auth package is released. – rmarscher Apr 22 '12 at 19:56

2 Answers2

6

It sounds like you're trying to restrict the client from accessing data until it's been authenticated. Here's one way to do that:

First, write a Meteor.publish function on the server that takes a user_id argument. Your function does whatever check you want in the privileged server environment and ultimately returns a Cursor. One simple example would be:

// define collection on both client and server
Users = new Meteor.Collection('users');

// server-side publish
Meteor.publish('my-user', function (user_id) {
  if (someServerMethodThatValidatesUserId(user_id))
    // publish a single user object to the client
    return Users.find({_id: user_id});
});

Then on the client, subscribe to the my-user set once you have a user_id in hand:

// client-side
Meteor.subscribe('my-user', Session.get('user_id'));

Now, you'll have one document in Users on the client if and only if the user_id was valid, as determined by your privileged function someServerMethodThatValidatesUserId that runs on the server.

(this.set is available inside your publish function if you want to manually manage the specific documents that get sent to the client, instead of relying on a Mongo query. But I don't think anything like that is necessary here.)

debergalis
  • 11,870
  • 2
  • 49
  • 43
  • 1
    It seems like that would create a conflict with other parts of my client code that want access to my entire Users collection, wouldn't it? – Samo Apr 22 '12 at 04:57
  • this is not bad, even if the user decides to change the session value of 'user_id' the server will validate anyway. – a11hard Apr 23 '12 at 00:22
1

This is an old question from the age before Meteor had authentication. The TL;DR answer is:

meteor remove autopublish

Then, manage your own collections, publications and subscriptions.

Community
  • 1
  • 1
Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404