【问题标题】:Why isn't Warden using all of the default strategies?为什么 Warden 不使用所有默认策略?
【发布时间】:2016-08-21 15:22:13
【问题描述】:

我正在将 Rails 3.2 应用程序迁移到更环保(编号更高)的牧场。一直为我服务的 AuthLogic 显然在 4 中不起作用。所以我要过渡到 Warden。

下面的warden.rb 文件是从几年前编写的应用程序迁移而来的……但是warden 文档表明基本界面是相同的。感觉应该可以了。

我有两种身份验证策略,:httpauth 和 :params。 :params 策略有效。这是一个显示身份验证工作的日志文件条目:

Started POST "/user_sessions" for 127.0.0.1 at 2016-08-17 16:32:12 -0500
Processing by UserSessionsController#create as HTML
  Parameters: {"utf8"=>"✓", "username"=>"...."}
[AUTH] checking params
[AUTH] Authenticating user jw@mustmodify.com from params
...
[AUTH] User jw@mustmodify.com authenticated with a password.
...
Completed 302 Found in 111.5ms (ActiveRecord: 1.0ms)

但是,当使用 httpauth(通过 curl)时:

curl http://dev.projectdomain.com/clouds/bmi.svg -u user:password

我希望看到“检查 httpauth”,然后是“检查参数”……但我看到“检查参数”两次。我假设我要求管理员在控制器中进行两次身份验证......但根据我的理解,我也应该看到“检查 httpauth”。关于为什么这不起作用的任何想法?

Started GET "/clouds/bmi.svg" for 127.0.0.1 at 2016-08-17 16:22:51 -0500
Processing by CloudsController#show as SVG
  Parameters: {"id"=>"bmi"}
[AUTH] checking params
[AUTH] checking params

然后就是认证的结束。

这是我的 config/initializers/warden.rb 文件。注意...由于 httpauth 和 params 使用相同的字段和方法进行身份验证,我将“检查密码”的内容抽象为一个类:UserCredentialAuthentication。我实际上有第三种策略,:token,但它不是默认策略,为了简单起见,我将其排除在外。我确实验证了修改后的代码问题仍然存在:

Rails.application.config.middleware.use Warden::Manager do |manager|
  manager.default_strategies :httpauth, :params
end

Warden::Manager.serialize_into_session do |user|
  user.persistence_token
end

Warden::Manager.serialize_from_session do |id|
  User.where(persistence_token: id).first
end

class UserCredentialAuthentication < ::Warden::Strategies::Base
  def verify_against_old_credentials( user, password )
    Sha512.matches?( user.sha512_password, password, user.sha512_salt )
  end

  def transition_from_sha512!( user, password )
    user.password = password
    user.sha512_password = nil
    user.sha512_salt = nil
    user.save
  end

  def authenticate!
    Rails.logger.warn("[AUTH] Authenticating user #{username} from #{medium}")
    user = User.find_by_username_or_email(username)

    if user.blank?
      Rails.logger.warn("[AUTH] No Such User")
      fail "Invalid email or password"

    elsif user.sha512_password.not.blank? && verify_against_old_credentials( user, password )
      Rails.logger.warn("[AUTH] User #{user.email} authenticated with a SHA512 password.")
      transition_from_sha512!( user, password )
      success! user

    elsif user.password_digest && user.authenticate( password )
      Rails.logger.warn("[AUTH] User #{user.email} authenticated with a password.")
      success! user

    else
      Rails.logger.warn("[AUTH] Bad Password")
      fail "Invalid email or password"

    end
  end
end


Warden::Strategies.add(:httpauth, UserCredentialAuthentication) do
  def medium
    'httpAuth'
  end

  def valid?
    Rails.logger.warn("[AUTH] checking httpAuth")
    auth.provided? && auth.basic?
  end

  def auth
    @auth ||= Rack::Auth::Basic::Request.new(env)
  end

  def username
    auth.credentials[1]
  end

  def password
    auth.credentials[2]
  end
