关于ruby on rails:使用Typhoeus手动登录网站

Manually login into website with Typheous

最近我用的是机械化,但我想用斑疹伤寒,我已经用在其他地方了。我想模仿机械化的行为,问题是我想以登录用户的身份登录到一个站点并执行请求。以下是脚本的通用版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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应用程序的管理)。知道我做错了什么吗,或者是更好或更广泛地适用于这个问题的解决方案?


以下是我能够成功运行的代码。

首先,您的cookie jar是一个数组,在我的代码中,它需要是一个带有替换(或哈希)的数组。当我在我的真实应用程序上运行代码时,get-url响应返回会话cookie,但post-url响应返回不同的会话cookie。

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

调整解析,以便获得每个cookie的名称和值:

1
2
3
4
5
6
7
8
9
10
11
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 jar需要转换为字符串:

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

最后,将您的头改为使用新的cookie jar-to-u:

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

另一个好处是让cookie jar成为自己的类,可能类似于这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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


我已经修复了@joelparkerhenderson的烹饪罐(因为它不在这里工作)。结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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})


您的站点是否使用了Rails伪造保护?

如果是这样,当您获得表单页面时,Rails将发送一个隐藏字段,该字段是CSRF令牌。

在HTML中,它看起来像这样:

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

发布表单时需要使用此隐藏值:

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

隐藏字段告诉Rails您是请求表单页面的人,因此您(并且只有您)可以发布。

以下是我关于CSRF的注释,并提供了更多信息的链接:

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

相关stackoverflow csrf信息:

1
http://stackoverflow.com/questions/941594/understand-rails-authenticity-token