如何实现过期帐户激活链接?

时间:2019-07-14 23:59:16

标签: node.js postgresql nestjs typeorm

我正在尝试使用户注册新帐户时发送到用户电子邮件的激活链接失效。

如果用户未单击该链接,则该链接应在24小时后失效。
到目前为止,注册后我已经可以将链接发送到用户的电子邮件,该链接看起来像这样'http://localhost:3000/auth/activate/${verificationKey}',一切正常。

但是,就像我说的那样,我希望链接在24小时后过期,而我对此一无所知。

根据到目前为止的经验,我认为一种方法是在24小时后从用户实体/模型中删除verificationKey值,如果verificationKey的值是< em> falsy 我需要向用户发送另一个链接。
现在我的问题是,如何检查是否已在24小时内生成一个值(在这种情况下为user.verification_key)?

这是注册新用户的相关代码:

const user = new User();
user.username = username;
user.password = await bcrypt.hash(password, salt);
user.is_verified = false;
user.verification_key = cryptoRandomString({
length: 10,
type: 'url-safe',
});

有人建议为此使用 Redis ,除了内存存储之外,我对此一无所知,虽然我可以阅读有关此工具的更多信息,但我想知道是否还有其他方法可以做到这一点。我不知道通过安装Redis托管应用程序时是否需要对服务器进行额外的配置,我想避免这种情况。

3 个答案:

答案 0 :(得分:0)

由于您已经设置了一些数据库,因此有必要存储一些验证密钥和到期时间。您无需实际删除该验证密钥,只需在其过期时进行存储即可。

也许您有一个单独的RegVerificationKey模型,其中包含字段key(随机生成的字符串),expiration(设置为创建日期24小时后的日期/时间)和{{1} }(与之关联的用户的ID)。创建此密钥。当您进行激活时,只需检查一下是否有与请求的用户相关联的密钥尚未过期。

  

有人建议为此使用Redis

这里不需要,您已经有一个可以放入数据的数据库。

  

我想知道是否还有其他方法可以做到

还有另一种方法,您可以对URL进行密码签名。基本上,您将密钥及其过期数据存储在URL本身中,并包括一些经过计算的证据证明您(拥有私钥的人)创建了此URL。当您的系统收到此URL时,它可以验证URL是否已正确签名,而不必查阅数据库。此方法可能很复杂,在您的情况下可能没有用。我只是在这里提到它作为替代。查看JWT以了解一种可能的实现:https://jwt.io/

答案 1 :(得分:0)

最近我需要在我的 Web 应用程序中实现这种实现。所以我只是按照以下几点来实现它。

1- 创建 URL(网络链接)并附加当前日期和时间以及您将存储在数据库中的加密密钥,如下所述。

2- 在数据库表(您存储任何用户特定详细信息的表)中创建一列,以存储您已加密并附加到 URL 中的随机生成的密钥。

3- 当您在服务器上收到此 URL 时,您将检查 URL 中的加密日期和时间,并根据您保留链接的标准(例如 24 小时)决定它是否仍然有效

4- 接下来,您将在创建时附加在其中的 URL 中解密该密钥,并将其与您存储在表中的内容进行匹配。

因此,通过实现上述逻辑,您可以实现所需的功能。

希望它对任何想要类似实现类型的人有用

答案 2 :(得分:-1)

我知道您已经找到了解决方案,通过在数据库中存储两个字段:一个用于密钥,另一个用于过期时间戳。一切都取决于用例,这绝对是一种方法。但是,与您的解决方案相比,我将解释 Redis 和 JWT 作为解决方案。

Redis 是一个内存数据存储(也允许持久化到磁盘),正如您所指出的,我认为人们建议它的原因是,您可以定义记录的到期时间。 Redis 将自动为您删除该记录。参考:https://redis.io/commands/expire

Redis 会减轻您的负担,检查 24 小时是否已经过去。如果您无法再获取密钥,则密钥可能已过期。 Redis 的另一个好处是,与普通的数据库查询相比,它的速度非常快。但是如果您只需要它用于激活链接,这对用户来说是一次性操作,那么时间收益可以忽略不计。此外,您还会为该用例引入一项新技术。

@Brad 已经建议使用 JWT(Json Web 令牌)而不是实现您自己的令牌解决方案,出于以下原因,我也建议这样做。

JWT 是一个自包含的令牌,由三部分组成:Header、Payload、Signature。标头包含用于创建令牌的算法的名称。 Paylod 包含一些标准化字段(例如创建日期、到期日期、令牌颁发的主题,如用户名),您还可以添加自定义字段。第三部分是一个签名,确保在您的令牌服务发出后没有人更改有效负载。

自包含意味着令牌包含验证它的所有内容,包括过期时间戳。在您的情况下,到期时间不是您的令牌的一部分,而是存储在数据库中。如果您创建另一个需要验证您的令牌的微服务,该服务需要联系您的主服务,其中包含检查过期数据库字段的逻辑。 使用 JWT,微服务只需要知道用于签署令牌的密钥,然后你就可以导入一些标准的 JWT 库来验证令牌。这些库验证签名以及过期时间戳,它是令牌有效负载中的可选字段。 顺便说一下,可以在不知道签名中的密钥的情况下读取有效载荷。因此,甚至可以在客户端读取负载以检查过期时间。

在您的解决方案中,您有额外的数据库调用,这可能会很慢。对于可接受的激活链接,但对于在短时间内重复使用的令牌(即需要身份验证的 API 请求),应避免额外的数据库调用。您还需要自己实现令牌生成和验证,而 JWT 提供标准库。例如,当您想在 Java 中使用另一个微服务而不是 NestJS 时,这是一个好处。您可以使用标准库将它们快速组合在一起,而不是移植您的实现或被迫决定使用集中式令牌验证服务。

您必须自己解决 JWT 的一个限制是您想要拥有“一次性令牌”的用例。您只能定义到期日期,但不能说令牌只能使用 x 次。在这里,您再次需要一个集中式服务,它可以跟踪令牌的使用频率(通过使用某些数据存储),并且周围的所有其他服务都需要联系该服务。

JWT with NestJS 的一个很好的起点是 NestJS 官方文档。

相关问题