end

Warden::Strategies.add(:params, UserCredentialAuthentication) do
  def medium
    'params'
  end

  def valid?
    Rails.logger.warn("[AUTH] checking params")
    credential_params['username'] && credential_params['password']
  end

  def username
    credential_params['username']
  end

  def password
    credential_params['password']
  end

  def credential_params
    p = params.blank? ? post_params : params
    p['user_session'] || {}
  end

  def post_params
    @post_params ||= get_post_params
  end

  def get_post_params
    req = Rack::Request.new(env)

    if( req.post? )
      begin
        body = req.body.read
        req.body.rewind
        JSON.parse( body )
      end
    else
      {}
    end
  end
end

【问题讨论】:

    标签: authentication warden


    【解决方案1】:

    从同一个基类继承的两个策略在 Warden 看来似乎是同一个策略。我复制/粘贴,修复了我的 httpauth 策略中的一个小错误,它起作用了。不幸。

    我使用模块而不是类来抽象常用方法。最终解决方案:

    Rails.application.config.middleware.use Warden::Manager do |manager|
      manager.default_strategies [:httpauth, :params]
    end
    
    Warden::Manager.serialize_into_session do |user|
      user.persistence_token
    end
    
    Warden::Manager.serialize_from_session do |id|
      User.where(persistence_token: id).first
    end
    
    module UserCredentialAuthentication
      def verify_against_old_credentials( user, password )
        Sha512.matches?( user.sha512_password, password, user.sha512_salt )
      end
    
      def transition_from_sha512!( user, password )
        user.password = password
        user.sha512_password = nil
        user.sha512_salt = nil
        user.save
      end
    
      def authenticate!
        Rails.logger.warn("[AUTH] Authenticating user #{username} from #{medium}")
        user = User.find_by_username_or_email(username)
    
        if user.blank?
          Rails.logger.warn("[AUTH] No Such User")
          fail "Invalid email or password"
    
        elsif user.sha512_password.not.blank? && verify_against_old_credentials( user, password )
          Rails.logger.warn("[AUTH] User #{user.email} authenticated with a SHA512 password.")
          transition_from_sha512!( user, password )
          success! user
    
        elsif user.password_digest && user.authenticate( password )
          Rails.logger.warn("[AUTH] User #{user.email} authenticated with a password.")
          success! user
    
        else
          Rails.logger.warn("[AUTH] Bad Password")
          fail "Invalid email or password"
    
        end
      end
    end
    
    
    Warden::Strategies.add(:httpauth) do
      include UserCredentialAuthentication
    
      def medium
        'httpAuth'
      end
    
      def valid?
        Rails.logger.warn("[AUTH] checking httpAuth")
        auth.provided? && auth.basic?
      end
    
      def username
        auth.credentials[0]
      end
    
      def password
        auth.credentials[1]
      end
    
      def auth
        @auth ||= Rack::Auth::Basic::Request.new(env)
      end
    end
    
    Warden::Strategies.add(:params) do
      include UserCredentialAuthentication
    
      def medium
        'params'
      end
    
      def valid?
        Rails.logger.warn("[AUTH] checking params")
        credential_params['username'] && credential_params['password']
      end
    
      def username
        credential_params['username']
      end
    
      def password
        credential_params['password']
      end
    
      def credential_params
        p = params.blank? ? post_params : params
        p['user_session'] || {}
      end
    
      def post_params
        @post_params ||= get_post_params
      end
    
      def get_post_params
        if( request.post? )
          begin
            body = request.body.read
            request.body.rewind
            JSON.parse( body )
          end
        else
          {}
        end
      end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-14
      • 2017-03-10
      • 1970-01-01
      • 1970-01-01
      • 2023-02-11
      • 2017-12-27
      • 2021-05-05
      相关资源
      最近更新 更多