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

Devise重置密码通知:如何通过SMS而非邮件发送至手机号

解决Devise框架下用SMS发送重置密码通知的方案

嘿,这个需求我之前在做一个无邮箱注册的项目时刚好踩过坑,给你整理一套可行的方案,完全适配你的场景——用户无邮箱、手机号必填:

1. 换掉Devise默认的密码重置控制器

Devise自带的PasswordsController是硬绑邮箱逻辑的,咱们得自己写一个控制器继承它,把查找用户的逻辑改成按手机号来:

# app/controllers/users/passwords_controller.rb
class Users::PasswordsController < Devise::PasswordsController
  def create
    # 按手机号查找用户,替代默认的邮箱查找逻辑
    @user = User.find_by(phone_number: params[:user][:phone_number])

    if @user.present?
      # 调用Devise内置方法生成重置令牌,同时触发咱们后面重写的通知逻辑
      @user.send_reset_password_instructions
      flash[:notice] = "重置密码的验证码已发送到你的手机号,15分钟内有效哦"
    else
      flash[:alert] = "没找到这个手机号对应的用户,请检查输入"
    end
    redirect_to new_user_password_path
  end
end

然后在路由里指定用咱们自定义的控制器:

# config/routes.rb
devise_for :users, controllers: { passwords: 'users/passwords' }

2. 重写用户模型的重置通知方法

Devise默认会发邮件,咱们要把这个逻辑彻底换成发短信。在User模型里重写send_reset_password_instructions方法:

# app/models/user.rb
class User < ApplicationRecord
  # 加上email_required: false,告诉Devise不强制要求邮箱字段
  devise :database_authenticatable, :registerable,
         :recoverable, :validatable, email_required: false, email_verifiable: false

  # 手机号必填+唯一的验证规则
  validates :phone_number, presence: true, uniqueness: true

  # 重写Devise的重置密码通知方法
  def send_reset_password_instructions
    # 生成并保存重置密码令牌(Devise内置方法,不用自己造轮子)
    generate_reset_password_token!

    # 这里调用你的短信服务发送内容,把令牌传进去
    # 示例:假设你有个封装好的SmsSender服务
    SmsSender.send(
      self.phone_number,
      "你的密码重置验证码是:#{reset_password_token},请在15分钟内完成密码重置"
    )
  end
end

3. 调整前端视图,把邮箱输入换成手机号

原来的密码重置申请页是让用户输邮箱的,咱们要改成输手机号:

# app/views/devise/passwords/new.html.erb
<h2>重置密码</h2>

<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
  <%= devise_error_messages! %>

  <div class="field">
    <%= f.label :phone_number, "手机号" %><br />
    <%= f.text_field :phone_number, autofocus: true, placeholder: "请输入你的手机号" %>
  </div>

  <div class="actions">
    <%= f.submit "发送重置短信" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>

4. 一些细节注意点

  • 短信服务集成:上面的SmsSender是示例,你得换成自己实际用的短信服务商API(比如阿里云、腾讯云或者Twilio),记得加异常捕获处理发送失败的情况,给用户友好提示。
  • 令牌有效期:可以在config/initializers/devise.rb里调整config.reset_password_within = 15.minutes,和短信里的提示保持一致。
  • Devise验证规则:一定要确认关掉邮箱相关的强制验证,不然用户无邮箱注册时会触发Devise的默认校验报错。

整个流程跑起来就是:用户输入手机号→系统生成唯一重置令牌→短信发送令牌→用户拿着令牌去输入新密码(Devise默认的密码重置编辑页可以直接用,只要输入令牌和新密码就行)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:22:41