【问题标题】:With Django @csrf_exempt, request.session is always empty使用 Django @csrf_exempt,request.session 始终为空
【发布时间】:2020-05-15 15:06:29
【问题描述】:

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

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

现在的问题是我无法访问我之前设置的任何会话变量。 edit - 我设置了多个会话变量,例如用户电子邮件,以了解用户是否已经登录。我能够在调用 3rd 方 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)

【问题讨论】:

  • 现在的问题是我无法访问我之前设置的任何会话变量。你是怎么做到的?
  • API 调用者是否注意为其所有调用发送相同的sessionid cookie?如果不是,那么 Django 会将每个调用视为一个新会话。
  • "我之前设置的变量。" ... 设置在 where 之前?在你的会话中?还是 API 用户?
  • 我有多个会话变量来检查用户是否登录。例如request.session["user_email"]=abc@gmail.com
  • 您的 API 入口点是 webhook 接收器吗?在这种情况下,API 调用将直接来自您的支付提供商,而不是您的客户,因此您将无法访问客户的会话。当您创建付款请求时,付款提供商会为您提供一个 ID,将其与您需要的任何其他信息一起存储在数据库中,并使用该 ID 进行关联。

标签: python django django-csrf


【解决方案1】:

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


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

【讨论】:

    【解决方案2】:

    见文档: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 中发送相同的会话密钥或在后续调用中发送数据。并捕获会话密钥并在您的视图中强制加载会话。

    【讨论】:

    • 嗨,Rahul,这似乎是一个可能的解决方案,我会尽力让您知道。谢谢
    【解决方案3】:

    我使用 Django 本身解决了它。不操纵 session-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 的,以便第三方可以在没有 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 为我们完成了。

    【讨论】:

      【解决方案4】:

      第 3 方 API 可能不会以登录用户的身份发送响应,当然也不会以发起交易的用户身份发送响应。

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

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

      【讨论】:

      • 这是我的问题中提到的。这是我要解决的基本问题
      • 是的,您需要使用回调中的信息来确定它响应的是哪个请求。在不知道 API 返回什么的情况下,我们无法真正帮助您,但希望您可以匹配某种“请求 ID”。一旦知道是哪个请求,就可以从那里查询数据库。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-26
      • 2022-01-13
      • 2014-01-08
      • 2016-07-23
      • 2017-03-12
      • 2018-03-07
      • 1970-01-01
      相关资源
      最近更新 更多