繁体   English   中英

在 django 中调用回调 URL 时出现 Forbidden (403) 错误

[英]Forbidden (403) error when calling the callback URL in django

我正在开发 django webapp。 我将paytm 支付网关与 django 应用程序连接起来。 我根据文档做了一切,一切正常。 几乎。

付款结束后,我在调用回调 URL 时遇到问题。

这是代码

视图.py

def donate(request):
    if request.method == "POST":
        form = DonateForm(request.POST)

        name = request.POST.get('firstName')
        phone = request.POST.get('phone')
        email = request.POST.get('email')
        amount = float("{0:.2f}".format(int(request.POST.get('amount'))))
        ord_id = OrdID()
        cust_id = CustID()

        paytm_params = {
            "MID" : MERCHANTID,
            "WEBSITE" : "WEBSTAGING",
            "INDUSTRY_TYPE_ID" : "Retail",
            "CHANNEL_ID" : "WEB",
            "ORDER_ID" : ord_id,
            "CUST_ID" : cust_id,
            "MOBILE_NO" : phone,
            "EMAIL" : email,
            "TXN_AMOUNT" : str(amount),
            "CALLBACK_URL" : "http://127.0.0.1:8000/payment/status",

            }

        paytm_params['CHECKSUMHASH'] = Checksum.generate_checksum(paytm_params, MERCHANTKEY)

        return render(request, 'paytm.html', {'paytm_params': paytm_params})

    else:
        form = DonateForm()
        context = {'Donate': form}
        return render(request, 'donate.html', context=context)

@csrf_exempt
def handlerequest(request):
    if request.method == 'POST':
        form = request.POST
        response_dict = {}

        for i in form.keys():
            response_dict[i] = form[i]

            if i == 'CHECKSUMHASH':
                checksum = form[i]
                print(checksum)

        verify = Checksum.verify_checksum(response_dict, MERCHANTKEY, checksum)

        if verify:
            if response_dict['RESPCODE'] == '01':
                print('order successful')
            else:
                print('error: ' + response_dict['RESPMSG'])

        return render(request, 'paymentstatus.html', {'response': response_dict})

网址.py

path('donate', views.donate, name='donate'),
path('payment/status', views.handlerequest, name='handlerequest'),

捐赠.html

<form class="test_paytm" action="{% url 'donate' %}" method="post">
    {% csrf_token %}
    <div class="row">
        <div class="col">
            {{ Donate.firstName|as_crispy_field }}
        </div>
        <div class="col">
            {{ Donate.lastName|as_crispy_field }}
        </div>
    </div>
    <div class="row">
        <div class="col">
            {{ Donate.email|as_crispy_field }}
        </div>
        <div class="col">
            {{ Donate.phone|as_crispy_field }}
        </div>
    </div>
    <div class="row">
        <div class="col">
            {{ Donate.amount|as_crispy_field }}
        </div>
    </div>
    <button type="submit" name="button" class="btn btn-lg mb-5 contact_submit">Donate</button>
</form>

支付宝.html

<html>

<head>
  <title>Merchant Check Out Page</title>
</head>

<body>
  <center>
    <h1>Please do not refresh this page...</h1>
  </center>
  <form method="post" action="https://securegw.paytm.in/order/process" name="paytm">
    {% for key, value in paytm_params.items %}
    <input type="hidden" name="{{key}}" value="{{value}}">
    {% endfor %}
  </form>
</body>
<script type="text/javascript">
  document.paytm.submit()

</script>

</html>

付款状态.html

<div class="container">
  {% if response_dict.RESPCODE == 01 %}
  <center>
    <h2>Thank you for your donation</h2>
    <p>
      We are thrilled to have your support. Through your donation we will be able to accomplish our goal. You truly make the difference for us, and we are
      extremely grateful!
    </p>
  </center>

  <h3>Order ID: {{response_dict.ORDERID}}</h3>
  <h3>Order Date: {{response_dict.TXNDATE}}</h3>
  <h3>Amount: {{response_dict.TXNAMOUNT}}</h3>
  <h3>Payment Mode: {{response_dict.PAYMENTMODE}}</h3>

  {% else %}
  <center>
    <p>
      There seems to be a problem. We will try to fix this from our end.
    </p>
  </center>
  {% endif %}
</div>

但是一旦付款结束,该网站就不会正确地从views.py调用handlerequest 这就是为什么我添加了@csrf_exempt以便外部页面可以毫无问题地调用 url。 但我仍然收到 403 错误。 我不确定我做错了什么

编辑1

我已将paytm.html代码添加到问题中。 我个人不认为问题出在这个页面上,因为该页面所做的只是重定向到 paytm 的支付网关页面。 我面临的问题是返回到我的 url 时,即。 paymentstatus.html 那是通过handlerequest视图。 捐赠流程如下

  1. 用户在donate.html填写表单并单击捐赠按钮。
  2. paytm.html获取信息并自动路由到paytm支付网关
  3. 用户进行捐赠。
  4. URL 从 paytm 支付网关路由回我的 URL。
  5. 将显示paymentstatus.html页面。

由于从外部 url 调用paymentstatus.html页面, csrf_exempt需要csrf_exempt ,这是我提供的。 但由于某种原因不起作用

[编辑 2]

当我与 Paytm 的技术团队交谈时,他们告诉我必须在 POST 中接受回调 URL。 我与之交谈的人对 Django 几乎没有经验,无法进一步帮助我。 means.我不太确定意味着什么。 有人可以帮我吗?

[编辑 3]

编辑了handlerequest view

但是一旦付款结束,该网站就不会正确地从 views.py 调用 handlerequest。 这就是为什么我添加了 @csrf_exempt 以便外部页面可以毫无问题地调用 url。 但我仍然收到 403 错误。 我不确定我做错了什么

这个 403 错误是否来自您的服务器? 或者你只是在浏览器中看到 403 ......?

当您的回调网址为http://127.0.0.1:8000时,我不相信Paytm可以访问您的服务器。 为了让Paytm访问您的服务器,您需要在回调 url 中提供您的公共 IP 地址,然后将您的路由器配置为打开端口 8000,然后将所有请求从端口 8000 转发到您的机器。 但既然你没有提到你已经这样做了,我猜你还没有这样做。

设置回调网址:

这是非常简单的事情,你所要做的就是在你的 Django 应用程序中添加一个新的 url,然后用你正在调用的 API 注册它,我对 PAYTM 一点也不熟悉,但是你肯定会找到一个通过它注册的地方您的仪表板或者他们是否有 CLI 界面。

进入代码示例:

#urls.py
path('payment/status/', views.check_status, name='payment_status') # the same full url to register in callback url in their website

#views.py
@csrf_exempt # API doesn't know how to send you csrf token
def check_status(request):
    if request.method == 'POST':
        print(request.POST)# examine the data returned from the API

顺便说一句,如果您在本地进行测试,那么您需要公开您的网站以供外部世界访问,请查看 ngrok https://ngrok.com/

处理在线支付需要使用 SSL、HTTPS 进行处理。

您可以在提交后强制重定向,例如:

将以下存根放入付款表格中

<input type="hidden" name="next" value="{% url 'payment_status' %}" />

然后从你提交视图

# force the redirect to
return redirect(request.POST.get('next') or 'where_ever_you_send_your_user')

我认为您应该重定向而不是在捐赠视图中呈现该请求。 我认为您的 handlerequest 视图甚至没有被触及。 这是我在捐赠视图中看到的:

return render(request, 'paytm.html', {'paytm_params': paytm_params})

在您的 paymentstatus.html 模板中,您有:

{% if response_dict.RESPCODE == 01 %}

但是您传递了paytm_params的上下文,而不是response_dict 除非,你从来没有向我展示过paytm.html是什么。

编辑:

感谢您添加 paytm.html。 您应该尝试做几件事。

  1. 确保您的浏览器没有阻止 cookie。 有些人会阻止 cookie,这会破坏您的浏览器。
  2. 在表单顶部添加{% csrf_token %}标签。 CSRF 令牌很重要,因为它无处不在,无论页面如何。
  3. 尝试从您的视图中删除csrf_exempt
  4. 将 settings.py 中的 csrf 令牌的名称更改为其他名称,例如 csrftokenasdfasdfasdf
  5. 还有一种叫做 corsheader 的东西。 我相信他们的包被称为 django-cors-headers 并且他们有一个中间穿,你可以使用它,因为你在视图之间来回跳跃。

我们来看两行代码

if request.method == 'POST':

"CALLBACK_URL" : "http://127.0.0.1:8000/payment/status",

这说明什么?

  1. 回调 URL 被发送到 Paytm 后端服务器。
  2. 设置请求处理程序以在您的服务器上接受 POST 请求。
  3. 最重要的是,您发送到 Paytm 服务器的服务器地址是 127.0.0.1
  4. 当支付网关在浏览器中重定向时,它总是一个 GET 请求。 (浏览器中所有的post请求都是ajax请求)

有了上述事实,让我们看看您的代码发生了什么。

有两种情况可能会发生

案例 1:Paytm 正在重定向到您在浏览器上的回调,但这将是一个 GET 请求,并且您的代码仅适用于 POST 请求。 如果这是真的,请将方法更改为 GET。

案例 2:Paytm 服务器正在向您的服务器发出 POST API 调用,但是,您已将 127.0.0.1 作为服务器 IP,并且 Paytm 服务器将无法通过环回连接到在您的本地机器上运行的服务器IP,因此您在服务器上看不到任何 POST 请求。 如果这是真的,请尝试将您的应用程序托管在某个云上并使用该机器的公共 IP,或者使用 ngrok 创建到您本地机器的隧道,并在回调 URL 中使用 ngrok URL。

我个人的意见是您的实施基于案例 1。

可能是回调 URL 的问题。 您可以通过自己调用 URL 来测试视图,看看它是否真正连接。 您的回调 URL 应该使用 POST 方法调用它:

http://127.0.0.1:8000/payment/status

如果这不起作用,请尝试添加结尾“/”并进行回调调用“url/payment/status/”

path('payment/status/', views.handlerequest, name='handlerequest') http://127.0.0.1:8000/payment/status/

POST 方法可以是这样的:

网址.py

urlpatterns = [
   url(r'^callback$', views.CallbackView.as_view())
]

视图.py

class CallbackViews(APIView):
    @csrf_exempt
    def post(self, request):
        # do something

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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