Javascript 如何确定哪个会话I';我要在《流星》中重新验证OAuth?

Javascript 如何确定哪个会话I';我要在《流星》中重新验证OAuth?,javascript,meteor,Javascript,Meteor,我已经编写了自己的自定义身份验证来与我们的公司OAuth解决方案配合使用。这将导致向我发送OAuth访问和刷新令牌。然后,我可以将这些令牌存储在Meteor数据库的用户集合中,但是当我想要执行重新验证时,我需要能够找到正确的会话,以便能够找到我应该用于刷新它的OAuth令牌(如果需要)。由于用户可以从多个设备登录,这使问题变得复杂 这是我用来存储令牌并在服务器端发送结果的代码: var userId = null; var user = Meteo

我已经编写了自己的自定义身份验证来与我们的公司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
中返回的令牌与存储在DB中的令牌不同,因此我无法跟踪哪个会话是我的

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;
    }
});

我不是meteorJS开发人员,但我会尝试提出问题的解决方案。

使用npm安装meteor Cookie安装meteor 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;
或:


也许我的补充中有错误,但我想你已经理解了其中的诀窍。(:

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

至于您最初的问题,为什么客户端上的
result.token
与数据库中的不同:我认为您在比较未删除的令牌(
result.token
)到存储在数据库中的哈希令牌。如果是这种情况,您可以将
result.token
传递到服务器,并通过
帐户传递。\u hashLoginToken
,然后再在数据库中查找


这有意义吗?

以下是我最终如何将OAuth令牌与Meteor会话令牌对齐的

我在服务器端创建了以下
Meteor.methods
,我的客户端只需调用我
帐户的
validateResult
中的
updateToken
。callLoginMethod
就可以通过@emily在回答中描述的方法找到我的oauth令牌

每当应用程序启动或刷新时,它调用
reaauthenticateuser
,最后,当用户登录或会话超时时,它调用
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令牌后更新它们,或者在用户注销后删除它们。

您是否尝试在浏览器cookie中长期存储令牌以重新生成会话?问题不是存储令牌;问题是我从服务器返回的令牌与存储在中的令牌不同用户的集合,因此我无法有效地重新授权。当然,由于站点的安全规则,您不会获得相同的令牌。但是您可以存储令牌以供将来使用。哦,那么您是在建议我获得的令牌是存储在数据库中的真实令牌的代理吗?如果是这样,我如何使用存储在t上的令牌重新授权客户端?Meteor提供了这样做的方法吗?我不是Meteor dev,即使在另一个框架中,这个问题的解决方法也是一样的。尝试阅读如何在cookie中存储和检索数据,然后尝试检索存储在cookie令牌中的数据,然后在生成init令牌的块中使用。我认为每次都会生成inittoken等等这就是它变化的原因。因此,请尝试检查inittoken的cookie,如果它不存在,则生成它并放入cookie中以备将来使用。我认为有点脱节。Meteor有两个组件,服务器端和客户端。在服务器端,您对用户进行身份验证,并将生成的StampedLogingToken存储在DB中,然后将其返回到client端。然后客户端存储该令牌,就像我在上面用localstorage显示的那样。然后,当用户刷新应用程序时,我们从localstorage中提取令牌并将其发送到服务器,服务器将其与数据库中的令牌进行比较。如果相同,则传递;如果不相同,则重新验证。您似乎在此处显示设置cookie,但您可以不要在服务器上这样做。谢谢Emily…这是我一直在寻找的函数。但现在的问题是,它返回resume.loginTokens下的令牌,而不是我在上面代码的第一部分中创建的令牌。我觉得我在那里做错了什么。我尝试了不同的方法,但我始终无法使哈希恢复令牌与m对齐y OAuth令牌,以便我可以正确搜索。我已尝试使用这些帐户。\u hashLoginToken()但这对我来说是个错误。我觉得如果我可以将oauth和恢复哈希令牌一起存储在DB中,我就不需要这样做了。有什么办法可以有效地做到这一点吗?再进一步一点,我将
结果。令牌
发送回服务器,这与存储在DB中的不同。我运行
Accounts.\u hashLoginToken(result.token)
结果是
服务.resume.loginToken
下的hashedToken。但正如我在前面的评论中所引用的,这与
服务.oauth.loginTokens
中存储的令牌不同,这意味着我没有从resume令牌返回到oauth令牌的指针。我会一起保存它们,但看起来像我teor自己保存简历令牌。我想我可以编写一个post钩子来更改它。似乎有问题。对不起,我很困惑。你问题中的第一段代码(“我用来存储令牌并在服务器上发送结果的代码”)
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;
}