Django中如何不使用全局变量将order_id从send_request视图传递至verify视图
支付场景下order_id跨视图传递的安全实现方案
首先全局变量的方案确实不可用:生产环境多为多进程/多线程部署,全局变量会在不同用户的请求之间串数据,极易出现订单对应错误的严重线上问题,你的顾虑是完全合理的。以下是3种可行的实现方案,按推荐优先级排序:
方案1:将order_id拼接在回调地址参数中(最推荐)
- 实现逻辑:Zarinpal等支付平台回调你的
verify接口时,会原封不动返回你提交的回调地址中携带的query参数,直接在构造回调地址时把order_id拼进去即可,不需要额外存储,成本最低。 - 改造后的
send_request代码示例:
from django.urls import reverse def send_request(request , order_id): amount = get_object_or_404(Order , id = order_id , user_id = request.user.id) # 构造带order_id参数的回调地址 callback_url = request.build_absolute_uri(reverse('verify')) + f'?order_id={order_id}' result = client.service.PaymentRequest(MERCHANT , amount.total , description , email , mobile , callback_url) if result.Status == 100 : return redirect('https://www.zarinpal.com/pg/StarPay' + str(result.Authority)) else : return HttpResponse(f'error code : {str(result.Status)}')
verify视图取值逻辑:
def verify(request): order_id = request.GET.get('order_id') # 先做合法性校验,避免恶意请求篡改其他订单状态 if not order_id: return HttpResponse("无效请求") order = get_object_or_404(Order, id=order_id, user_id=request.user.id) # 后续执行支付结果校验、订单状态更新逻辑即可
注意:拿到order_id后必须校验订单归属、订单状态是否为待支付,避免被恶意构造请求篡改数据。
方案2:关联存储order_id和支付平台返回的Authority字段
- 实现逻辑:调用支付请求成功后会拿到全局唯一的
Authority字段,支付平台回调时也会返回该字段,你只需要在发送请求时将Authority和对应order_id做关联存储,回调时用Authority查询对应order_id即可。 - 操作步骤:
- 给
Order表新增authority字段,或者单独建支付流水表关联order_id和authority send_request中拿到result.Authority后,写入对应订单的authority字段verify视图从回调参数中取出Authority,到数据库查询对应的order_id即可
- 给
- 优势:回调地址不会暴露order_id参数,适合对参数保密性要求高的场景。
方案3:使用Django Session存储(仅适合小流量场景)
- 实现逻辑:
send_request中将order_id写入用户session,verify视图中从session读取即可,session数据存储在服务端,相对安全。 - 局限:如果用户支付过程中更换浏览器、清除cookie,或者session过期会取不到值;另外部分支付平台的回调是服务端直接发起的,不会携带用户cookie,这种场景下session完全不可用。
内容的提问来源于stack exchange,提问作者alireza
相关产品推荐
相关产品推荐

