You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何限制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. 常见误区提醒

  • Stripepk_开头的公钥本来就是设计给前端用的,可以公开暴露,不需要藏,只有sk_开头的密钥必须全程留在服务端
  • 永远不要把支付金额、商品信息这类核心交易参数完全交给前端传,所有交易数据以后端存储的订单记录为准,防止被篡改
  • 不要为了调试方便临时关掉CSRF校验、登录校验,上线前一定要把这些安全中间件全部打开

内容的提问来源于stack exchange,提问作者bernardo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 20:57:21