使用访问令牌重置环回密码
Reset Loopback Password with Access Token
我正在开发一个使用 Loopback 作为框架并包括用户和身份验证的项目。我添加了生成的密码重置路由并通过电子邮件发送,一切似乎都正常工作。最近,我发现密码重置似乎不起作用。这里重置密码的过程是:
- 为用户调用密码重置方法
- 从重置事件发送电子邮件,包括用户 ID 和访问令牌
- 从重置 link 开始,将 $http.defaults.headers.common.authorization 设置为传递的令牌
- 调用user.prototype$updateAttributes(由lb-ng生成)更新基于表单的密码属性
预期的行为是在密码重置表单上更新密码。相反,我得到一个授权错误,作为 401 或 500(似乎来回)。我注意到在发送到 API 的实际 headers 中,授权令牌与我从路由中传递的内容不匹配。尝试使用 LoopBackAUth.setUser 设置它不起作用,在实际发送请求之前也不会更新授权 属性。
我在第一次添加时确实花了时间测试它,但我无法弄清楚会发生什么变化来破坏它。我一直在关注 loopback-faq-user-management 中的示例,但我们有 Angular front-end 而不是该示例中的服务器端视图。
编辑:
我尝试完全打开 ACL,看看是否可以更新我的用户 object(继承自 User,但属于自己的类型)的密码(或任何属性)。尝试执行此操作时,我仍然收到 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;
}
...
找出问题所在。在我们应用程序的服务器中,我们没有使用 Loopback 的令牌中间件。在启动服务器之前添加 app.use(loopback.token());
会导致重置 link 中提供的访问令牌按预期工作!
@OverlappingElvis 让我走上了正确的轨道。这是针对其他 运行 的更完整答案。环回文档在这方面非常有限。
确保您在电子邮件中收到用户 ID 和令牌,并在表单中填充这些内容。
表单中的以下代码完成了这项工作:
function resetPassword(id, token, password) {
$http.defaults.headers.common.authorization = token;
return User
.prototype$updateAttributes({id:id}, {
password: password
})
.$promise;
}
虽然上述所有答案都将被证明是有帮助的,但请注意 Loopback destroys a token during validation when it prove it to be invalid 。令牌将消失。因此,当您尝试解决 401 问题时,请确保每次尝试新的代码迭代时都创建了一个新的密码重置令牌。
否则,您可能会发现自己正在查看非常健康的代码来更改密码,但使用的令牌在之前的代码迭代中已被删除,从而导致您得出错误的结论,即您需要在以下时间处理您的代码你看到另一个 401.
在我的特定情况下,访问令牌存储在 SQL 服务器数据库中,并且由于引入的时区问题,令牌总是会立即过期,因为我将 options.useUTC 设置为错误的。这导致所有新令牌过去 7200 秒,比密码重置令牌有效的 900 秒多。我没有注意到这些令牌立即被销毁并得出结论,我的代码仍然存在问题,因为我在 return 中看到了 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);
我正在开发一个使用 Loopback 作为框架并包括用户和身份验证的项目。我添加了生成的密码重置路由并通过电子邮件发送,一切似乎都正常工作。最近,我发现密码重置似乎不起作用。这里重置密码的过程是:
- 为用户调用密码重置方法
- 从重置事件发送电子邮件,包括用户 ID 和访问令牌
- 从重置 link 开始,将 $http.defaults.headers.common.authorization 设置为传递的令牌
- 调用user.prototype$updateAttributes(由lb-ng生成)更新基于表单的密码属性
预期的行为是在密码重置表单上更新密码。相反,我得到一个授权错误,作为 401 或 500(似乎来回)。我注意到在发送到 API 的实际 headers 中,授权令牌与我从路由中传递的内容不匹配。尝试使用 LoopBackAUth.setUser 设置它不起作用,在实际发送请求之前也不会更新授权 属性。
我在第一次添加时确实花了时间测试它,但我无法弄清楚会发生什么变化来破坏它。我一直在关注 loopback-faq-user-management 中的示例,但我们有 Angular front-end 而不是该示例中的服务器端视图。
编辑:
我尝试完全打开 ACL,看看是否可以更新我的用户 object(继承自 User,但属于自己的类型)的密码(或任何属性)。尝试执行此操作时,我仍然收到 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;
}
...
找出问题所在。在我们应用程序的服务器中,我们没有使用 Loopback 的令牌中间件。在启动服务器之前添加 app.use(loopback.token());
会导致重置 link 中提供的访问令牌按预期工作!
@OverlappingElvis 让我走上了正确的轨道。这是针对其他 运行 的更完整答案。环回文档在这方面非常有限。
确保您在电子邮件中收到用户 ID 和令牌,并在表单中填充这些内容。
表单中的以下代码完成了这项工作:
function resetPassword(id, token, password) {
$http.defaults.headers.common.authorization = token;
return User
.prototype$updateAttributes({id:id}, {
password: password
})
.$promise;
}
虽然上述所有答案都将被证明是有帮助的,但请注意 Loopback destroys a token during validation when it prove it to be invalid 。令牌将消失。因此,当您尝试解决 401 问题时,请确保每次尝试新的代码迭代时都创建了一个新的密码重置令牌。
否则,您可能会发现自己正在查看非常健康的代码来更改密码,但使用的令牌在之前的代码迭代中已被删除,从而导致您得出错误的结论,即您需要在以下时间处理您的代码你看到另一个 401.
在我的特定情况下,访问令牌存储在 SQL 服务器数据库中,并且由于引入的时区问题,令牌总是会立即过期,因为我将 options.useUTC 设置为错误的。这导致所有新令牌过去 7200 秒,比密码重置令牌有效的 900 秒多。我没有注意到这些令牌立即被销毁并得出结论,我的代码仍然存在问题,因为我在 return 中看到了 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);