使用 Django @csrf_exempt,request.session 总是空的

With Django @csrf_exempt, request.session is always empty

我被困在 django 中,如果有人能帮助我,我将不胜感激。

我需要一个第三方的入口点 API。所以我创建了一个视图并用 @csrf_exempt

装饰它

现在的问题是我无法访问我之前设置的任何会话变量。 编辑 - 我设置了多个会话变量,如用户电子邮件,以了解用户是否已经登录。我能够在调用第 3 方之前使用该会话 API。当第 3 方 API 发送响应时,他们不会发送 CSRF 令牌,因此我已将该视图从 csrf 中排除。收到有效回复后,我想更新我的数据库。为此,我需要知道我丢失的用户的电子邮件 ID,因为我不再有会话变量。

ppConfirmPaymentProcess 是另一个函数,处理由第 3 方 API 发送的 POST 数据。 一切正常,csrf_exempt 也正常,但我无法 request.session["foo"] 处理此请求。有人可以帮忙吗?

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

第 3 方 API 可能不是作为登录用户发送响应,当然也不是作为发起交易的用户。

您必须跟踪您向 API 发出的请求以及他们与哪个用户关联,可能在数据库中。当您从 API 获得响应时,您需要将其与那些记录进行匹配,加载相关用户的信息并进行适当的更新。

来自第 3 方的响应 API 与用户的会话完全分开;这意味着它可能会在单独的线程、进程甚至服务器中处理(取决于您的站点的设置方式),因此您需要使用一些跨越这些边界的机制来让用户了解付款结果(这意味着数据库或您为此设置的其他内容)。

request.session 将永远为空,因为它只能由您的系统初始化,一旦连接关闭,会话就会被销毁。对于新连接,设置新会话。由于您的 API 端点由第三方 API 直接触发,而没有触发任何其他端点,因此第三方无法设置会话。因此,request.session 为空。


尝试将信息存储在 request.POST 而不是 request.session 中,这是从第三方获取信息的最佳方式。

查看文档:https://docs.djangoproject.com/en/3.0/topics/http/sessions/

Django 存储标记为会话密钥的会话数据,如下所示:
{"session_key":sdfkjdsbks, "user_email":"abc@df.com"}

在存储用户电子邮件时打印并复制 request.session.session_key 并检查您是否再次在视图中获得相同的 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)

如果这有效,那么您可以将 session_key 发送给第 3 方 API 并请求他们在后续调用中发送 cookie 或数据中的相同会话密钥。并捕获会话密钥并在您的视图中强制加载会话。

我使用 Django 本身解决了它。不操纵会话 ID 或与数据库交互。

Step1: 调用第3方api

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

Step2: 在视图中接收来自第3方的回调。请注意我如何放置 csrf_exempt 而不是 login_required 以便第 3 方可以在没有 CSRF 令牌和会话的情况下向我的应用程序发送请求。这就像他们进入我的应用程序的入口点。 在此 callBackView 中执行一些操作并检查这是否确实是来自第 3 方的有效响应或是否有人试图入侵您的系统。 例如。检查 CHECKSUMTXNID 等,然后创建响应字典并在我的应用程序中使用 HttpResponseRedirect 将另一个 HTTP 响应发送到另一个资源,然后我将相关的 GET 参数传递给它。

这个特定的步骤恢复了我以前的会话,现在我有来自第 3 方的相关数据来处理我发送给他们的请求,我也在请求中得到了我的 session

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

我最喜欢这种方法,因为正如我之前提到的,我们不需要存储会话,Django 为我们做了。