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

Rails API中Devise-Passwordless过期魔法链接的验证与重发方案

实现Devise-Passwordless魔法链接重发验证方案

1. 扩展用户模型,保存历史令牌

默认Devise-Passwordless在用户登录后会清空当前魔法链接令牌,无法验证旧令牌有效性。我们需要新增字段存储已使用的令牌(含创建时间):

生成迁移文件

rails generate migration AddLastUsedMagicLinkTokenToUsers last_used_magic_link_token:json
rails db:migrate

重写登录后回调方法

在User模型中添加逻辑,保存旧令牌及创建时间:

# app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,
         :passwordless_authenticatable

  # 登录成功后保存旧令牌信息
  def after_passwordless_sign_in
    self.last_used_magic_link_token = {
      token: magic_link_token,
      created_at: magic_link_sent_at
    }
    clear_magic_link_token # 清空当前有效令牌
    save(validate: false)
  end
end

2. 创建重发魔法链接API端点

新增API控制器动作,实现旧令牌验证、用户授权检查及新链接发送:

# app/controllers/api/v1/sessions_controller.rb
class Api::V1::SessionsController < ActionController::API
  include Devise::Controllers::Rails7ApiMode
  include Devise::Controllers::Helpers

  def resend_magic_link
    user = User.find_by(email: params[:email])
    return render_unauthorized unless user

    # 验证旧令牌有效性:匹配当前未使用令牌或已使用的历史令牌,且令牌在有效期内
    valid_token = validate_old_token(user, params[:old_token])
    # 验证用户是否为授权的管理员/经理(根据实际业务调整判断逻辑)
    authorized = user.role.in?(['admin', 'manager'])

    if valid_token && authorized
      user.send_magic_link # 生成并发送新魔法链接
      render json: { message: "新的魔法链接已发送至你的邮箱" }, status: :ok
    else
      render_unauthorized
    end
  end

  private

  def validate_old_token(user, old_token)
    # 检查当前未使用的令牌是否匹配且在有效期内
    if user.magic_link_token == old_token
      return user.magic_link_sent_at >= Devise.passwordless_token_valid_for.ago
    end

    # 检查已使用的历史令牌是否匹配且当时在有效期内
    return false unless user.last_used_magic_link_token.present?
    return false unless user.last_used_magic_link_token['token'] == old_token

    user.last_used_magic_link_token['created_at'] >= Devise.passwordless_token_valid_for.ago
  end

  def render_unauthorized
    render json: { error: "无权重发魔法链接,请确认信息或联系管理员" }, status: :unauthorized
  end
end

3. 配置路由

在routes.rb中添加重发链接的API路由:

# config/routes.rb
Rails.application.routes.draw do
  namespace :api do
    namespace :v1 do
      post '/sessions/resend_magic_link', to: 'sessions#resend_magic_link'
    end
  end

  # 其他Devise路由...
end

4. 调整令牌有效期(可选)

如需修改魔法链接默认15分钟的有效期,在Devise初始化文件中配置:

# config/initializers/devise.rb
Devise.setup do |config|
  # 其他配置...
  config.passwordless_token_valid_for = 30.minutes # 自定义有效期
end

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:17:18