Javascript 使用访问令牌重置环回密码

Javascript 使用访问令牌重置环回密码,javascript,angularjs,node.js,loopbackjs,strongloop,Javascript,Angularjs,Node.js,Loopbackjs,Strongloop,我正在做一个使用环回作为框架的项目,包括用户和身份验证。我添加了一个在电子邮件中生成并发送的密码重置路由,一切似乎都正常工作。最近,我发现密码重置似乎不起作用。此处重置密码的过程如下: 用户的呼叫密码重置方法 从重置事件发送电子邮件,包括用户ID和访问令牌 从重置链接,将$http.defaults.headers.common.authorization设置为传递的令牌 调用user.prototype$updateAttributes(由lb ng生成)以基于表单更新密码属性 预期的行为

我正在做一个使用环回作为框架的项目,包括用户和身份验证。我添加了一个在电子邮件中生成并发送的密码重置路由,一切似乎都正常工作。最近,我发现密码重置似乎不起作用。此处重置密码的过程如下:

  • 用户的呼叫密码重置方法
  • 从重置事件发送电子邮件,包括用户ID和访问令牌
  • 从重置链接,将$http.defaults.headers.common.authorization设置为传递的令牌
  • 调用user.prototype$updateAttributes(由lb ng生成)以基于表单更新密码属性
预期的行为是在密码重置表单上更新密码。相反,我得到的授权错误是401或500(似乎来回)。我注意到,在发送到API的实际头中,授权令牌与我从路由传递的内容不匹配。尝试使用LoopBackAUth.setUser进行设置无效,并且在实际发送请求之前也不会更新授权属性

当它第一次被添加时,我确实花了时间来测试它,我不知道会有什么变化来打破它。我一直在遵循“环回常见问题解答用户管理”中的示例,但在该示例中,我们有一个角度的前端,而不是服务器端视图

编辑:

我尝试完全打开ACL,看看是否可以更新我的用户对象(从用户继承,但它是自己的类型)的密码(或任何属性)。当我尝试这样做的时候,我仍然得到了401

编辑#2:

下面是我的ACL和如何调用它的示例代码

来自模型定义的ACL

...
{
    "accessType": "*",
    "principalType": "ROLE",
    "principalId": "$owner",
    "permission": "ALLOW"
},
{
    "accessType": "EXECUTE",
    "principalType": "ROLE",
    "principalId": "$owner",
    "permission": "ALLOW",
    "property": "updateAttributes"
}
...
auth.js

...
resetPassword: function(user) {
    return MyUser.prototype$updateAttributes(user, user).$promise;
}
...

找出问题所在。在我们的应用程序服务器中,我们没有使用环回的令牌中间件。添加
app.use(loopback.token())在启动服务器之前,会导致重置链接中提供的访问令牌按预期工作

@Elvis让我走上了正确的道路。这里有一个更完整的答案供其他遇到这个问题的人参考。环回文档在这方面非常有限

确保您在电子邮件中同时获得用户id和令牌,并在表单中填充它们

从表单中,以下代码执行此任务:

 function resetPassword(id, token, password) {
  $http.defaults.headers.common.authorization = token;

  return User
    .prototype$updateAttributes({id:id}, {
     password: password
   })
   .$promise;

}

虽然上述所有答案都将被证明是有帮助的,但请注意,在验证过程中,当它被证明无效时,会出现回送。代币将不见了。因此,当您正在努力解决401的问题时,请确保每次尝试新的代码迭代时都创建了一个新的密码重置令牌

否则,您可能会发现自己正在使用完全健康的代码来更改密码,但使用的令牌在代码的上一次迭代中已被删除,从而导致错误的结论,即当您看到另一个401时,您需要处理代码


在我的特殊情况下,访问令牌存储在SQL Server数据库中,由于引入了时区问题,该令牌总是会立即过期,因为我已将其设置为false。这会导致所有新令牌在过去为7200秒,这比密码重置令牌有效的900秒还要多。我没有注意到这些代币立即被销毁,并得出结论,当我看到401的回报时,我的代码仍然存在问题。事实上,401是由使用服务器上已经存在的令牌引起的

这比应该的要复杂得多。以下是我的完整解决方案:

1) 我在服务器端公开了一个新方法,该方法从令牌更新密码

Member.updatePasswordFromToken = (accessToken, __, newPassword, cb) => {
  const buildError = (code, error) => {
    const err = new Error(error);
    err.statusCode = 400;
    err.code = code;
    return err;
  };

  if (!accessToken) {
    cb(buildError('INVALID_TOKEN', 'token is null'));
    return;
  }

  Member.findById(accessToken.userId, function (err, user) {
    if (err) {
      cb(buildError('INVALID_USER', err));
      return;
    };
    user.updateAttribute('password', newPassword, function (err, user) {
      if (err) {
        cb(buildError('INVALID_OPERATION', err));
        return;
      }

      // successful,
      // notify that everything is OK!
      cb(null, null);
    });
  });
}
我还定义了可访问性:

Member.remoteMethod('updatePasswordFromToken', {
  isStatic: true,
  accepts: [
    {
      arg: 'accessToken',
      type: 'object',
      http: function(ctx) {
        return ctx.req.accessToken;
      }
    },
    {arg: 'access_token', type: 'string', required: true, 'http': { source: 'query' }},
    {arg: 'newPassword', type: 'string', required: true},      
  ],
  http: {path: '/update-password-from-token', verb: 'post'},
  returns: {type: 'boolean', arg: 'passwordChanged'}
});
在客户端,我只是这样称呼它:

this.memberApi.updatePasswordFromToken(token, newPassword);

我完全被这件事弄糊涂了。为什么我不能更新我自己的任何属性?你能附加一些代码吗?401似乎表明你没有被授权在这里做一些事情,包括相关的,微小的部分。你能更具体地说,我需要在哪里改变什么?我也有同样的问题,但仍然不知道你做了什么,使这个work@EdmundoDelGusto将其添加到
boot/server.js
文件中,在
app.start
函数示例之前,用于环回中的示例用户管理,您需要在电子邮件连接器中设置电子邮件和密码。整洁地给出每一件事,你在哪里添加这个函数?在模型定义中,我对远程方法声明做了一个小的更改,但总体上是相同的代码。我没有使用{arg:'accessToken',type:'object'…},而是将整个请求发送到我的方法,并从那里获取令牌ID