使用 HTTParty 传递 cookie

Passing cookies with HTTParty

我正在尝试使用 HTTParty 将用户登录到 Rails 应用程序。 想法是发送一个 POST 请求并用它获取一个会话 cookie,然后用这个 cookie 发送一个 GET 请求并成功登录:

POST请求

HTTParty.post('url/login/', basic_auth: {user: 'user', password: 'password'}, follow_redirects: false)

returns

#<HTTParty::Response:0x7f9c71bc4598 parsed_response=nil, @response=#<Net::HTTPFound 302 302 readbody=true>, @headers={"date"=>["Mon, 04 Mar 2019 08:02:26 GMT"], "server"=>["Apache"], "strict-transport-security"=>["max-age=31536000"], "set-cookie"=>["JSESSIONID=6552C1F4FD12D1C5B1D3B42168B9588A.node2; Path=/; Secure; HttpOnly"], "x-content-type-options"=>["nosniff"], "x-xss-protection"=>["1; mode=block"], "cache-control"=>["no-cache, no-store, max-age=0, must-revalidate"], "pragma"=>["no-cache"], "expires"=>["0"], "location"=>["/ipad-api/v20/login/failure/"], "vary"=>["Accept-Encoding,User-Agent"], "content-length"=>["20"], "connection"=>["close"], "content-type"=>["text/plain; charset=UTF-8"]}>

我发送一个GET请求

HTTParty.get('url/login/success/', cookie: "6552C1F4FD12D1C5B1D3B42168B9588A.node2")

并获得

#<HTTParty::Response:0x7f9c71b95950 parsed_response={"head"=>{"apikey"=>nil, "sessionid"=>"320E4C622043566D5424627BDE11997D.node3", "timestamp"=>1551686567666, "sessiontimeout"=>1551689267666, "wishlistItemsCount"=>0, "basketItemsCount"=>0, "loggedIn"=>false, "role"=>"G"}, "data"=>{"user"=>{"profile"=>{"title"=>nil, "firstname"=>nil, "lastname"=>nil, "street"=>nil, "street2"=>nil, "postalcode"=>nil, "city"=>nil, "customerID"=>nil, "customerType"=>0}}, "abandonedBasket"=>false}, "messages"=>[{"code"=>"bmd.api.login.success", "statusCode"=>200, "description"=>"OK"}]}, @response=#<Net::HTTPOK 200 200 readbody=true>, @headers={"date"=>["Mon, 04 Mar 2019 08:02:47 GMT"], "server"=>["Apache"], "strict-transport-security"=>["max-age=31536000"], "set-cookie"=>["JSESSIONID=320E4C622043566D5424627BDE11997D.node3; Path=/; Secure; HttpOnly"], "x-content-type-options"=>["nosniff"], "x-xss-protection"=>["1; mode=block"], "cache-control"=>["no-cache, no-store, max-age=0, must-revalidate"], "pragma"=>["no-cache"], "expires"=>["0"], "vary"=>["Accept-Encoding,User-Agent"], "connection"=>["close"], "transfer-encoding"=>["chunked"], "content-type"=>["application/json;charset=UTF-8"]}>

会话更改,用户未登录。与 curl 相同的请求使用户成功登录。 研究表明 it might be not easy and this solution 也不起作用。

知道我做错了什么以及应该往哪个方向思考吗?按照建议改成法拉第here?

要使用 HTTParty 登录,您需要查看的东西比 cookie 还多。你也得看看CSRF_token。我认为您可以使用 gsub 方法获得 authenticity_token 但我尝试过并且创建正则表达式非常困难。所以我使用 Nokogiri 来获取实际存在于登录表单中的令牌。下面是细节,最后,我会把整个代码。

添加需要的Gem,可以在Gemfile中添加

gem 'httparty'
gem 'nokogiri'

运行 bundle install 安装 gem。

要获得 CSRF_token 我们必须获得 sign_in 页。

url = "http://localhost:3000/users/sign_in"
get_response = HTTParty.get(url)
noko_doc = Nokogiri::HTML(get_response)
auth_token = noko_doc.css('form').css('input[name="authenticity_token"]').first.values[2]

这样我们得到了 auth_token ,它在表单中作为隐藏字段。现在让我们获取 cookie,因为可能需要会话 cookie。

cookie_hash = HTTParty::CookieHash.new
get_response.get_fields('Set-Cookie').each { |c| cookie_hash.add_cookies(c) }

我们在这里获取会话也存在的 cookie。 现在是获取最终参数的时候了,我们会将 cookie 和会话发送到登录

params = {"utf8" => "✓", "authenticity_token" => auth_token, "user[email]"=>"user@email.com",·
          "user[password]"=>"password"}

params["commit"] = "Login"

现在参数已准备就绪,您可以使用以下 httparty 请求登录并获取 cookie。

response = HTTParty.post("http://localhost:3000/users/sign_in", {:body=>params, headers: {'Cookie' => cookie_hash.to_cookie_string }} )

现在对于其他请求,您可以运行使用相同的 cookie 方法来取回所有 cookie

cookie_hash = HTTParty::CookieHash.new
get_response.get_fields('Set-Cookie').each { |c| cookie_hash.add_cookies(c) }

要访问其他页面,您可以像我们在上面的示例中那样发送带有 cookie 的请求。请记住,如果您再次使用任何具有表单的页面,您也需要再次获取其 csrf。

response = HTTParty.post("http://localhost:3000/users/other_urls", {headers: {'Cookie' => cookie_hash.to_cookie_string }} )

我试过这段代码,它运行良好。这是供您使用的完整代码

require 'httparty'
require 'Nokogiri'
require 'Pry'

url = "http://localhost:3000/users/sign_in"

get_response = HTTParty.get(url)
noko_doc = Nokogiri::HTML(get_response)
auth_token = noko_doc.css('form').css('input[name="authenticity_token"]').first.values[2]
cookie_hash = HTTParty::CookieHash.new
get_response.get_fields('Set-Cookie').each { |c| cookie_hash.add_cookies(c) }

params = {"utf8" => "✓", "authenticity_token" => auth_token, "user[email]"=>"user@example.com",·
          "user[password]"=>"password"}

params["commit"] = "Login"

response = HTTParty.post("http://localhost:3000/users/sign_in", {:body=>params, headers: {'Cookie' => cookie_hash.to_cookie_string }} )

puts response