游客购卡:不注册也能用,但不能不安全
【摘要】 游客购买能显著降低转化门槛,但代价是「订单和用户的绑定」要靠别的方式实现。这里有一条清晰的安全基线。
游客购买能显著降低转化门槛,但代价是「订单和用户的绑定」要靠别的方式实现。这里有一条清晰的安全基线。
能力凭证放在请求头里
订单交付后给用户一个能力凭证,放在 X-Payment-Token 头里,数据库只保存摘要而不是明文。
兑换码是预付凭证,游客卡是订单交付产物,两者的失败模式不一样。
兑换失败通常是「码不存在 / 已使用 / 过期」;游客购卡失败可能是「支付未确认 / 凭证过期 / 目标 Key 已停用」。
恢复链接的凭证不能进查询参数
它应该放在 URL 的 fragment 部分(# 之后)。fragment 不会发给服务器,也就不会进访问日志和 Referer 头。
价格用整数分存储,额度用整数(并且检查溢出),不能用浮点数。
支付前不交付 Key
订单未支付时不能提前把 Key 交出去,否则会出现「没付款但已经有可用 Key」的情况。
到期后续费应该从付款核验成功的时刻重新计时,未激活的 Key 则累加待激活天数。
游客也要能查用量
游客卡同样需要查询入口。查询凭证的机制在这里和普通用户是一样的。
用量统计的时间口径必须写清楚,是 UTC 还是某个业务时区,一周从哪天开始。
一旦这里含糊,用户看到的「今日用量」就会和他自己的记录对不上。
实操:支付回调的验签与幂等处理骨架。
游客卡的用量查询路径和普通 Key 完全一致。
import hashlib, hmac, json
def verify_notification(raw_body: bytes, headers: dict) -> bool:
# 1) 验签:用平台公钥对原始报文做 RSA/SM2 验签,
# 任何字段被改动都会导致验签失败
# verify_signature(raw_body, headers["signature"], PLATFORM_PUBLIC_KEY)
# 2) 核对业务字段:应用、商户、订单号、金额、交易状态
data = json.loads(raw_body)
if data["app_id"] != APP_ID or data["seller_id"] != SELLER_ID:
return False
if data["total_amount"] != str(expected_amount(data["out_trade_no"])):
return False
return data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED")
def handle(data):
# 3) 幂等:同一笔订单重复通知时直接返回成功,
# 绝不能重复加额度或重复发卡
order = load_order(data["out_trade_no"])
if order.paid_at:
return "SUCCESS"
with transaction():
settle_order(order) # 结算 + 加额度 + 发卡,原子完成
mark_paid(order, data)
return "SUCCESS"
# 浏览器返回地址和前端轮询到的状态,都不能作为支付成功的依据。
几个容易踩的坑
- 价格用浮点数存储,累加后账目对不上。
- 套餐改了之后已创建的订单也跟着变,用户看到的和付的不一样。
- 续费时没保留今日已用量,等于凭空多给了一份额度。
- 奖励金被撤销但已经被抵扣,产生了资损。
小结
把配置项和凭据都外置,是成本最低、收益最持久的一个工程习惯。
如果你正在评估方案,可以先注册一个 Key 跑通最小请求,再决定要不要迁移——https://aiminis.info/ 支持按量计费,试用成本很低。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)