繁体   English   中英

如何确定我正在Meteor中进行OAuth重新身份验证的会话?

[英]How to determine which session I'm on for OAuth reauthentication in Meteor?

我已经编写了自己的自定义身份验证以与我们的公司OAuth解决方案一起使用。 这样会导致向我发送OAuth访问和刷新令牌。 然后,我可以将这些令牌存储在Meteor数据库的用户集合中,但是当我想执行重新身份验证时,我需要能够找到正确的会话,以便能够找到需要用来刷新它的OAuth令牌。 由于用户可以从多个设备登录,因此使事情变得复杂。

这是我用于存储令牌并在服务器端发送结果的代码:

            var userId = null;
            var user = Meteor.users.findOne({username: userName});
            if (!user) {
                userId = Meteor.users.insert({username: userName});
            } else {
                userId = user._id;
            }
            logger.info("User logged in: " + userId);

            var initToken = Accounts._generateStampedLoginToken();
            var token = Accounts._hashStampedToken(initToken);
            token.accessToken = result.data.access_token;
            token.refreshToken = result.data.refresh_token;
            token.ttl = result.data.expires_in;

            // Need way to bind oath.loginTokens with Meteor resume token
            Meteor.users.update(userId,
                {$push: {'services.oauth.loginTokens': token}}
            );

            var rslt = {
                userId: userId
            };
            return(rslt);

这是数据库中的结果记录:

"services" : {
    "oauth" : {
        "loginTokens" : [ 
            {
                "when" : ISODate("2014-06-17T17:51:24.635Z"),
                "hashedToken" : "ErcosEo9rD+IuT3EyFb3DFS8Bf0enwLzkCIf/nP1JFE=",
                "accessToken" : "bhafr3WBDS67EmZ9hFE20af83BJRPFQQS8NGpMlSH6NHVCOiTeTuTJ",
                "refreshToken" : "enOAFkBcxB88FlATUh2m0E5NLLG0y8AojyIH5gItnJXdU6",
                "ttl" : 3600
            }
        ]
    },
    "resume" : {
        "loginTokens" : [ 
            {
                "when" : ISODate("2014-06-17T17:51:24.637Z"),
                "hashedToken" : "uhRZpGdBHnAVKvgBEm7oSWsdflOGRI2YrR9Q21iqjzp+Xc="
            }
        ]
    }
},
"username" : "lous"

从上面的内容中可以看到,我需要取消标记值之一的查找,以找到正确的oauth信息以进行可能的刷新。 然后,在客户端上,我执行以下所示的操作,但是问题是validateResult返回的令牌与存储在数据库中的令牌不同,因此我无法跟踪属于我的会话。

Template.login.events({
    'submit #login-form': function(e,t) {
        e.preventDefault();
        var id = t.find('#login-id').value,
            password = t.find('#login-password').value;

        var req = {id: id, password: password};

        Accounts.callLoginMethod({
            methodArguments: [req],
            validateResult: function (result) {
                var token = result.token;
                window.localStorage.setItem('token', token);

                subscribeToRequests();
                $.mobile.changePage('#landingPage', {transition: 'slidefade'});
            },
            userCallback: function(error) {
                if (error) {
                    console.log("Error: " + error.message);
                    alert("Login Failure");
                } 
            }
        });
        return false;
    }
});

为什么令牌会不一样? 关于如何解决此问题的任何建议? 然后,一旦我将令牌存储在客户端,Meteor是否提供了一种开箱即用的方式来测试令牌的有效性? 这是我用来尝试执行此操作的findUser方法:

Meteor.methods({
    findUser: function(token) {
        var user = null;

        var hashedToken = Accounts._hashLoginToken(token);
        if (this.userId) {
            //TODO need user object to include token to do TTL check and reauth if necessary
            user = Meteor.users.findOne({_id:this.userId});
            var result = refreshUser(user);
            if (result.err) {
                throw { name: 'System Error', message: 'The following error occurred: ' + result.err
                };
            }
        } else {
            throw { name: 'System Error', message: 'No userId available. Please try again.'
            };
        }
        return user;
    }
});

