在 Meteor 中存储未决用户密码的安全方法
Secure way to store pending user's password in Meteor
对于我的 Meteor 应用程序,我希望有以下注册过程:
- 用户注册用户名、电子邮件和密码。 (他还不能登录。)
- 已发送确认邮件 [
Accounts.sendEnrollmentEmail
]
- 用户确认电子邮件 [
Accounts.onEnrollmentLink
]
- 用户已创建。 [
Accounts.createUser
] (他可以登录了。)
为了实现这一点,我觉得我必须将 纯文本 密码存储在 table 临时用户(步骤 1)中,以便稍后创建实际用户(第 3 步)。显然这是一个糟糕的想法。
我当然可以只要求输入第 3 步的密码并立即创建用户 - 但这不是我想要实现的行为。
因此:是否有适当的方法来安全地存储密码以便稍后将其传递给用户创建?或者有没有办法创建不可登录的用户?
当您使用内置方法创建用户时,Meteor 提供了保存密码存储所需的一切,因此您无需自己做太多事情。所以你应该从一开始就使用这些方法(你的第 1 步:Accounts.createUser
,第 2 步:Accounts.sendVerificationEmail
,第 3 步:Accounts.verifyEmail
,第 4 步不再是必需的)。
现在要到达您想去的地方,您可以使用 David Weldon 建议的方法,但在服务器端使用 Accounts.validateLoginAttempt
。这更容易一些,首先不允许登录。
例如,您可以在服务器端使用此代码:
Accounts.validateLoginAttempt(function(loginAttempt){
if (!loginAttempt.allowed) {
// Only tell the user that something went wrong but not what to enhance security
throw new Meteor.Error(901, 'Your login credentials are wrong. Try again.');
} else {
// In some cases this method isn't invoked with a correct user object...
if (!loginAttempt.user) {
throw new Meteor.Error(902, 'No valid user object. Make sure to validate your email address first.');
}
// If email verification is required check if the user has a valid email address and don't allow the login if he has none
if (!loginAttempt.user.emails[0].verified) {
throw new Meteor.Error(902, 'Your email address has to be verified first.');
}
// We have a correct login!
return true;
}
});
现在在客户端,您可以使用这样的逻辑进行登录
Meteor.loginWithPassword(email, password, function(callback) {
if (callback === undefined) {
// Your login logic
} else if (callback.error == 902) {
// Your "not verfied" logic
} else {
// Your other login errors logic
}
}
请注意,您可能还需要稍微调整注册过程,因为 Meteor 默认情况下会尝试在注册后直接登录用户,但这将不再可能。
另请注意,您可以使用 Accounts.validateLoginAttempt
不止于此。例如,您还可以在此处实现一个逻辑,只允许来自同一 IP 的一定数量的错误登录尝试。
我们根据帐户包在我们的应用中使用了稍微不同的模式
- 用户注册
- 用户正常登录
出主站模板条件内容与
<template name="main">
{{#if currentUser}}
{{#if verified }}
...
{{else}}
Notice to user to look for their verification email
{{/if}}
{{/if}}
</template>
基于辅助函数
Template.main.helpers({
verified: function() { return Meteor.user().emails[0].verified; }
});
这满足了用户在通过验证之前不能做任何事情的要求,但仍以简单安全的方式使用帐户包。
我也可以看到使用 iron:router 采取相关方法。
对于我的 Meteor 应用程序,我希望有以下注册过程:
- 用户注册用户名、电子邮件和密码。 (他还不能登录。)
- 已发送确认邮件 [
Accounts.sendEnrollmentEmail
] - 用户确认电子邮件 [
Accounts.onEnrollmentLink
] - 用户已创建。 [
Accounts.createUser
] (他可以登录了。)
为了实现这一点,我觉得我必须将 纯文本 密码存储在 table 临时用户(步骤 1)中,以便稍后创建实际用户(第 3 步)。显然这是一个糟糕的想法。
我当然可以只要求输入第 3 步的密码并立即创建用户 - 但这不是我想要实现的行为。
因此:是否有适当的方法来安全地存储密码以便稍后将其传递给用户创建?或者有没有办法创建不可登录的用户?
当您使用内置方法创建用户时,Meteor 提供了保存密码存储所需的一切,因此您无需自己做太多事情。所以你应该从一开始就使用这些方法(你的第 1 步:Accounts.createUser
,第 2 步:Accounts.sendVerificationEmail
,第 3 步:Accounts.verifyEmail
,第 4 步不再是必需的)。
现在要到达您想去的地方,您可以使用 David Weldon 建议的方法,但在服务器端使用 Accounts.validateLoginAttempt
。这更容易一些,首先不允许登录。
例如,您可以在服务器端使用此代码:
Accounts.validateLoginAttempt(function(loginAttempt){
if (!loginAttempt.allowed) {
// Only tell the user that something went wrong but not what to enhance security
throw new Meteor.Error(901, 'Your login credentials are wrong. Try again.');
} else {
// In some cases this method isn't invoked with a correct user object...
if (!loginAttempt.user) {
throw new Meteor.Error(902, 'No valid user object. Make sure to validate your email address first.');
}
// If email verification is required check if the user has a valid email address and don't allow the login if he has none
if (!loginAttempt.user.emails[0].verified) {
throw new Meteor.Error(902, 'Your email address has to be verified first.');
}
// We have a correct login!
return true;
}
});
现在在客户端,您可以使用这样的逻辑进行登录
Meteor.loginWithPassword(email, password, function(callback) {
if (callback === undefined) {
// Your login logic
} else if (callback.error == 902) {
// Your "not verfied" logic
} else {
// Your other login errors logic
}
}
请注意,您可能还需要稍微调整注册过程,因为 Meteor 默认情况下会尝试在注册后直接登录用户,但这将不再可能。
另请注意,您可以使用 Accounts.validateLoginAttempt
不止于此。例如,您还可以在此处实现一个逻辑,只允许来自同一 IP 的一定数量的错误登录尝试。
我们根据帐户包在我们的应用中使用了稍微不同的模式
- 用户注册
- 用户正常登录
出主站模板条件内容与
<template name="main">
{{#if currentUser}}
{{#if verified }}
...
{{else}}
Notice to user to look for their verification email
{{/if}}
{{/if}}
</template>
基于辅助函数
Template.main.helpers({
verified: function() { return Meteor.user().emails[0].verified; }
});
这满足了用户在通过验证之前不能做任何事情的要求,但仍以简单安全的方式使用帐户包。
我也可以看到使用 iron:router 采取相关方法。