You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Timex为验证链接设置超时(不使用Coherence等认证包)

使用Timex实现验证链接的超时机制

没问题,咱们完全可以用Timex手动搞定这个需求,不用依赖任何认证类包,步骤其实很清晰:

1. 数据库表新增过期时间字段

首先你需要在存储验证链接的表(比如verification_tokens)里加一个expires_at字段,用来记录链接的失效时间。如果用Ecto的话,Schema可以这么定义:

defmodule YourApp.VerificationToken do
  use Ecto.Schema
  import Ecto.Changeset
  alias Timex.DateTime

  schema "verification_tokens" do
    field :token, :string
    field :user_id, :integer # 关联到对应用户
    field :expires_at, :utc_datetime # 存储UTC时间,避免时区问题
    timestamps()
  end

  def changeset(token, attrs) do
    token
    |> cast(attrs, [:token, :user_id, :expires_at])
    |> validate_required([:token, :user_id, :expires_at])
  end
end

2. 生成验证链接时计算过期时间

当你生成验证token并存入数据库时,用Timex计算出过期时间。比如设置链接24小时后失效:

# 生成安全的随机token
token = :crypto.strong_rand_bytes(16) |> Base.url_encode64(padding: false)

# 计算24小时后的UTC时间作为过期时间
expires_at = Timex.now() |> Timex.add(Timex.Duration.from_hours(24))

# 存入数据库
YourApp.Repo.insert!(YourApp.VerificationToken.changeset(%YourApp.VerificationToken{}, %{
  token: token,
  user_id: user.id,
  expires_at: expires_at
}))

# 把包含token的链接通过邮件发给用户,比如"https://your-app.com/verify?token=#{token}"

这里推荐用UTC时间存储,避免不同时区导致的过期时间计算偏差,Timex的Timex.now()默认返回的就是UTC时间(只要你的项目时区配置正确)。

3. 验证链接时检查是否过期

当用户点击链接访问验证接口时,先根据token从数据库取出对应记录,再用Timex对比当前时间和过期时间:

def verify_token(token) do
  case YourApp.Repo.get_by(YourApp.VerificationToken, token: token) do
    nil ->
      {:error, :invalid_token}
    token_record ->
      # Timex.compare返回1表示当前时间晚于过期时间,即链接已失效
      case Timex.compare(Timex.now(), token_record.expires_at) do
        1 ->
          # 顺便删除过期token,避免数据库冗余
          YourApp.Repo.delete(token_record)
          {:error, :token_expired}
        _ ->
          # 验证通过,执行后续逻辑(比如激活用户)
          {:ok, token_record.user_id}
      end
  end
end

Timex.compare/2的返回值规则:

  • -1:第一个时间早于第二个
  • 0:两个时间完全相等
  • 1:第一个时间晚于第二个

所以返回1时,就说明链接已经过期失效了。

额外优化:定期清理过期token

为了避免数据库堆积大量过期的无效token,你可以加个定时任务自动清理,比如用Oban或者简单的Task:

def clean_expired_tokens do
  expired_at = Timex.now()
  YourApp.Repo.delete_all(
    from t in YourApp.VerificationToken,
    where: t.expires_at < ^expired_at
  )
end

内容的提问来源于stack exchange,提问作者Sh4dy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:47:51