Best practice? clearing subscriptions upon logout? security?


#1

I’m trying to deal with many subscriptions to different types of collections, and I have a logout button… when they log out, I am trying to call .clear() on all the SubscriptionManager objects, in order to not leave data on the client when they are logged out.

But then I find it tricky to pull that data back to the client when they log back in. I’m currently looking at a “before” hook in the Iron Router configuration:

 Router.configure({layoutTemplate: 'layout',
   before: function () {
     console.log('before hook');
     console.log("subscribing to insuranceCompanies");
     lookupSubsManager.subscribe('insuranceCompanies');
     this.next();
   }
 });

insuranceCompanies is a collection that I’m going to try to use to fill the contents of a drop down select control with AutoForm… Therefore, I don’t have any specific route where I should do this susbcribe() call… all my other subscribe calls are in their respective routes… I just want to ensure that the insuranceCompanies data is up in the client at all times, not depending on a specific route…

btw:

Template.navbar.events = {
  'click #logoutButton': function () {
    console.log("click logout event, calling clearSubscriptions");
    clearSubscriptions();
    Meteor.logout();
    Router.go('/');
  }



clearSubscriptions = function () {
  console.log("clearSubscriptions running");
  filterSubs.clear();
  searchSubsManager.clear();
  detailChartsSubsManager.clear();
  lookupSubsManager.clear();
  console.log("clearSubscriptions finished");
}

thanks.


#2

Instead believing in an event that “they” may logout, I would prefer using template based subscriptions and listen to their create and destroy events.

Have a look at:

  1. https://www.discovermeteor.com/blog/template-level-subscriptions/
  2. https://meteorhacks.com/flow-router-and-subscription-management
  3. https://github.com/meteorhacks/flow-router

#3

I"m not sure what you mean by “believing in an event that “they” may logout”…??

but I do believe you’re telling me to remove iron router and switch things over to using flow router… … guess I’ve got some more learning to do!


#4

I am just reflection, that currently the logout does only happen when “they” (the users) click on the button logout.

I think, as developers we can’t trust them (the users) always act as wished :slight_smile:


#5

We moved over to flow-router and very happy. Just check also FlowLayout and FastRender. But also have a look on template based subscriptions to get the pattern.


#6

ok, still a bit confused, it’s a common pattern to log out the user when they click log out… not sure what’ I’m missing…

but anyway, I switched my subscribe to be done as a template level subscription:

Template.chart.onCreated(function () {
  console.log("chart template is created, subbing to ins companies ");
  lookupSubsManager.subscribe('insuranceCompanies');

}
);

and added the onDestroyed as well:

Template.chart.onDestroyed( function() {
  console.log("the chart template was destroyed");
  lookupSubsManager.clear();

});

So, now I’m seeing that when I’m viewing the chart template, it subscribes to the insuranceCompanies, and when the user switches to any other route, then the insuranceCompanies are cleared out, but that seems very inefficient because now I’m pulling and dropping the data all the time, as the user goes through the app… I really only want to get rid of the subscription when they log out… so maybe back to putting the call to clear() in the logout action?

EDIT: yes, I tried this, and I think this is the way I will go now… I will call subscribe in the onCreated method for the template, and call clear() when the user clicks logout. (and not use the onDestroyed at all)


#7

I am not sure how you have designed your app, but e.g. Flow-Router allows also Global subscriptions, maybe you have a look on that feature as well.

Why I just make my remarks “to click on logout” is, that you at least can not make sure, that a user will click that before closing the browser or changing the url. So I prefer some “technical” driven events to get reliable results but this are just my 10cents.


#8

Meteor.user() is a reactive variable. If you include a reference to it in an autorun, the correct things will be un/subscribed

Template.something.onCreated(function(){
 var self = this;
 self.autorun(function(){
  var userId = Meteor.userId();
  self.subscribe('collection');
 });
});

and on the server you publish based on this.userId. If the user logs out, or the template gets destroyed, that should handle all documents being purged from the client.

If you don’t want to subscribe in a template but globally, you can use the same code on the top-level of your application

 Tracker.autorun(function(){
  var userId = Meteor.userId();
  self.subscribe('collection');
 });

#9
Meteor.publish(null, function() {
    if(this.userId) {
        return JustForLoggedCollection.find({});
    } else {
        throw new Meteor.Error(500, 'Access denied'):
    }
})

#10

@mrzafod that’s pretty cool… I added the check for this.userId in all my publish calls and that works to magically clear the subscriptions on the client upon logout… verified with mongol that they all went to a count of “0”… however, I noticed under “Subscriptions” in mongol, that the subscriptions with their parameters are still visible on the client. Thus, it seems it would still be necessary for me to do this:

 Template.navbar.events = {
  'click #logoutButton': function () {
    console.log("click logout event, calling clearSubscriptions");
    clearSubscriptions();
    Meteor.logout();
    Router.go('/');
  }
clearSubscriptions = function () {
  console.log("clearSubscriptions running");
  filterSubs.clear();
  searchSubsManager.clear();
  detailChartsSubsManager.clear();
  lookupSubsManager.clear();
  console.log("clearSubscriptions finished");
}

Now I see why some web apps tell the user “please close your browser after logging out”… maybe that’s the real solution here…


#11

Got it. Looks like your subscritpions are global and does not stop automatically. You have to stop your subscriptions every time they are unused. You can handle it with

Tracker.autorun(function() {
     if(!Meteor.userId()) {
        clearSubscriptions();
    }
})

#12

ok, doing it that way works… side comment… I removed all the checks for this.userId in the publish methods because it was actually preventing the session timeout (zuuk:stale-session) from working… but I don’t really need those checks in there anymore I guess.

Also, what did you mean by “your subscriptions are global” ?? is there a better way to do it?


#13

It’s much better if you are trying to prevent access to data to still use the this.userId checks. Otherwise the user could just open the client and subscribe to whatever publication they so choose.


#14

Looking at the zuuk:stale-session it doesn’t seem that a check for a logged in user would prevent it from working… It just clears the services.resume.loginTokens on the user document.


#15

@copleykj what do you mean by that ?

I tried in my console:

Meteor.subscribe(‘insuranceCompany’)

then
InsuranceCompany.find().count()
and I got 0

is this what you’re talking about?

EDIT: oh, I see, I just typed my publicaation name incorrectly… when I used
Meteor.subscribe(‘insuranceCompanies’);
then I see that it does indeed pull them up even if I"m logged out… ok, back to the drawing board… I’ll try to figure out why that broke the session timeout thing…


#16

Update… per my comment on how checking for this.userId in the publication broke the stale session plugin… I logged an issue and got a resolution. The trick was to return this.ready() once you have determined that the user is not logged in anymore.

if it helps anyone in the future.