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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 04:54:44  来源:igfitidea点击:

HTTP basic authentication not working in python 3.4

pythonbasic-authentication

提问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 HTTPPasswordMgrcontains 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 HTTPPasswordMgrsearches (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 Nonerealm (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 HTTPPasswordMgrWithDefaultRealminstead of HTTPPasswordMgrto 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 HTTPPasswordMgrWithDefaultRealmtoHTTPPasswordMgrWithPriorAuthand pass is_authenticated=Truewhen call password_mgr.add_passwordworked for me.

当电话对我 有用时更改HTTPPasswordMgrWithDefaultRealmHTTPPasswordMgrWithPriorAuth并通过。is_authenticated=Truepassword_mgr.add_password

password_mgr = urllib.request.HTTPPasswordMgrWithPriorAuth()
password_mgr.add_password(None, url, username, password, is_authenticated=True)