如何从Meteor.js中的服务器注销用户

How can I log out a user from the server in Meteor.js?

本文关键字:服务器 注销 用户 js Meteor      更新时间:2024-06-27

在我的Meteor.js应用程序中,我想让管理员能够强制注销用户。

用例是,我的应用程序正在为最终用户服务,每当超级用户登录时,该服务都会打开。如果超级用户忘记明确注销,则该服务似乎对最终用户开放。如果管理员看到了这一点,他/她应该能够强制注销已登录的用户,从而为最终用户关闭服务。

Meteor.js有可能做到这一点吗?如果是,如何?对于这个用例,是否有更好/其他的方法?

编辑:添加了一些我尝试过的远程注销示例,为@Akshat澄清。

示例1(不能按我的意愿工作):

在注销方法中:

if (user.profile.role === ROLES.ADMIN) {
            Meteor
                .users
                .update({
                    _id: options.userId
                }, 
                { 
                    $set: { 
                        'services.resume.loginTokens' : [] 
                }});
        } else {
            throw new Meteor.Error(403, "You are not allowed to access this.");
        }

在我的应用程序.js:中

var lastUserId;
Deps.autorun(function () {
    if(Meteor.user()) {
        if (Meteor.user().profile && Meteor.user().profile.firstName) {
            console.log("USER LOGGED IN");
            console.log("LENGTH LOGINTOKENS", 
                    Meteor
                        .user()
                        .services
                        .resume
                        .loginTokens.length); // This is always 1
            lastUserId = Meteor.user()._id;
            if (Meteor.user().services.resume.loginTokens.length === 0) {
                // This never fires, and thus the client does not know until
                // manually refreshed. Of course I could keep a forceLogOut-variable
                // as done in the next example.
                window.location.reload();
            }
        }
    } else {
        console.log("SOMETHING CHANGED IN METEOR.USER");
        if (lastUserId) {
            console.log("THE USER IS LOGGED OUT");
            Meteor.call('userLoggedOut',
            {
                userId: lastUserId
            });
            lastUserId = null;
        }
    }
});

示例2(当在客户端只使用forceLogOut和Meteor.logout()时,这可以按我的意愿工作。):

在注销方法中:

if (user.profile.role === ROLES.ADMIN) {
            Meteor
                .users
                .update({
                    _id: options.userId
                }, 
                { 
                    $set: { 
                        'services.resume.loginTokens' : [],
                        'profile.forceLogOut': true
                }});
        } else {
            throw new Meteor.Error(403, "You are not allowed to access this.");
        }

在我的应用程序.js:中

var lastUserId;
Deps.autorun(function () {
    if(Meteor.user()) {
        if (Meteor.user().profile && Meteor.user().profile.firstName) {
            console.log("USER LOGGED IN");
            console.log("LENGTH LOGINTOKENS", 
                    Meteor
                        .user()
                        .services
                        .resume
                        .loginTokens.length); // This is always 1
            lastUserId = Meteor.user()._id;
            if (Meteor.user().profile.forceLogOut) {
                // Small example 1:
                // When logintokens have been set to [], and forceLogOut
                // is true, we need to reload the window to show the user
                // he is logged out.
                window.location.reload();
                // END Small example 1.
                // Small example 2:
                // When already keeping this variable, I might as well just use
                // this variable for logging the user out, and no resetting of
                // loginTokens are needed, or reloading the browser window.
                // This seems to me as the best way.
                console.log("FORCING LOGOUT");
                Meteor.logout();
                // END Small example 2.
                // And finally resetting the variable
                Meteor.call('resetForceLogOut',
                    {
                        userId: Meteor.user()._id
                    });
           }
        }
    } else {
        console.log("SOMETHING CHANGED IN METEOR.USER");
        if (lastUserId) {
            console.log("THE USER IS LOGGED OUT");
            Meteor.call('userLoggedOut',
            {
                userId: lastUserId
            });
            lastUserId = null;
        }
    }
});

您必须从数据库中删除所有loginTokens。它将为具有此查询的所有用户执行此操作。如果要注销较小的用户子集或排除当前用户,则可以自定义选择器。

Meteor.users.update({}, {$set : { "services.resume.loginTokens" : [] }}, {multi:true});

几件事:

  • 这将注销包括当前登录用户在内的所有用户
  • 它只在服务器端工作

注销所有人,但不注销当前用户:

Meteor.users.update({
    _id: {
        $ne: Meteor.user()._id
    }
}, {
    $set: {
        "services.resume.loginTokens": []
    }
}, {
    multi: true
});

我最近遇到了类似的问题-在删除当前登录用户的恢复令牌后,Tracker.autorun无法(在这种情况下应该如此)检测Meteor.userId()中的更改,如下代码所示:

Tracker.autorun(() => {
  console.log('currrent user', Meteor.userId());
});

事实证明,问题是由登录用户订阅的某个发布引起的。在路由相关代码的某个地方(我使用的是Iron路由器),我有:

export const AppController = RouteController.extend({
  waitOn() {
    if (!Meteor.userId()) {
      return Router.go('signIn');
    }
    Meteor.subscribe('data'),
  },
});

发布代码为:

Meteor.publish('data', function () {
  if (!this.userId) {
    return; // this line caused the logout bug
  }
  return MyCollection.find();
}

该错误是由于在未设置this.userId时返回未定义(而不是空数组)而导致的,这导致发布永远无法准备好。出于某种奇怪的原因,这也导致Tracker在删除恢复令牌时没有启动。

所以修复方法是:

Meteor.publish('data', function () {
  if (!this.userId) {
    return []; // this is the correct way to return empty set
  }
  return MyCollection.find();
}