9

I am stuck in django and would really appreciate it if someone could help me.

I need to have an entry point for a 3rd party API. So I created a view and decorated it with @csrf_exempt

Now the problem is I am not able to access any session variables I set before. edit - I set multiple session variables like user email to know if a user is already logged in. I was able to use the session before calling the 3rd party API. When the 3rd party API sends a response, they don't send CSRF token hence I have exempt that view from csrf. Once I receive a valid response I want to update my database. To do that, I need to know the email id of the user which I lost since I don't have session variables anymore.

ppConfirmPaymentProcess is another function that processes the POST data sent by this 3rd party API. Everything is working fine, csrf_exempt is also working fine but I can't do request.session["foo"] with this request. Can someone please help?

@csrf_exempt
def ppConfirmPayment(request):
    print(request.session, "=======================================")
    for key, value in request.session.items():
        print('{} => {}'.format(key, value))
    return ppConfirmPaymentProcess(request)
GKV
  • 864
  • 1
  • 12
  • 25
  • 1
    _Now the problem is I am not able to access any session variables I set before._ how did you do that? – Kurohige May 15 '20 at 15:23
  • 1
    Is the API caller taking care to send the same `sessionid` cookie for all of its calls? If not, then Django will treat each call as a new session. – John Gordon May 15 '20 at 15:41
  • 1
    "variables I set before." ... Set before _where_ ? In your session? or the API user? – Basic May 15 '20 at 16:01
  • I have multiple session variables to check if a user is logged in. e.g. request.session["user_email"]=abc@gmail.com – GKV May 15 '20 at 16:03
  • 1
    Is your API entry point a webhook receiver? In which case the API call will come from your payment provider directly and not your client so you won't have access to the client's session. The payment provider will give you an ID when you create the payment request, store that in the database along with any other information you need and use that to correlate instead. – Andee May 21 '20 at 18:22
  • I have created a similar scenario for your case (my sample worked great) and it has nothing to do with csrf_exempt, would you give additional info on how you set your session variables? – scriptmonster May 23 '20 at 14:59
  • @csrf_exempt will bypass the login, and the user is AnonymousUser. It’s possible that you need to pass all of the data through post or get. Reference https://docs.djangoproject.com/en/3.0/ref/csrf/#django.views.decorators.csrf.csrf_exempt – caot May 24 '20 at 23:11

4 Answers4

1

request.session will always be empty because it can only be initialized by your system and once the connection is closed, the session is destroyed. For new connection, new session is set. Since, your API endpoint is triggered directly by the third-party API without triggering any other endpoint, there is no way that the third party can set the sessions. Hence, request.session is empty.


Try storing the information in request.POST instead of request.session , which is more optimal way of getting information from third party.

Damnik Jain
  • 374
  • 2
  • 11
1

See Docs: https://docs.djangoproject.com/en/3.0/topics/http/sessions/

Django stores session data tagged to session key something like this:
{"session_key":sdfkjdsbks, "user_email":"abc@df.com"}

Print and Copy the request.session.session_key when you are storing user email and check if you are getting the same session_key inside your view again.

if not then you can forcefully load the previous session inside view using the copied session key:

from importlib import import_module
from django.conf import settings

@csrf_exempt
def ppConfirmPayment(request):

    engine = import_module(settings.SESSION_ENGINE)

    # copy the old_session_key value from request when you saved user email
    request.session = engine.SessionStore(old_session_key)

    print(request.session, "=======================================")
    for key, value in request.session.items():
        print('{} => {}'.format(key, value))
    return ppConfirmPaymentProcess(request)

If this works then you can send session_key to 3rd party API and request them to send the same session key inside cookie or data in subsequent calls. And capture the session key and forcefully load the session inside your view.

  • hi Rahul, this seems like a possible solution, I will try and let you know. Thank you – GKV May 26 '20 at 06:02
0

I solved it using Django itself. No manipulation of session-id or interaction with the database.

Step1: call 3rd party api

@login_required
def thirdPartyAPICall(request):
    #do some stuff and send a request to 3rd party

Step2: receive a call-back from 3rd party in the view. Note how I put csrf_exempt and not login_required so that 3rd party can send a request to my application without CSRF token and session. It's like an entry point to my APP for them. In this callBackView do some action and check if this indeed is a valid response from the 3rd party or someone is trying to hack your system. E.g. check for CHECKSUM or TXNID etc and then create a response dictionary and sent another HTTP response to another resource using HttpResponseRedirect with-in my app and then I passed relevant GET parameter to it.

This particular step restores my previous session and now I have the relevant data from the 3rd party to process the request I sent to them and I also got my session back in the request.

@csrf_exempt
def callBackView(request):
     if request.POST["CHECKSUM"] == myCalCulatedCheckSum:
          foo = True
     else:
          foo = False
     return HttpResponseRedirect("TEST.HTML" +"/" + str(foo))

I like this method the most because as I mentioned before, we don't need to store session, Django does it for us.

GKV
  • 864
  • 1
  • 12
  • 25
-1

The 3rd-party API is probably not sending the response as a logged-in user, and certainly not as the user which initiated the transaction.

You'll have to keep track of the requests you've made to the API and which user they're associated with, probably in the database. When you get a response from the API, you'll need to match it up with those records, load the relevant user's information and make the appropriate update.

The response from the 3rd-party API is completely separate from the user's session; this means that it'll probably be processed in a separate thread, process or even server (depending on how your site is set up), so you'll need to use some mechanism which crosses these boundaries in order to let the user know about the outcome of the payment (which means either the database, or something else you've set up for this).

Jiří Baum
  • 6,697
  • 2
  • 17
  • 17
  • this is what mentioned in my question. That is the basic issue that I want to solve – GKV May 20 '20 at 09:53
  • Yes, you need to use the information in the callback to figure out which request it's in response to. We can't really help you with that without knowing what the API is returning, but hopefully there will be some sort of "request ID" that you can match up. Once you know which request it was, you can query the database from there. – Jiří Baum May 21 '20 at 07:37