Yêu cầu Python: POST yêu cầu thả tiêu đề ủy quyền


9

Tôi đang cố gắng thực hiện một yêu cầu POST API bằng thư viện yêu cầu Python. Tôi đang chuyển qua một Authorizationtiêu đề nhưng khi tôi thử gỡ lỗi, tôi có thể thấy rằng tiêu đề đang bị loại bỏ. Tôi không biết chuyện gì đang xảy ra.

Đây là mã của tôi:

access_token = get_access_token()
bearer_token = base64.b64encode(bytes("'Bearer {}'".format(access_token)), 'utf-8')
headers = {'Content-Type': 'application/json', 'Authorization': bearer_token}
data = '{"FirstName" : "Jane", "LastName" : "Smith"}'
response = requests.post('https://myserver.com/endpoint', headers=headers, data=data)

Như bạn có thể thấy ở trên, tôi đặt thủ công Authorizationtiêu đề trong các đối số yêu cầu, nhưng nó thiếu các tiêu đề của yêu cầu thực tế : {'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'python-requests/2.4.3 CPython/2.7.9 Linux/4.1.19-v7+'}.

Một thông tin bổ sung là nếu tôi thay đổi yêu cầu POST thành yêu cầu GET, Authorizationtiêu đề sẽ chuyển qua bình thường!

Tại sao thư viện này sẽ bỏ tiêu đề cho các yêu cầu POST và làm cách nào để nó hoạt động?

Sử dụng v2.4.3 của các yêu cầu lib và Python 2.7.9

Câu trả lời:


9

TLD

Url bạn đang yêu cầu chuyển hướng yêu cầu POST đến một máy chủ khác, vì vậy thư viện yêu cầu giảm Authoriztiontiêu đề vì sợ rò rỉ thông tin đăng nhập của bạn. Để khắc phục rằng bạn có thể ghi đè phương thức chịu trách nhiệm trong các yêu cầu 'Session lớp .

Chi tiết

Trong các yêu cầu 2.4.3, nơi duy nhất reqeuestsxóa Authorizationtiêu đề là khi yêu cầu được chuyển hướng đến một máy chủ khác. Đây là mã có liên quan :

if 'Authorization' in headers:
    # If we get redirected to a new host, we should strip out any
    # authentication headers.
    original_parsed = urlparse(response.request.url)
    redirect_parsed = urlparse(url)

    if (original_parsed.hostname != redirect_parsed.hostname):
        del headers['Authorization']

Trong các phiên bản mới hơn của requests,Authorization tiêu đề sẽ bị loại bỏ trong các trường hợp bổ sung (ví dụ: nếu chuyển hướng là từ một giao thức an toàn sang không an toàn).

Vì vậy, những gì có thể xảy ra trong trường hợp của bạn, là các yêu cầu POST của bạn được chuyển hướng đến một máy chủ khác. Cách duy nhất bạn có thể cung cấp xác thực cho máy chủ được chuyển hướng bằng thư viện yêu cầu, là thông qua một .netrctệp. Đáng buồn thay, điều đó sẽ chỉ cho phép bạn sử dụng HTTP Basic Auth, điều này không giúp bạn nhiều. Trong trường hợp đó, giải pháp tốt nhất có lẽ là phân lớp requests.Sessionvà ghi đè hành vi này, như vậy:

from requests import Session

class NoRebuildAuthSession(Session):
    def rebuild_auth(self, prepared_request, response):
        """
        No code here means requests will always preserve the Authorization
        header when redirected.
        Be careful not to leak your credentials to untrusted hosts!
        """

session = NoRebuildAuthSession()
response = session.post('https://myserver.com/endpoint', headers=headers, data=data)

1
Cảm ơn, đây là vấn đề!
user4184113

0

Đây là những gì tài liệu yêu cầu nói:

Authorization headers set with headers= will be overridden if credentials are specified in .netrc, which in turn will be overridden by the auth= parameter. Authorization headers will be removed if you get redirected off-host.

Bạn có được chuyển hướng trong yêu cầu của bạn?

Nếu đây là trường hợp, hãy thử vô hiệu hóa chuyển hướng với tùy chọn này trong yêu cầu bài viết:

allow_redirects=False


allow_redirects=Falsesẽ chỉ ngăn các yêu cầu theo chuyển hướng được yêu cầu bởi máy chủ. Điều này sẽ không giúp hoàn thành yêu cầu, nó sẽ chỉ dừng lại ở giữa.
kmaork

0

Vấn đề đầu tiên (và có thể là thực tế) tôi thấy là cách bạn tạo bearer_tokenvì bạn không chỉ mã hóa mã thông báo mà còn cả loại xác thực'Bearer'

Theo tôi hiểu, bạn chỉ cần mã hóa mã thông báo và phải cung cấp loại xác thực trống + mã thông báo được mã hóa trong tiêu đề yêu cầu của bạn:

bearer_token = str(base64.b64encode(access_token.encode()), "utf8")
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(bearer_token)}

Nếu đó cũng là một vấn đề chuyển hướng, bạn có thể chỉ cần tìm đúng vị trí và đưa ra yêu cầu của bạn tới url này hoặc bạn có thể nghĩ đến việc gửi mã thông báo truy cập trong cơ thể POSTnếu máy chủ chấp nhận điều này.


0

Từ tài liệu: Requests will attempt to get the authentication credentials for the URL’s hostname from the user’s netrc file. The netrc file overrides raw HTTP authentication headers set with headers=. If credentials for the hostname are found, the request is sent with HTTP Basic Auth.

Nếu bạn đang được chuyển hướng, bạn có thể thử sử dụng allow_redirects=false


-1

bạn có thể thử sử dụng ủy quyền tùy chỉnh trong các tiêu đề.

Xác định một lớp xác thực tùy chỉnh:

class MyAuth(requests.auth.AuthBase):
def __init__(self, bearer_token):
    self.username = None
    self.bearer_token = bearer_token

def __call__(self, r):
    r.headers['Authorization'] = self.bearer_token
    return r

sau đó sử dụng để gửi yêu cầu:

headers = {'Content-Type': 'application/json'}

data = '{"FirstName" : "Jane", "LastName" : "Smith"}'

response = requests.post('https://myserver.com/endpoint', headers=headers, auth=MyAuth(bearer_token), data=data)

Nếu điều này hoạt động xin vui lòng chấp nhận câu trả lời. Hoặc nếu bạn vẫn có vấn đề, hãy cho chúng tôi biết. Hi vọng điêu nay co ich.


Không cần phải thừa kế từ requests.auth.AuthBase. Nếu bạn nhìn vào mã nguồn cho nó, bạn sẽ thấy rằng tất cả những gì nó làm sẽ tăng lên NotImplementednếu bạn quên ghi đè __call__.
Phục hồi lại

Điều này sẽ không thay đổi hành vi được mô tả trong câu hỏi. Khi xây dựng lại auth trên chuyển hướng, các yêu cầu không sử dụng đối số auth.
kmaork
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.