使用 Guardian 创建电子邮件验证 url

Create email verification url using Guardian

我正在开发一个实现用户身份验证的网站(使用 Comeonin 和 Guardian)。

我正在实施电子邮件验证。我想我可能会利用 Guardian 中的功能来使用 JWT 令牌生成 url。根据 this post,这似乎是一个合理的解决方案(只要 url 使用 https 并且令牌在相对较短的时间内过期)。

这是我到目前为止编写的代码:

def email_verification( user = %User{} ) do
  if ( user.email != nil ) do
    claims = Guardian.Claims.app_claims
       |> Map.put("email", user.email)
       |> Guardian.Claims.ttl({1, :hours})

    { :ok, jwt, full_claims } = Guardian.encode_and_sign(user, :email_verification, claims)

    Zoinks.Mailer.send_verification_email( user.email, jwt )
  end
end

我已将电子邮件地址放入声明中。我的想法是,一旦用户单击 link,我就可以将 "email" 声明与数据库中的电子邮件地址相匹配。

但是,我认为这是个坏主意 - 特别是因为 link 将通过电子邮件以明文形式公开。

按照此 SO post 中概述的模式,也许我可以生成一个随机数,对其进行哈希处理(使用 Comeonin),针对用户存储它并将其放入我的声明中?这是个好主意,还是我完全偏离了轨道?

假设我让这部分解决方案正常工作,可以将负载类型设置为 :email_verification 吗?

通过电子邮件发送 JWT 是完全没问题的,只要使用了强密码(但这始终很重要,尽管有传输方法)

引自评论:

I'm assuming that if you collect enough tokens (clear text via email), then it might be possible to apply a technique such as a Rainbow Table attack?

这就是为什么你应该选择一个强大的秘密。 JWT 的最后一部分,即签名,是 base64UrlEncode(header)base64UrlEncode(payload)secret 的组合,放入像 HMAC SHA256 这样的强哈希函数中。有关更多安全信息,jwt.io

上有很好的描述

实施

您根本不需要将实际的电子邮件放入声明中。像 email=true 这样的简单字段就足够了,因为您的 Serializer 已经将用户 ID 放入令牌中。只要确保一个用户只能被验证一次并选择一个强秘密!