19

Is there any way to pick up when a user logs out of the website? I need to do some clean up when they do so. Using the built-in meteor.js user accounts.

I'll be doing some validation using it, so I need a solution that cannot be trigger on behalf of other users on the client side - preferably something completely server side.

Evan Knowles
  • 7,426
  • 2
  • 37
  • 71
  • Maybe this answer your question: http://stackoverflow.com/questions/10257958/server-cleanup-after-a-client-disconnects – Peppe L-G Jul 29 '13 at 12:47
  • That's very close, but I do want to make sure it's only when they actively log out unfortunately. – Evan Knowles Jul 29 '13 at 13:20
  • this could help: http://stackoverflow.com/questions/22900405/how-to-redirect-after-user-has-just-logged-in-or-just-logged-out?answertab=votes#tab-top – dm76 Sep 22 '14 at 09:44

6 Answers6

9

You may use Deps.autorun to setup a custom handler observing Meteor.userId() reactive variable changes.

Meteor.userId() (and Meteor.user()) are reactive variables returning respectively the currently logged in userId (null if none) and the corresponding user document (record) in the Meteor.users collection.

As a consequence one can track signing in/out of a Meteor application by reacting to the modification of those reactive data sources.

client/main.js :

var lastUser=null;

Meteor.startup(function(){
    Deps.autorun(function(){
        var userId=Meteor.userId();
        if(userId){
            console.log(userId+" connected");
            // do something with Meteor.user()
        }
        else if(lastUser){
            console.log(lastUser._id+" disconnected");
            // can't use Meteor.user() anymore
            // do something with lastUser (read-only !)
            Meteor.call("userDisconnected",lastUser._id);
        }
        lastUser=Meteor.user();
    });
});

In this code sample, I'm setting up a source file local variable (lastUser) to keep track of the last user that was logged in the application. Then in Meteor.startup, I use Deps.autorun to setup a reactive context (code that will get re-executed whenever one of the reactive data sources accessed is modified). This reactive context tracks Meteor.userId() variation and reacts accordingly.

In the deconnection code, you can't use Meteor.user() but if you want to access the last user document you can use the lastUser variable. You can call a server method with the lastUser._id as argument if you want to modify the document after logging out.

server/server.js

Meteor.methods({
    userDisconnected:function(userId){
        check(userId,String);
        var user=Meteor.users.findOne(userId);
        // do something with user (read-write)
    }
});

Be aware though that malicious clients can call this server method with anyone userId, so you shouldn't do anything critical unless you setup some verification code.

saimeunt
  • 22,666
  • 2
  • 56
  • 61
  • Hey - in this case I do need to avoid malicious clients being able to call it, as it would have the effect of logging a player out of the game which I obviously can't allow people to do to one another. Any idea as to how I could go about setting up verification code and tying it to a specific user? – Evan Knowles Jul 29 '13 at 13:17
7

Use the user-status package that I've created: https://github.com/mizzao/meteor-user-status. This is completely server-side.

See the docs for usage, but you can attach an event handler to a session logout:

UserStatus.events.on "connectionLogout", (fields) ->
  console.log(fields.userId + " with connection " + fields.connectionId + " logged out")

Note that a user can be logged in from different places at once with multiple sessions. This smart package detects all of them as well as whether the user is online at all. For more information or to implement your own method, check out the code.

Currently the package doesn't distinguish between browser window closes and logouts, and treats them as the same.

Lucidity
  • 1,299
  • 17
  • 19
Andrew Mao
  • 35,740
  • 23
  • 143
  • 224
  • Thanks - I'l definitely have a look! – Evan Knowles Jul 29 '13 at 19:29
  • 1
    it's a cool package. Any idea how I can implement event triggers only on user login/logout excluding browser/window close? any hint/direction would be awesome. thanks @andrew-mao – Foysal Ahamed Nov 16 '13 at 14:04
  • How can I redirect User to some specific route when user get himself logged out ? – mfq Nov 11 '14 at 13:45
  • @mfq you can use the reactivity of `Meteor.user()`, which will change to `undefined` when the client logs out. See saimeunt's answer to this question. – Andrew Mao Nov 11 '14 at 18:57
6

We had a similar, though not exact requirement. We wanted to do a bit of clean up on the client when they signed out. We did it by hijacking Meteor.logout:

if (Meteor.isClient) {
  var _logout = Meteor.logout;
  Meteor.logout = function customLogout() {
    // Do your thing here
    _logout.apply(Meteor, arguments);
  }
}
u2622
  • 2,991
  • 3
  • 25
  • 27
  • This is quote simple and works really well. I just wanted to redirect the 'loged out' user to home page and this was and easy + clean approach. – Diego Feb 25 '16 at 15:15
2

The answer provided by @saimeunt looks about right, but it is a bit fluffy for what I needed. Instead I went with a very simple approach like this:

if (Meteor.isClient) {
    Deps.autorun(function () {
        if(!Meteor.userId())
        {
            Session.set('store', null);
        }
    });
}

This is however triggered during a page load if the user has not yet logged in, which might be undesirable. So you could go with something like this instead:

if (Meteor.isClient) {
    var userWasLoggedIn = false;
    Deps.autorun(function (c) {
        if(!Meteor.userId())
        {
            if(userWasLoggedIn)
            {
                console.log('Clean up');
                Session.set('store', null);
            }
        }
        else
        {
            userWasLoggedIn = true;
        }
    });
}
Bob Davies
  • 2,229
  • 1
  • 19
  • 28
  • It seems like it would be nice to put the deps.autorun registration inside the onLogin handler, that way you only register it once you know the user has signed in. good stuff though! – Derek Oct 27 '15 at 18:39
1

None of the solutions worked for me, since they all suffered from the problem of not being able to distinguish between manual logout by the user vs. browser page reload/close.

I'm now going with a hack, but at least it works (as long as you don't provide any other means of logging out than the default accounts-ui buttons):

Template._loginButtons.events({
    'click #login-buttons-logout': function(ev) {
        console.log("manual log out");
        // do stuff
    }
});
Christian Fritz
  • 20,641
  • 3
  • 42
  • 71
  • Really interesting. Do you need `aldeed:template-extension` or similar package in order to extend/overwrite the functionality of the templates in the _accounts_ package? – Diego Feb 24 '16 at 19:53
  • Thanks, this also did what I needed perfectly! – jremi May 07 '16 at 20:27
-2

You can use the following Meteor.logout - http://docs.meteor.com/#meteor_logout

Almog
  • 2,639
  • 6
  • 30
  • 59