HTTP 基本身份验证在 python 3.4 中不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29708708/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
HTTP basic authentication not working in python 3.4
提问by Vab
I am trying to login to a REST API using HTTP Basic Authentication but it is not working and giving the error
我正在尝试使用 HTTP 基本身份验证登录到 REST API,但它不工作并给出错误
HTTP error 400: Bad Request
Here is my code:
这是我的代码:
import urllib.parse
import urllib.request
import urllib.response
# create an authorization handler
#auth_handler = urllib.request.HTTPPasswordMgrWithDefaultRealm()
auth_handler = urllib.request.HTTPBasicAuthHandler()
# Add the username and password.
# If we knew the realm, we could use it instead of None.
userName = "username"
passWord = "pass"
top_level_url = "http URL"
auth_handler.add_password(None, top_level_url, userName,passWord)
# create "opener" (OpenerDirector instance)
opener = urllib.request.build_opener(auth_handler)
# Install the opener.
# Now all calls to urllib.request.urlopen use our opener.
urllib.request.install_opener(opener)
# use the opener to fetch a URL
try:
result = opener.open(top_level_url)
#result = urllib.request.urlopen(top_level_url)
messages = result.read()
print (messages)
except IOError as e:
print (e)
回答by larsks
Updated for Python 3.x compatibility.
针对 Python 3.x 兼容性进行了更新。
The requestslibrary offers a far easier way of making this sort of request:
该要求的库提供的使这种请求的远更简单的方法:
import requests
response = requests.get('http://service.example.com',
auth=requests.auth.HTTPBasicAuth(
'username', 'password'))
print(response.text)
In my own testing this works out fine, while a solution involving urllib.request
(like yours, or using the code verbatim from the examples in the documentation) will fail to send the Authentication:
header.
在我自己的测试中,这很好,而涉及的解决方案urllib.request
(如您的,或使用文档中示例中的逐字代码)将无法发送Authentication:
标头。
回答by Anti Veeranna
I would also use requests library as recommended by larsks, it makes HTTP requests so much easier.
我也会使用 larsks 推荐的请求库,它使 HTTP 请求变得更加容易。
That said, here is a working code sample using urllib
也就是说,这是一个使用 urllib 的工作代码示例
import urllib.parse
import urllib.request
import urllib.response
username = "my_username"
password = "my_password"
top_level_url = "URL"
# create an authorization handler
p = urllib.request.HTTPPasswordMgrWithDefaultRealm()
p.add_password(None, top_level_url, username, password)
auth_handler = urllib.request.HTTPBasicAuthHandler(p)
opener = urllib.request.build_opener(auth_handler)
urllib.request.install_opener(opener)
try:
result = opener.open(top_level_url)
messages = result.read()
print (messages)
except IOError as e:
print (e)
Another detail - I tried your own code sample and I got back "http 401 unauthorized", which would be the expected response in case of failed or missing auth.
另一个细节 - 我尝试了你自己的代码示例,我得到了“http 401 未经授权”,这将是在身份验证失败或丢失的情况下的预期响应。
However you claim that you got http 400 bad request, which leads me to think that you either have the wrong url or there is some other issue as well
但是您声称您收到了 http 400 错误请求,这让我认为您要么使用了错误的网址,要么还有其他一些问题
回答by Tobias Ernst
The following python3 code will work:
以下 python3 代码将起作用:
import urllib.request
import base64
req = urllib.request.Request(download_url)
credentials = ('%s:%s' % (username, password))
encoded_credentials = base64.b64encode(credentials.encode('ascii'))
req.add_header('Authorization', 'Basic %s' % encoded_credentials.decode("ascii"))
with urllib.request.urlopen(req) as response, open(out_file_path, 'wb') as
out_file:
data = response.read()
out_file.write(data)
回答by Vincent Maillol
urllib.request.HTTPBasicAuthHandler()
by default uses HTTPPasswordMgr
.
The HTTPPasswordMgr
contains a map that has the password from realm and the top_level_url
.
urllib.request.HTTPBasicAuthHandler()
默认情况下使用HTTPPasswordMgr
. 该HTTPPasswordMgr
包含映射有从境界和密码top_level_url
。
When you perform the request and the server returns 401. The returned HTTP headers contains:
当您执行请求并且服务器返回 401 时。返回的 HTTP 标头包含:
Www-Authenticate: Basic realm="a-value"
The HTTPPasswordMgr
searches (user, password) for the returned realm and a new request will be sent with (user, password).
HTTPPasswordMgr
返回的领域的搜索(用户,密码)和新请求将与(用户,密码)一起发送。
When you write:
当你写:
auth_handler = urllib.request.HTTPBasicAuthHandler()
# Never use None to realm parameter.
auth_handler.add_password(None, top_level_url, userName,passWord)
You expect that the server sends None
realm (but it's not possible). If you want your server to send an empty realm in Www-Autheader
, you should use
您希望服务器发送None
领域(但这是不可能的)。如果您希望您的服务器在 中发送一个空领域Www-Autheader
,您应该使用
auth_handler.add_password('', top_level_url, userName,passWord)
You can use HTTPPasswordMgrWithDefaultRealm
instead of HTTPPasswordMgr
to ignore the returned realm:
您可以使用HTTPPasswordMgrWithDefaultRealm
而不是HTTPPasswordMgr
忽略返回的领域:
auth_handler = urllib.request.HTTPBasicAuthHandler(
urllib.request.HTTPPasswordMgr()
)
auth_handler.add_password(None, top_level_url, userName,passWord))
If your server sends you a 400 response code, with your sample code, then the authentication was not asked.
如果您的服务器向您发送 400 响应代码和您的示例代码,则没有要求进行身份验证。
回答by crazygit
Below code is from https://docs.python.org/3.1/howto/urllib2.html, but not send auth info when request.
下面的代码来自https://docs.python.org/3.1/howto/urllib2.html,但在请求时不发送身份验证信息。
# create a password manager
password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
# Add the username and password.
# If we knew the realm, we could use it instead of None.
top_level_url = "http://example.com/foo/"
password_mgr.add_password(None, top_level_url, username, password)
handler = urllib.request.HTTPBasicAuthHandler(password_mgr)
# create "opener" (OpenerDirector instance)
opener = urllib.request.build_opener(handler)
# use the opener to fetch a URL
opener.open(a_url)
# Install the opener.
# Now all calls to urllib.request.urlopen use our opener.
urllib.request.install_opener(opener)
change the HTTPPasswordMgrWithDefaultRealm
toHTTPPasswordMgrWithPriorAuth
and pass is_authenticated=True
when call password_mgr.add_password
worked for me.
当电话对我
有用时更改HTTPPasswordMgrWithDefaultRealm
为HTTPPasswordMgrWithPriorAuth
并通过。is_authenticated=True
password_mgr.add_password
password_mgr = urllib.request.HTTPPasswordMgrWithPriorAuth()
password_mgr.add_password(None, url, username, password, is_authenticated=True)