2010-03-09 3 views
76

Обновление: основано на комментарий Ли я решил уплотнить мой код очень простой скрипт и запустить его из командной строки:Python urllib2 Basic Auth Проблема

import urllib2 
import sys 

username = sys.argv[1] 
password = sys.argv[2] 
url = sys.argv[3] 
print("calling %s with %s:%s\n" % (url, username, password)) 

passman = urllib2.HTTPPasswordMgrWithDefaultRealm() 
passman.add_password(None, url, username, password) 
urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(passman))) 

req = urllib2.Request(url) 
f = urllib2.urlopen(req) 
data = f.read() 
print(data) 

К сожалению, до сих пор не генерировать заголовок Authorization . (в Wireshark) :(

у меня проблема отправки основной AUTH над urllib2 я смотрел на this article, и последовал примеру Мой код:.

passman = urllib2.HTTPPasswordMgrWithDefaultRealm() 
passman.add_password(None, "api.foursquare.com", username, password) 
urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(passman))) 

req = urllib2.Request("http://api.foursquare.com/v1/user")  
f = urllib2.urlopen(req) 
data = f.read() 

Я вижу следующий на проводах с помощью Wireshark:

GET /v1/user HTTP/1.1 
Host: api.foursquare.com 
Connection: close 
Accept-Encoding: gzip 
User-Agent: Python-urllib/2.5 

Вы можете увидеть авторизацию не отсылается, против, когда я отправить запрос через завиток: curl -u user:password http://api.foursquare.com/v1/user

GET /v1/user HTTP/1.1 
Authorization: Basic =SNIP= 
User-Agent: curl/7.19.4 (universal-apple-darwin10.0) libcurl/7.19.4 OpenSSL/0.9.8k zlib/1.2.3 
Host: api.foursquare.com 
Accept: */* 

Для некоторых почему мой код, похоже, не отправляет аутентификацию - кто-нибудь видит, что мне не хватает?

благодаря

-simon

+1

Интересно, проблема в том, что сайт не возвращает заголовок '' WWW-Authenticate''. Вы можете проверить это, используя 'try: urllib2.urlopen (req), кроме urllib2.HTTPError, e: print e.headers' [См. Этот ответ SO post] (http: // stackoverflow.ком/а/9698319/1020470). –

ответ

186

Проблема может быть, что библиотеки Python, в HTTP-Standard, первая отправить запрос неаутентифицированную, и только если он ответил с 401 повторами, являются правильным учетной посланным. Если серверы Foursquare не выполняют «полностью стандартную проверку подлинности», тогда библиотеки не будут работать.

Попробуйте использовать заголовки, чтобы сделать проверку подлинности:

import urllib2, base64 

request = urllib2.Request("http://api.foursquare.com/v1/user") 
base64string = base64.b64encode('%s:%s' % (username, password)) 
request.add_header("Authorization", "Basic %s" % base64string) 
result = urllib2.urlopen(request) 

была такая же проблема, как вы и нашли решение этой темы: http://forums.shopify.com/categories/9/posts/27662

+3

Спасибо, человек, полностью спас мой день! – Ulf

+0

Ошибка HTTP 505: HTTP-версия не поддерживается; ( –

+0

Работает с аутентификацией PayPal (для получения доступа). Спасибо большое! Mate! – DerShodan

4

Второй параметр должен быть URI, а не имя домена. т.е.

passman = urllib2.HTTPPasswordMgrWithDefaultRealm() 
passman.add_password(None, "http://api.foursquare.com/", username, password) 
+0

Спасибо - я должен был упомянуть, что пробовал это в нескольких комбинациях 'http: // api.foursquare.com',' api.foursquare.com', 'http: // api.foursquare.com/v1 /' , но это, похоже, не решает проблему. – Simon

+0

Я просто попробовал это на локальном сервере здесь, который требует базового auth, и с URL-адресом в add_password он работал нормально. Поэтому я предполагаю, что что-то еще происходит. – Lee

+0

Это будет работать, только если HTTP-ответ содержит код 401 Unauthorized ** _ и _ ** заголовок '' WWW-Authenticate''; см. [этот ответ SO post] (http://stackoverflow.com/a/9698319/1020470). –

4

(копировать-вставить/адаптированный https://stackoverflow.com/a/24048772/1733117).

Сначала вы можете подкласса urllib2.BaseHandler или urllib2.HTTPBasicAuthHandler и реализовать http_request, чтобы каждый запрос имел соответствующий заголовок Authorization.

import urllib2 
import base64 

class PreemptiveBasicAuthHandler(urllib2.HTTPBasicAuthHandler): 
    '''Preemptive basic auth. 

    Instead of waiting for a 403 to then retry with the credentials, 
    send the credentials if the url is handled by the password manager. 
    Note: please use realm=None when calling add_password.''' 
    def http_request(self, req): 
     url = req.get_full_url() 
     realm = None 
     # this is very similar to the code from retry_http_basic_auth() 
     # but returns a request object. 
     user, pw = self.passwd.find_user_password(realm, url) 
     if pw: 
      raw = "%s:%s" % (user, pw) 
      auth = 'Basic %s' % base64.b64encode(raw).strip() 
      req.add_unredirected_header(self.auth_header, auth) 
     return req 

    https_request = http_request 

Тогда, если вы ленивы, как я, установить обработчик глобально

api_url = "http://api.foursquare.com/" 
api_username = "johndoe" 
api_password = "some-cryptic-value" 

auth_handler = PreemptiveBasicAuthHandler() 
auth_handler.add_password(
    realm=None, # default realm. 
    uri=api_url, 
    user=api_username, 
    passwd=api_password) 
opener = urllib2.build_opener(auth_handler) 
urllib2.install_opener(opener) 
0

Я хотел бы предложить, что нынешнее решение использовать мой пакет urllib2_prior_auth, который решает эту проблему очень хорошо (я работаю на inclusion в стандартная библиотека.

+0

Уил позволяет открывать URL-адреса, такие как' urllib2.urlopen ('http: // USER: PASS @ example .com/path/') ' – ddofborg

+0

Это еще одна проблема. Вы уверены, что это не работает со стандартным' 'urllib2''? – mcepl

+0

Нет, это не работает :( – ddofborg

2

Вот что я использую для решения аналогичной проблемы, с которой я столкнулся при попытке получить доступ к API MailChimp. Это делает то же самое, только что отформатированное.

import urllib2 
import base64 

chimpConfig = { 
    "headers" : { 
    "Content-Type": "application/json", 
    "Authorization": "Basic " + base64.encodestring("hayden:MYSECRETAPIKEY").replace('\n', '') 
    }, 
    "url": 'https://us12.api.mailchimp.com/3.0/'} 

#perform authentication 
datas = None 
request = urllib2.Request(chimpConfig["url"], datas, chimpConfig["headers"]) 
result = urllib2.urlopen(request) 
+0

Отлично, это работает с python 2.6. 6 – dirceusemighini