Filtering socket.io subscriptions

2019-04-16 12:58发布

问题:

Imagine I have a User model and also a Message model. User has many messages.

Then in the client I do a:

io.socket.get('/user/2/messages'....

I get all my user messages and there is no problem trying to get someones else messages because I have a policy for that. Good.

I want to listen if the user has new messages, if I do a:

io.socket.on('message')

I get every message created, mine or not mine.

So: Can I listen just for MY messages? AKA listen for associated messages but not all of them.

Maybe using a policy or something for just that. Because even if there is a way to listen to them, anyone can modify the client to listen to what he wants to, I need to filter all of that.

回答1:

Yes, you can. The trick is to listen for user events with the "addedTo" verb, rather than listening directly for message creation. The code would be something like:

io.socket.on('user', function(msg) {

    if (msg.verb == 'addedTo' && msg.attribute == 'messages') {

        // A new message was added to the user's "messages" collection
        var messageId = msg.addedId
        // From here you can request /message/[messageId] to get the
        // message details if you need them

    }

});

More info on the .publishAdd() doc page.

Note that only the ID of the added message is given; you may find you want the whole thing. You can handle that by either making a separate request for the new message, or overriding publishAdd as is suggested in this answer.

The only catch here is to make sure you're limiting who gets subscribed to those user events. It sounds like you have a policy in place that prevents users from accessing /user/:id/messages for other users. You'll want want preventing them from accessing /user/:id for other users as well (at least via sockets), since they will be subscribed to any user they access that way.

If this is undesirable--that is, if you'd like people to be able to hit those routes--then an alternative would be to use the autoSubscribe model property to restrict the automatic subscription that blueprints normally do. autoSubscribe is normally set to true, which means that any time a socket request is made for a model, the requesting socket will be subscribed to all events for that model instance. You can instead set it to an array of contexts that should be subscribed to. Contexts are specific events you're interested in, like update or destroy (more about contexts in the docs). Finally, you can set autoSubscribe to false to restrict subscription to that model entirely. Then you can just subscribe manually with .subscribe() whenever you want to listen for events.

You can see some examples of contexts and autoSubscribe in action in the sailsChat sample app.