Getting Mechanize::UnauthorizedError: 401 => Net::HTTPUnauthorized when accessing API with Basic Auth
Getting Mechanize::UnauthorizedError: 401 => Net::HTTPUnauthorized when accessing API with Basic Auth
我正在尝试使用基本身份验证访问 API。它适用于 HTTParty,但不适用于 2.7.6 Mechanize。
这是我试过的:
agent = Mechanize.new
agent.log = Logger.new(STDERR)
agent.add_auth("https://website.net/listingapi", "user", "pass")
page = agent.get("https://website.net/listingapi")
这就是我得到的:
INFO -- : Net::HTTP::Get: /listingapi
DEBUG -- : request-header: accept-encoding => gzip,deflate,identity
DEBUG -- : request-header: accept => */*
DEBUG -- : request-header: user-agent => Mechanize/2.7.6 Ruby/2.5.3p105 (http://github.com/sparklemotion/mechanize/)
DEBUG -- : request-header: accept-charset => ISO-8859-1,utf-8;q=0.7,*;q=0.7
DEBUG -- : request-header: accept-language => en-us,en;q=0.5
DEBUG -- : request-header: host => website.net
INFO -- : status: Net::HTTPUnauthorized 1.1 401 Unauthorized
DEBUG -- : response-header: content-type => application/json; charset=utf-8
DEBUG -- : response-header: www-authenticate => Bearer, Basic realm=ListingApi
DEBUG -- : response-header: date => Wed, 13 Mar 2019 14:14:51 GMT
DEBUG -- : response-header: content-length => 61
DEBUG -- : response-header: x-xss-protection => 1; mode=block
DEBUG -- : response-header: strict-transport-security => max-age=31536000
DEBUG -- : response-header: x-content-type-options => nosniff
DEBUG -- : Read 61 bytes (61 total)
Mechanize::UnauthorizedError: 401 => Net::HTTPUnauthorized for https://website.net/listingapi/ -- no credentials found, provide some with #add_auth -- available realms:
from /Users/nk/.rvm/gems/ruby-2.5.3@mygems/gems/mechanize-2.7.6/lib/mechanize/http/agent.rb:749:in `response_authenticate'
我做错了什么,或者 API 响应有什么问题?
PS。我发现了这个,我认为这可能是相关的:https://github.com/sparklemotion/mechanize/pull/442
当使用basic auth时,用户名和密码连接在一起,然后使用base64编码。使用 Basic
在 Authorization
header 中将编码结果字符串发送到服务器
如果您在使用 add_auth
时遇到问题,现在可以采取的解决方法是您自己通过授权 header:
username = 'Radu'
password = 'mypassword'
agent = Mechanize.new do |agent|
agent.pre_connect_hooks << lambda { |agent, request| request["Authorization"] = "Basic #{Base64.strict_encode64(username + ':' + password)}" }
end
page = agent.get("https://website.net/listingapi")
编辑 1
现在我再次阅读日志,我可以看到 www-authenticate
header 说 Bearer, Basic realm=ListingApi
。相反,它应该说 Basic realm=ListingApi
.
问题是 response_authenticate can't find any challange most likely because the API you're requesting does not respect this part of RFC7235 关于挑战。
缺少的挑战在this line
后提出401
[1] pry(main)> authenticate_parser = Mechanize::HTTP::WWWAuthenticateParser.new
=> #<Mechanize::HTTP::WWWAuthenticateParser:0x00007fe2a5c74ec8 @scanner=nil>
[2] pry(main)> authenticate_parser.parse "Basic realm=ListingApi"
=> [#<struct Mechanize::HTTP::AuthChallenge scheme=nil, params=nil, raw=nil>]
[3] pry(main)> authenticate_parser.parse "Bearer, Basic realm=ListingApi"
=> []
编辑 2
HTTParty 工作的原因是他们直接在 Net::HTTP::Get 上添加了 Authorization header upfront。 Mechanize 使用整个 challenge-response 授权,他们只会在挑战方案为 Basic
.
时添加它
我正在尝试使用基本身份验证访问 API。它适用于 HTTParty,但不适用于 2.7.6 Mechanize。
这是我试过的:
agent = Mechanize.new
agent.log = Logger.new(STDERR)
agent.add_auth("https://website.net/listingapi", "user", "pass")
page = agent.get("https://website.net/listingapi")
这就是我得到的:
INFO -- : Net::HTTP::Get: /listingapi
DEBUG -- : request-header: accept-encoding => gzip,deflate,identity
DEBUG -- : request-header: accept => */*
DEBUG -- : request-header: user-agent => Mechanize/2.7.6 Ruby/2.5.3p105 (http://github.com/sparklemotion/mechanize/)
DEBUG -- : request-header: accept-charset => ISO-8859-1,utf-8;q=0.7,*;q=0.7
DEBUG -- : request-header: accept-language => en-us,en;q=0.5
DEBUG -- : request-header: host => website.net
INFO -- : status: Net::HTTPUnauthorized 1.1 401 Unauthorized
DEBUG -- : response-header: content-type => application/json; charset=utf-8
DEBUG -- : response-header: www-authenticate => Bearer, Basic realm=ListingApi
DEBUG -- : response-header: date => Wed, 13 Mar 2019 14:14:51 GMT
DEBUG -- : response-header: content-length => 61
DEBUG -- : response-header: x-xss-protection => 1; mode=block
DEBUG -- : response-header: strict-transport-security => max-age=31536000
DEBUG -- : response-header: x-content-type-options => nosniff
DEBUG -- : Read 61 bytes (61 total)
Mechanize::UnauthorizedError: 401 => Net::HTTPUnauthorized for https://website.net/listingapi/ -- no credentials found, provide some with #add_auth -- available realms:
from /Users/nk/.rvm/gems/ruby-2.5.3@mygems/gems/mechanize-2.7.6/lib/mechanize/http/agent.rb:749:in `response_authenticate'
我做错了什么,或者 API 响应有什么问题?
PS。我发现了这个,我认为这可能是相关的:https://github.com/sparklemotion/mechanize/pull/442
当使用basic auth时,用户名和密码连接在一起,然后使用base64编码。使用 Basic
在Authorization
header 中将编码结果字符串发送到服务器
如果您在使用 add_auth
时遇到问题,现在可以采取的解决方法是您自己通过授权 header:
username = 'Radu'
password = 'mypassword'
agent = Mechanize.new do |agent|
agent.pre_connect_hooks << lambda { |agent, request| request["Authorization"] = "Basic #{Base64.strict_encode64(username + ':' + password)}" }
end
page = agent.get("https://website.net/listingapi")
编辑 1
现在我再次阅读日志,我可以看到 www-authenticate
header 说 Bearer, Basic realm=ListingApi
。相反,它应该说 Basic realm=ListingApi
.
问题是 response_authenticate can't find any challange most likely because the API you're requesting does not respect this part of RFC7235 关于挑战。
缺少的挑战在this line
后提出401[1] pry(main)> authenticate_parser = Mechanize::HTTP::WWWAuthenticateParser.new
=> #<Mechanize::HTTP::WWWAuthenticateParser:0x00007fe2a5c74ec8 @scanner=nil>
[2] pry(main)> authenticate_parser.parse "Basic realm=ListingApi"
=> [#<struct Mechanize::HTTP::AuthChallenge scheme=nil, params=nil, raw=nil>]
[3] pry(main)> authenticate_parser.parse "Bearer, Basic realm=ListingApi"
=> []
编辑 2
HTTParty 工作的原因是他们直接在 Net::HTTP::Get 上添加了 Authorization header upfront。 Mechanize 使用整个 challenge-response 授权,他们只会在挑战方案为 Basic
.