【问题标题】:How can I log out a user from the server in Meteor.js?如何从 Meteor.js 中的服务器注销用户?
【发布时间】:2018-04-06 17:32:46
【问题描述】:

在我的 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.");
        }

在我的 application.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.");
        }

在我的 application.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;
        }
    }
});

【问题讨论】:

    标签: javascript meteor


    【解决方案1】:

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

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

    有几点:

    • 这将注销所有用户,包括当前登录的用户。
    • 它只适用于服务器端

    【讨论】:

    • 我马上试试这个!谢谢你的快速反应。顺便说一句,这是否记录在任何地方?
    • 我认为它没有记录在案,但 Meteor 使用 loginTokens 中的值来识别已登录的用户。因此,没有它们,用户将被注销,因为一切都是被动的
    • 有时它就像一个魅力,重新呈现用户视图并将用户重定向到登录页面。但其他时候,用户仍然可以在“限制区域”内四处走动。我必须刷新用户才能看到它已注销。我该如何解决这个问题?
    • @user2602152 在受限区域中,您需要检查用户是否响应式登录,如果没有则显示消息。如果您已经这样做了,请查看 javascript 控制台,看看是否有任何错误可能会阻止模板更改。
    • 注意现在是:db.users.update({}, {$set : { "services.resume.loginTokens" : [] }}, {multi:true});
    【解决方案2】:

    退出除当前用户(您)以外的所有人

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

    【讨论】:

    • 在流星 1.8 中,我必须同时清除 "resume.loginTokens""services.resume.loginTokens"
    【解决方案3】:

    我最近遇到了类似的问题 - 在删除当前登录用户的恢复令牌后,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();
    }
    

    【讨论】:

    • 哇哦!我们在一个非常庞大的流星项目中也有同样的事情,我们现在希望在服务器端注销时有更好的用户体验,并且想知道为什么Meteor.user() 根本没有接受更改(当然有解决方法,但它们很丑)。非常感谢您的详细解答!
    猜你喜欢
    • 2013-07-29
    • 1970-01-01
    • 2015-07-09
    • 2013-08-28
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多