Вручную войти на сайт с Typheous - PullRequest
6 голосов
/ 21 марта 2012

Недавно я использовал 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 = "admin@example.com"
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).Любая идея, что я делаю не так или, может быть, лучшее или более широкое применение этой проблемы?

Ответы [ 3 ]

8 голосов
/ 26 марта 2012

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

Во-первых, ваш файл 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
3 голосов
/ 04 октября 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})
1 голос
/ 26 марта 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

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

/669643/ponimanie-tokena-podlinnosti-rails
...