使用Devise和Rails 4.0添加用于登录的验证字段

时间:2013-11-12 16:47:29

标签: ruby-on-rails authentication devise ruby-on-rails-4 warden

我正在尝试使用Devise和Rails 4.0在登录页面中添加另一个字段。用户需要提供其用户名,密码和组织/位置代码。用户has_and belongs_to_many位置,登录后,此组织代码应保存在会话中。

此时,我认为我已经完成了大部分工作(如果有更好的方法,请告诉我),但我不知道如何处理输入无效位置代码时会发生什么。这是我到目前为止所拥有的。

class SessionsController < Devise::SessionsController
  def create
    user = User.find_by_username(params["user"]["username"])
    org_code = params["user"]["check_org_code"].downcase
    user.locations.each do |location|
      if location.org_code == org_code
        super
        session[:location] = location
      else
        < return a warden.authenticate! fail? >
        super
      end
    end
  end
end

1 个答案:

答案 0 :(得分:0)

我最初通过使用throw(:warden)来解决这个问题,虽然这有效,但可能不是最佳解决方案。后来我通过r00k遇到了一个自定义设计策略示例并实现了我自己的变体。我在下面列出了两种解决方案。

r00k-esque解决方案 注:有些代码是r00k的解决方案,对我来说不起作用。如果r00k的解决方案不适合您,请注意与“失败”的区别!和“valid_password?”。

# config/initializers/local_override.rb

require 'devise/strategies/authenticatable'

module Devise
  module Strategies
    class LocalOverride < Authenticatable
      def valid?
        true
      end

      def authenticate!
        if params[:user]
          user = User.find_by_username(params["user"]["username"])
          if user.present?
            code = params["user"]["check_org_code"].downcase
            codes = user.locations.pluck(:org_code).map{ |code| code.downcase }
            check_code = code.in?(codes)
            check_password = user.valid_password?(params["user"]["password"])

            if check_code && check_password
              success!(user)
            else
              fail!(:invalid)
            end
          else
            fail!(:invalid)
          end
        else
          fail!(:invalid)
        end
      end
    end
  end
end

Warden::Strategies.add(:local_override, Devise::Strategies::LocalOverride)

# config/initializers/devise.rb
config.warden do |manager|
  manager.default_strategies(:scope => :user).unshift :local_override
end

初始解决方案

class SessionsController < Devise::SessionsController
  def create
    user = User.find_by_username(params["user"]["username"])
    org_code = params["user"]["check_org_code"].downcase
    matching = false

    user.locations.each do |location|
      if location.org_code == org_code
        super
        session[:location] = location
        matching = true
        break
      end
    end

    if matching == false
      throw(:warden, :message => :invalid)
    end
  end
end