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

如何在不修改源码的情况下用Devise gem检测登录失败尝试?

解决方案

以下几种方案都不需要修改Devise::SessionsController源码,也不用猴子补丁:

1. 优化Warden的before_failure钩子(精准判断场景)

通过请求路径、请求方法或控制器实例来区分「登录失败」和「未认证访问受限资源」:

Warden::Manager.before_failure do |env, opts|
  # 方式1:通过请求路径和方法判断(适合默认路由)
  request = ActionDispatch::Request.new(env)
  next unless request.path == '/users/sign_in' && request.post?

  # 方式2:通过控制器实例判断(更灵活,支持自定义路由)
  # controller = env['action_controller.instance']
  # next unless controller.is_a?(Devise::SessionsController) && controller.action_name == 'create'

  # 这里编写登录失败的处理逻辑,比如记录日志、限制IP等
end

2. 自定义Devise的Failure App(官方推荐扩展方式)

Devise允许自定义failure_app来处理认证失败逻辑,这是官方设计的扩展点:

首先创建自定义FailureApp类:

# app/lib/custom_failure.rb
class CustomFailure < Devise::FailureApp
  def respond
    # 仅在登录请求(sessions#create)失败时执行自定义逻辑
    if warden_options[:recall] || (request.path == '/users/sign_in' && request.post?)
      # 登录失败处理:比如写入失败日志、触发告警
      Rails.logger.info "登录失败:#{request.params[:user][:email]} 尝试登录失败"
    end

    # 保持Devise默认的失败响应(比如跳转到登录页)
    super
  end
end

然后在Devise初始化配置中指定这个自定义FailureApp:

# config/initializers/devise.rb
Devise.setup do |config|
  # ... 其他配置 ...
  config.warden do |manager|
    manager.failure_app = CustomFailure
  end
end

3. 订阅Devise的认证失败事件(解耦式处理)

Devise会在认证失败时触发devise.failure事件,通过ActiveSupport订阅可以无侵入地处理登录失败:

# config/initializers/devise_failure_listener.rb
ActiveSupport::Notifications.subscribe('devise.failure') do |_name, _start, _finish, _id, payload|
  request = payload[:request]
  # 判断是否是登录请求的失败
  if request.path == '/users/sign_in' && request.post?
    # 处理逻辑:比如记录到数据库、发送通知
    LoginFailureLog.create(email: request.params[:user]&.[](:email), ip: request.remote_ip)
  end
end

关于:recall参数的补充

你之前通过opts.key?(:recall)判断的方式其实是可靠的——Devise在登录失败时,会传递:recall参数来指定回调的控制器动作(即sessions#new),而未认证访问受限资源时不会传递这个参数。虽然文档未明确提及,但这是Devise长期稳定的实现逻辑,只要不升级到重构了这部分逻辑的大版本,就可以放心使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 06:15:21