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
相关产品推荐
相关产品推荐

