2016-04-01 6 views
3

Ich verwende requests, um mich auf meiner Django-Website zum Testen anmelden (und ja, ich weiß über den Django TestClient, aber ich brauche http http). Ich kann mich anmelden und, solange ich Anfragen bekomme, ist alles in Ordnung.Django und Python-Anfragen - 403 auf eine Anfrage anfordern

Wenn ich versuche post stattdessen zu verwenden, bekomme ich eine 403 von der csrf Middleware. Ich habe das bisher mit einem @crsf_exempt aus meiner Sicht versucht, würde aber eine längerfristige Lösung bevorzugen.

Dies ist mein Code:

with requests.Session() as ses: 

    try: 

     data = { 
      'username': self.username, 
      'password': self.password, 
     } 

     ses.get(login_url) 
     try: 
      csrftoken = ses.cookies["csrftoken"] 
     except Exception, e: 
      raise 
     data.update(csrfmiddlewaretoken=csrftoken) 

     _login_response = ses.post(login_url, data=data) 

     logger.info("ses.cookies:%s" % (ses.cookies)) 

     assert 200 <= _login_response.status_code < 300, "_login_response.status_code:%s" % (_login_response.status_code) 

     response = ses.post(
      full_url, 
      data=data, 
      ) 

     return self._process_response(response) 

Die Login funktioniert gut, und ich kann Token hier die csrf sehen.

INFO:tests.helper_fetch:ses.cookies:<RequestsCookieJar[<Cookie csrftoken=TmM97gnNHs4YCgQPzfNztrAWY3KcysAg for localhost.local/>, <Cookie sessionid=kj6wfmta 

Allerdings sieht die Middleware Cookies als leer.

INFO:django.middleware.csrf:request.COOKIES:{} 

Ich habe den Logging-Code hinzugefügt:

def process_view(self, request, callback, callback_args, callback_kwargs): 

    if getattr(request, 'csrf_processing_done', False): 
     return None 

    try: 
     csrf_token = _sanitize_token(
      request.COOKIES[settings.CSRF_COOKIE_NAME]) 
     # Use same token next time 
     request.META['CSRF_COOKIE'] = csrf_token 
    except KeyError: 
     # import pdb 
     # pdb.set_trace() 
     import logging 
     logger = logging.getLogger(__name__) 
     logger.info("request.COOKIES:%s" % (request.COOKIES)) 

Bin ich etwas mit Art und Weise ich abhanden Wunsch des session.post nennen? Ich habe versucht, Cookies hinzuzufügen, machte keinen Unterschied. Aber ich kann total sehen, warum crsf Middleware nervt. Ich dachte, die Kekse waren Teil der Sitzung, warum fehlen sie dann in meinem zweiten Beitrag?

  response = ses.post(
       self.res.full_url, 
       data=data, 
       cookies=ses.cookies, 
       ) 

Diese Variante, die von How to send cookies in a post request with the Python Requests library? inspiriert zeigte jedoch auch nicht in irgendetwas zu csrf Middleware übergeben wird:

nach dem Login
  response = ses.post(
       self.res.full_url, 
       data=data, 
       cookies=dict(csrftoken=csrftoken), 
       ) 

Antwort

4

Für nachfolgende Anforderungen, versuchen Sie es als Kopf liefert X-CSRFToken statt.

Das funktionierte für mich folgendes:

with requests.Session() as sesssion: 
    response = session.get(login_url) 
    response.raise_for_status() # raises HTTPError if: 400 <= status_code < 600 

    csrf = session.cookies['csrftoken'] 
    data = { 
     'username': self.username, 
     'password': self.password, 
     'csrfmiddlewaretoken': csrf 
    } 


    response = session.post(login_url, data=data) 
    response.raise_for_status() 

    headers = {'X-CSRFToken': csrf, 'Referer': url} 
    response = session.post('another_url', data={}, headers=headers) 
    response.raise_for_status() 

    return response # At this point we probably made it 

Docs Referenz: anstelle des csrf_exempthttps://docs.djangoproject.com/en/dev/ref/csrf/#csrf-ajax

+0

Danke für Ihre Hilfe. Habe es funktioniert, OK, ich musste einige Änderungen vornehmen, was sehr lange dauerte, bis ich herausgefunden habe, dass sich das csrf-Token ** nach 'session.post (login_url, data = data)' ändert **. Und dieses veränderte Token muss in "X-CSRFToken" gehen. Aber es sieht ziemlich gut aus und X-CSRFToken stimmt mit dem überein, was ich für JS Ajax-Posts mache. Was ich tun werde ist, meine Antwort am Ende der Woche zu schreiben - mit dem aufgeräumten Code - und akzeptiere deine Antwort, um mich in die richtige Richtung zu weisen. Behalte es für jetzt offen, denn das war kein billiges Kopfgeld und jemand hat vielleicht eine andere großartige Antwort. Pass auf. –

+0

Wenn ich es bis Montag noch nicht angenommen habe, gib mir einen Buzz. Ich gehe davon aus, dass SO dir trotzdem die 100 Punkte geben würde, wenn ich die Bounty-Dauer überschreite, aber ich möchte nicht, dass du das Kopfgeld verpasst, wenn das nicht der Fall ist. –

+0

Mach dir keine Sorgen über das Kopfgeld! Ich habe gerade diese Frage beantwortet, weil ich es vor einiger Zeit gelöst habe. Sie haben recht, das csrf-Token ändert sich nach dem Post-Login, aber wenn Sie Sessions verwenden, wird es transparent für Sie gehandhabt. Für eine vollständige Lösung können Sie meine Bibliothek auf github (die auf Kontrollprüfungen zugreift) auf genau die Art und Weise testen, wie Sie es tun: https: // github.com/stphivos/fnval/blob/master/fnval/net.py # L41 – fips

1

Sie auch this decorator auf Ihrer Ansicht verwenden könnten versuchen. Ich habe versucht, dein Problem zu reproduzieren, und das hat auch für mich funktioniert.

from django.views.decorators.csrf import ensure_csrf_cookie` 

@ensure_csrf_cookie 
def your_login_view(request): 
    # your view code 
+0

Der Job 'secure_csrf_cookie' soll sicherstellen, dass ein csrf-Token ausgeht, auch wenn auf der Seite kein Formular vorhanden ist. Ich habe dieses Problem nicht - mein write-up sagt ausdrücklich, dass ich das csrf_token sehen kann, ich weiß nur nicht, wie man es an das tatsächliche Ziel (nicht den Login) POST zurückgibt. –

+0

Ok, danke für deinen Kommentar, das Wichtigste hier ist, dass du eine Lösung findest, die für dich funktioniert;) und dass wir, die helfen wollen, das zu erreichen, daran denken, und es war mein Ziel;) . Nochmals vielen Dank und viel Glück! –