2012-03-21 2 views
6

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

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('; ') } 
           ) 

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

ответ

8

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

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

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

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

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 

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

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 } 

бонус будет сделать кук своего собственного класса, возможно, что-то вроде этого:

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 
1

Ваши сайты используют защиту подделок 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 
+0

Отключение защиты CSRF в моем приложении было первым, что я пробовал. Тем не менее, второй сайт, на котором я тестировал его, является обычным PHP-приложением без этого, поэтому проблема не в этом, я думаю.Поместите скрипт в файл, установите typhoeus с 'gem install typhoeus', измените константы в верхней части соответственно, попробуйте, если он сработает для вас и сообщит мне. Я очень ценю ваш интерес. Благодарю. – Kreeki

3

Я исправил @ 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})