简体   繁体   中英

How can I detect the actual URL a client used to access a Django web service?

I have implemented an authentication scheme that mimics what Amazon does with S3 on my Django web service. Each request is signed using a secret. The string to sign includes among other things the URL of the resource being accessed.

For example, if a client issues a GET request for http://myservices.org/users the client must construct a string_to_sign that contains http://myservices.org/users . When the server processes the request it will also construct a string_to_sign and can include the same URL, based on information it learns from the WSGI wrapper request object.

My issue is that when the client decides to include the port number (eg http://myservices.org:80/users ) then the server code constructs an incorrect string_to_sign because I don't know how to get the actual URL that was used by the client. The WSGI wrapper does not let me know that the URL included the port number.

Is there a way for a Django application to learn the actual URL that was part of the HTTP request? Do I need to setup some sort of request handler that sits in front of the WSGI wrapper in order to get access to the raw HTTP request and pull the URL out myself?

You're asking for the impossible. All you have is the first line of the request which doesn't include the network location (hostname and port number). You normally get a Host header (HTTP 1.0 or better) which may or may not include the port number.

You might want to look at django-fost-authn which implements a scheme very similar to Amazon's.

Even if you don't use that and prefer your own, you should be able to see how the normalisation of the request is done there pre-signature calculation. The most pertinent observation is that it only uses factors inside the HTTP request itself. It allows for the addition of custom headers to be included in the signed header set, and you could insist that for what you want the Host header is signed.

Look particularly at how the document is generated in fost-authn/signature.py

Although it may not always work with varying browsers and HTTP versions, you can use request.META['HTTP_HOST'] . For my local development server right now this returns "localhost:8000", which I could then split by the colon in the middle to get both pieces separately.

Furthermore, you might find some use in the get_host() method on the HttpRequest class. From the Django documentation :

Returns the originating host of the request using information from the HTTP_X_FORWARDED_HOST (if USE_X_FORWARDED_HOST is enabled) and HTTP_HOST headers, in that order. If they don't provide a value, the method uses a combination of SERVER_NAME and SERVER_PORT as detailed in PEP 3333.

Example: "127.0.0.1:8000"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM