Python urllib2 Temel Kimlik Doğrulama Sorunu


81

Güncelleme: Lee'nin yorumuna dayanarak, kodumu gerçekten basit bir betiğe yoğunlaştırmaya ve komut satırından çalıştırmaya karar verdim:

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)

Maalesef yine de Authorizationbaşlığı oluşturmayacak (Wireshark başına) :(

Urllib2 üzerinden temel AUTH gönderirken sorun yaşıyorum. Bu makaleye bir göz attım ve örneği takip ettim . Kodum:

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()

Wire'da wireshark aracılığıyla şunları görüyorum:

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

Curl aracılığıyla bir istek gönderdiğimde, Yetkilendirmenin gönderilmediğini görebilirsiniz: 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: */*

Nedense kodum kimlik doğrulamasını göndermiyor gibi görünüyor - kimse neyi kaçırdığımı görüyor mu?

Teşekkürler

-Simon


1
Sorunun sitenin bir 'WWW-Authenticate'başlık döndürmemesi olup olmadığını merak ediyorum . Bunu, try: urllib2.urlopen(req) except urllib2.HTTPError, e: print e.headers Bu SO gönderi yanıtına bakın seçeneğini kullanarak kontrol edebilirsiniz .
Mark Mikofski

Yanıtlar:


199

Sorun, Python kitaplıklarının HTTP Standardı başına ilk önce kimliği doğrulanmamış bir istek göndermesi ve ardından yalnızca 401 yeniden denemesiyle yanıtlanması durumunda doğru kimlik bilgilerinin gönderilmesi olabilir. Foursquare sunucuları "tamamen standart kimlik doğrulaması" yapmazsa, kütüphaneler çalışmayacaktır.

Kimlik doğrulaması yapmak için üstbilgileri kullanmayı deneyin:

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)

Sizinle aynı sorunu yaşadım ve bu konu başlığındaki çözümü buldum: http://forums.shopify.com/categories/9/posts/27662


HTTP Hatası 505: Desteklenmeyen HTTP Sürümü; (
Daniel Magnusson

Paypal kimlik doğrulaması ile de çalışır (access_token almak için). Çok teşekkürler dostum!
DerShodan

3
base64.b64encodeBunun yerine basit arama base64.encodestringyapabileceğinizi ve ardından yeni satırı değiştirmeniz gerekmediğini unutmayın.
Trey Stout

Teşekkürler @TreyStout, önerinizi eklemek için çözümü düzenledim.
yayitswei

Benzer sorun burada ... Yüklenen yetkili sayfanın tarayıcı içeriğinde ve iptal düğmesine tıklarsam şifre sayfası içeriğini görebilirim
Mostafa

5

( https://stackoverflow.com/a/24048772/1733117 adresinden kopyalayıp yapıştırın / uyarlanmıştır ).

İlk olarak, urllib2.BaseHandlerveya her isteğin uygun başlığa sahip olması için alt sınıflara ayırabilir urllib2.HTTPBasicAuthHandlerve uygulayabilirsiniz .http_requestAuthorization

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

O zaman benim gibi tembelsen, işleyiciyi global olarak kur

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)

5

MailChimp'in API'sine erişmeye çalışırken karşılaştığım benzer bir sorunla başa çıkmak için kullandığım şey. Bu aynı şeyi yapar, sadece daha güzel biçimlendirilir.

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)

4

İkinci parametre bir alan adı değil, bir URI olmalıdır. yani

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

1
Teşekkürler - Ben farklı kombinasyonlar bir dizi denedik bahsetmeliydik http://api.foursquare.com, api.foursquare.com, http://api.foursquare.com/v1/ama bu sorunu çözmek için görünmüyor.
Simon

Bunu burada temel kimlik doğrulama gerektiren yerel bir sunucuya karşı denedim ve add_password'deki URL ile iyi çalıştı. Bu nedenle, başka bir şeyin yolda olduğunu öneririm.
Lee

Bu yalnızca http yanıtı 401 Unauthorized kodunu ve başlığı içeriyorsa çalışır 'WWW-Authenticate'; bkz bu SO sonrası cevabı .
Mark Mikofski

0

Şu anki çözümün, bunu oldukça güzel bir şekilde çözen urllib2_prior_auth paketimi kullanmak olduğunu öneririm ( standart lib'ye dahil etmek için çalışıyorum .


Böyle URL'lerin açılmasına izin urllib2.urlopen('http://USER:PASS@example.com/path/')
verilsin

Bu başka bir sorundur. Bunun standartla çalışmadığından emin misiniz urllib2?
mcepl
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.