Войдите на сайт вручную с помощью Typheous

Недавно я использовал Mechanize для такого рода вещей, но я хочу использовать Typhoeus, который я уже использую везде. Я хочу имитировать поведение Mechanize, проблема в том, что я хотел бы войти на сайт и выполнять запросы как зарегистрированный пользователь. Вот обобщенная версия скрипта:

require 'rubygems'
require 'typhoeus'

GET_URL = 'http://localhost:3000'
POST_URL = "http://localhost:3000/admins/sign_in"
URL = "http://localhost:3000/dashboard"
USERNAME_FIELD = 'admin[email]'
PASSWORD_FIELD = 'admin[password]'
USERNAME = "[email protected]"
PASSWORD = "my_secret_password"

def merge_cookies_into_cookie_jar(response)                            
  if response.headers_hash['set-cookie'].instance_of? Array
    response.headers_hash['set-cookie'].each do |cookie|
      @cookie_jar << cookie.split('; ')[0]
    end
  elsif response.headers_hash['set-cookie'].instance_of? String
    @cookie_jar << response.headers_hash['set-cookie'].split('; ')[0]
  end        
end

# initialize cookie jar
@cookie_jar = []

# for server to establish me a session
response = Typhoeus::Request.get( GET_URL, :follow_location => true )
merge_cookies_into_cookie_jar(response)                                                   

# like submiting a log in form
response = Typhoeus::Request.post( POST_URL,
                                   :params => { USERNAME_FIELD => USERNAME, PASSWORD_FIELD => PASSWORD },
                                   :headers => { 'Cookie' => @cookie_jar.join('; ') }
                                 )
merge_cookies_into_cookie_jar(response)                                                   

# the page I'd like to get in a first place, 
# but not working, redirects me back to login form with 401 Unauthorized :-(                 
response = Typhoeus::Request.get( URL, 
                                  :follow_location => true,
                                  :headers => { 'Cookie' => @cookie_jar.join('; ') }
                                 )

Файл cookie отправляется на сервер, но по какой-то причине я не вошел в систему. Я тестировал его на двух разных сайтах (один из них был администратором моего приложения Rails). Есть идеи, что я делаю не так, или, может быть, лучшее или более широко применимое решение этой проблемы?


person Kreeki    schedule 21.03.2012    source источник


Ответы (3)


Вот код, который я могу успешно запустить.

Во-первых, ваша банка cookie - это массив, а в моем коде он должен быть массивом с заменой (или хешем). Когда я запускаю код в своем реальном приложении, ответ GET_URL возвращает файл cookie сеанса, но ответ POST_URL возвращает другой файл cookie сеанса.

# initialize cookie jar as a Hash
@cookie_jar = {}

Настройте синтаксический анализ, чтобы получить имя и значение каждого файла cookie:

def merge_cookies_into_cookie_jar(response)
  x =  response.headers_hash['set-cookie']
  case x
  ...
  when String
    x.split('; ').each{|cookie|
      key,value=cookie.split('=', 2)
      @cookie_jar[key]=value
    }
  end
end

Банку cookie необходимо преобразовать в строку:

def cookie_jar_to_s
  @cookie_jar.to_a.map{|key, val| "#{key}=#{val}"}.join("; ")
end

Наконец, измените заголовки, чтобы использовать новый cookie_jar_to_s:

:headers => { 'Cookie' => cookie_jar_to_s }

Бонусом было бы сделать банку cookie отдельным классом, возможно, примерно так:

class CookieJar < Hash

  def to_s
    self.to_a.map{|key, val| "#{key}=#{val}"}.join("; ")
  end

  def parse(*cookie_strings)
    cookie_strings.each{|s|
      s.split('; ').each{|cookie|
        key,value=cookie.split('=', 2)
        self.[key]=value
      }
    }
  end

end
person joelparkerhenderson    schedule 26.03.2012

Я исправил CookieJar @ joelparkerhenderson (поскольку он здесь не работал). Вот результат:

class CookieJar < Hash
  def to_s
    self.map { |key, value| "#{key}=#{value}"}.join("; ")
  end

  def parse(cookie_strings)
    cookie_strings.each { |s|
      key, value = s.split('; ').first.split('=', 2)
      self[key] = value
    }
    self
  end
end

# Use like this:
response = Typhoeus::Request.get("http://www.example.com")
cookies = CookieJar.new.parse(response.headers_hash["Set-Cookie"])
Typhoeus::Request.get("http://www.example.com", headers: {Cookie: cookies.to_s})
person iGEL    schedule 04.10.2012

Используют ли ваши сайты защиту от подделки Rails?

Если это так, когда вы получаете страницу формы, Rails отправляет скрытое поле, которое является токеном CSRF.

В HTML это будет выглядеть примерно так:

<input type="hidden" name="csrf" value="abcdef">

Вам нужно использовать это скрытое значение при публикации формы:

:params => {"csrf" => "abcdef", USERNAME_FIELD => USERNAME, ...

Скрытое поле сообщает Rails, что вы - человек, который запросил страницу формы, поэтому вам (и только вам) разрешено публиковать сообщения.

Вот мои заметки о CSRF со ссылками на дополнительную информацию:

http://sixarm.com/about/rails-session-csrf-token-jquery-ajaxprefilter.html

Связанная информация о StackOverflow CSRF:

http://stackoverflow.com/questions/941594/understand-rails-authenticity-token
person joelparkerhenderson    schedule 25.03.2012
comment
Отключение защиты CSRF в моем приложении было первым, что я попробовал. Тем не менее, второй сайт, на котором я его тестировал, - это обычное приложение PHP без этого, так что, я думаю, проблема не в этом. Поместите приведенный выше сценарий в файл, установите typhoeus с gem install typhoeus, измените константы вверху соответственно, попробуйте, работает ли он для вас, и дайте мне знать. Я очень ценю ваш интерес. Спасибо. - person Kreeki; 26.03.2012