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

Rails框架下基于Metamask的Web3签名注册/登录API实现:Devise支持性及自定义验证方案咨询

很棒的问题!Devise本身并没有内置Web3签名登录的功能,但它的扩展性极强,完全可以通过自定义配置和逻辑来实现你想要的Web3签名注册/登录流程。下面一步步拆解具体怎么做:

1. 禁用用户模型的密码字段

首先,我们需要修改Devise的用户模型,移除和密码相关的验证及模块,同时调整数据库结构:

  • 修改用户模型:打开app/models/user.rb,去掉devise方法里的:database_authenticatable模块(这个是处理密码验证的核心模块),同时禁用密码相关的默认验证:
class User < ApplicationRecord
  # 保留你需要的Devise模块,比如:registerable、:trackable,去掉:database_authenticatable
  devise :registerable, :trackable, :validatable # 注意:如果保留:validatable,需要自定义验证逻辑,避免默认的密码校验

  # 禁用密码字段的必填验证
  validates :password, presence: false, allow_nil: true
end
  • 调整数据库结构:如果已经生成了包含password_digest字段的迁移,需要创建一个新迁移来移除它:
# 生成迁移文件:rails generate migration RemovePasswordDigestFromUsers
class RemovePasswordDigestFromUsers < ActiveRecord::Migration[7.0]
  def change
    remove_column :users, :password_digest, :string
  end
end

运行迁移:rails db:migrate

2. 自定义Web3签名的登录验证逻辑

接下来我们要实现“请求随机Nonce → 钱包签名 → 后端校验签名”的Web3登录流程:

第一步:添加钱包地址字段

首先给用户模型添加wallet_address字段,用来存储用户的Web3钱包地址:

# 生成迁移文件:rails generate migration AddWalletAddressToUsers
class AddWalletAddressToUsers < ActiveRecord::Migration[7.0]
  def change
    add_column :users, :wallet_address, :string, unique: true, null: false
  end
end

运行迁移:rails db:migrate

然后在用户模型里添加钱包地址的验证,以及生成Nonce、校验签名的方法:

class User < ApplicationRecord
  # ... 之前的Devise配置

  # 验证钱包地址格式(以太坊地址为例)
  validates :wallet_address, presence: true, uniqueness: true, format: { with: /\A0x[a-fA-F0-9]{40}\z/ }

  # 生成随机Nonce(防止重放攻击)
  def generate_nonce
    update!(nonce: SecureRandom.hex(16))
    nonce
  end

  # 校验Web3签名是否有效(这里以以太坊为例,使用ethereum.rb库)
  def valid_signature?(signature)
    # 构造签名消息,必须和前端保持一致
    message = "请签名此消息完成验证,Nonce: #{nonce}"
    # 从签名中恢复钱包地址
    recovered_address = Ethereum::Signature.recover(message, signature)
    # 对比恢复的地址和用户存储的地址(统一转小写避免大小写问题)
    recovered_address.downcase == wallet_address.downcase
  end
end

第二步:添加Web3登录的控制器和路由

创建一个专门处理Web3登录的控制器Web3SessionsController:

class Web3SessionsController < ApplicationController
  skip_before_action :authenticate_user!

  # 前端请求获取随机Nonce
  def nonce
    wallet_address = params[:wallet_address]
    # 找到或创建用户(自动注册逻辑,可根据需求调整)
    user = User.find_or_initialize_by(wallet_address: wallet_address)
    user.save! if user.new_record?
    render json: { nonce: user.generate_nonce }
  end

  # 校验签名并完成登录
  def create
    user = User.find_by(wallet_address: params[:wallet_address])
    if user&.valid_signature?(params[:signature])
      # 使用Devise的sign_in方法登录用户
      sign_in(user, scope: :user)
      render json: { success: true, user: user }
    else
      render json: { error: "签名或钱包地址无效" }, status: :unauthorized
    end
  end
end

然后在config/routes.rb里添加对应的路由:

Rails.application.routes.draw do
  devise_for :users
  # Web3登录相关路由
  post '/web3/nonce', to: 'web3_sessions#nonce'
  post '/web3/login', to: 'web3_sessions#create'
end

第三步:添加Web3依赖库

我们需要用到Web3相关的Ruby库来处理签名校验,比如ethereum.rb,在Gemfile里添加:

gem 'ethereum.rb'

然后运行bundle install安装依赖。

3. 额外注意事项
  • 如果保留了Devise的:validatable模块,建议自定义验证规则,避免它默认的密码校验逻辑干扰。
  • Nonce使用后可以重置,或者设置过期时间,进一步提升安全性。
  • 签名消息的内容必须前后端完全一致,否则校验会失败,建议把消息内容抽成常量统一管理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 16:32:41