在您的findUser方法中,您可以调用Accounts._getLoginToken(this.connection.id)以获取该连接的当前登录令牌。 然后,您可以查找与此值关联的OAuth访问令牌。

关于您的原始问题,为什么客户端上的result.token与数据库中的不同:我认为您正在将未哈希的令牌( result.token )与数据库中存储的哈希令牌进行比较。 如果是这种情况,您可以将result.token传递到服务器,并通过Accounts._hashLoginToken传递给它,然后再在数据库中查找它。

那有意义吗?

这就是我最终将OAuth令牌与Meteor会话令牌对齐的方式。

我在服务器端创建了以下Meteor.methods ,客户端仅在Accounts.callLoginMethodvalidateResult中调用updateToken ,因此可以通过@emily在其答案中描述的方法找到我的oauth令牌。

它调用reauthenticateUser每当应用程序启动或刷新最后,它调用logoutUser当用户登录我们或会话超时。

updateToken: function() {
    // Update oauth hash token with correct hashed token
    var user = Meteor.users.findOne({'_id': this.userId});
    var hashedToken = Accounts._getLoginToken(this.connection.id);

    // Get last element for OAuth array (safely presuming the last one is the last oauth from current call stack) and update hashedToken
    var oauthObj = _.last(user.services.oauth.loginTokens);

    Meteor.users.update({'services.oauth.loginTokens': {$elemMatch: {hashedToken: oauthObj.hashedToken}}}, {$set: {'services.oauth.loginTokens.$.hashedToken': hashedToken}});
},
reauthenticateUser: function() {
    var user = null;
    if (this.userId) {
        var hashedToken = Accounts._getLoginToken(this.connection.id);
        user = Meteor.users.findOne({$and: [{'_id': this.userId}, {'services.oauth.loginTokens': {$elemMatch: {hashedToken: hashedToken}}}]});

        // Get specific oauthTokens (keep in mind multiples per client)
        var oauthTokens = _.findWhere(user.services.oauth.loginTokens, {'hashedToken': hashedToken});
        var result = refreshUser(this.userId, user.username, oauthTokens);

        if (result.err) {
            throw { name: 'System Error', message: 'The following error occurred: ' + result.err
            };
        }
    } else {
        throw { name: 'System Error', message: 'No userId available. Please try again.'
        };
    }
    return user;
},
logoutUser: function() {
    var hashedToken = Accounts._getLoginToken(this.connection.id);
    // Remove orphaned Oauth tokens
    Meteor.users.update(
        {$and: [{'_id': this.userId}, {'services.oauth.loginTokens': {$elemMatch: {hashedToken: hashedToken}}}]},
        {$pull: {'services.oauth.loginTokens': {'hashedToken':hashedToken}
        }});
    return true;
}

一旦设置好,对我来说,很容易在刷新oauth令牌后更新它们,或者在用户注销后将其删除。

我不是meteorJS开发人员,但我将尝试建议解决问题的方法。

使用npm安装流星cookie来安装流星cookie。
接着:

        var initToken = Cookie.get('initToken');
        if(!initToken) {
            initToken = Accounts._generateStampedLoginToken();
            Cookie.set('initToken', initToken, {days: 30});
        }
        var token = Accounts._hashStampedToken(initToken);
        token.accessToken = result.data.access_token;
        token.refreshToken = result.data.refresh_token;
        token.ttl = result.data.expires_in;

要么:

        var token = Cookie.get('token');
        if(!token) {
            var initToken = Accounts._generateStampedLoginToken();
            token = Accounts._hashStampedToken(initToken);
            Cookie.set('token', token, {days: 30});
        }
        token.accessToken = result.data.access_token;
        token.refreshToken = result.data.refresh_token;
        token.ttl = result.data.expires_in;

也许我添加的内容有误,但我认为您已经理解了窍门。 (:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM