如何限制Django端点访问权限仅允许本人调用
你把Stripe密钥逻辑放在后端的思路是完全正确的,接口公开可访问本身不是问题——所有Web支付接口都是公开可访问的,核心问题是你没做访问控制和业务规则校验,才会导致接口可以被随意滥用。另外你当前贴的代码存在基础写法错误,函数视图里return render之后的嵌套get方法永远不会执行,属于死代码,需要先修正。
具体实现步骤
1. 修正Django视图的基础写法
支付类接口不要用GET方法,改用POST请求,避免被缓存、爬虫、浏览器预加载随意触发。参考写法如下:
# views.py import os import stripe from django.http import JsonResponse from django.views.decorators.http import require_http_methods from django.contrib.auth.decorators import login_required # 密钥从服务端环境变量读取,不要硬编码在代码里,不要提交到代码仓库 stripe.api_key = os.getenv("STRIPE_SECRET_KEY") @login_required # 第一步校验:只允许已登录的用户调用接口,未登录直接返回403 @require_http_methods(["POST"]) def payment(request): # 第二步:业务规则校验 # 1. 从请求里拿到用户要支付的订单ID,校验这个订单属于当前登录用户、且是未支付状态 order_id = request.json().get("order_id") if not order_id: return JsonResponse({"error": "缺少订单参数"}, status=400) order = get_object_or_404(Order, id=order_id, user=request.user, is_paid=False) # 2. 金额永远从后端已存的订单数据取,绝对不要信任前端传的金额参数 try: # 如果这个订单已经生成过支付凭证,直接返回已有凭证,不要重复调用Stripe if order.stripe_payment_intent_id: intent = stripe.PaymentIntent.retrieve(order.stripe_payment_intent_id) return JsonResponse({"client_secret": intent.client_secret}) # 没有有效凭证的话再调用Stripe生成新的 intent = stripe.PaymentIntent.create( amount=int(order.total_amount * 100), # Stripe金额最小单位是分 currency="cny", metadata={"order_id": order.id} ) # 把生成的凭证ID存到自己的订单记录里,避免重复生成 order.stripe_payment_intent_id = intent.id order.save() return JsonResponse({"client_secret": intent.client_secret}) except Exception as e: return JsonResponse({"error": "支付请求失败"}, status=400)
对应路由配置调整为:
# urls.py from django.urls import path from . import views urlpatterns = [ path("payment/", views.payment, name="payment"), ]
前端调用时改用POST请求,带上Django要求的CSRF令牌:
// 从cookie取Django生成的CSRF令牌的工具函数 function getCookie(name) { let cookieValue = null; if (document.cookie && document.cookie !== '') { const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } // 调用支付接口 const resp = await fetch("https://url.com/payment/", { method: "POST", headers: { "X-CSRFToken": getCookie("csrftoken"), "Content-Type": "application/json" }, body: JSON.stringify({ order_id: "当前页面要支付的订单ID" }) }) const data = await resp.json(); // 拿到client_secret之后再用Stripe前端SDK完成后续支付流程
2. 补充必要的安全防护规则
做完上面的基础逻辑后,再加几层防护就能完全避免接口被滥用:
- 加请求频率限制:同一个用户ID/IP1分钟内最多允许调用3次支付接口,防止恶意刷接口消耗Stripe调用额度
- 配置Stripe Webhook:支付结果永远以Stripe异步推送到你后端的Webhook通知为准,不要以前端返回的支付成功提示作为订单已支付的依据,Webhook接收端要校验Stripe的签名,防止伪造支付成功通知
- 区分密钥环境:开发测试环境用Stripe测试模式的
sk_test开头密钥,生产环境用sk_live开头的正式密钥,两个密钥不要混用,避免调试时产生真实扣费
3. 常见误区提醒
- Stripe
pk_开头的公钥本来就是设计给前端用的,可以公开暴露,不需要藏,只有sk_开头的密钥必须全程留在服务端 - 永远不要把支付金额、商品信息这类核心交易参数完全交给前端传,所有交易数据以后端存储的订单记录为准,防止被篡改
- 不要为了调试方便临时关掉CSRF校验、登录校验,上线前一定要把这些安全中间件全部打开
内容的提问来源于stack exchange,提问作者bernardo
相关产品推荐
相关产品推荐

