add
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
"""支付宝渠道:App 支付下单参数(本地 RSA2 签名)+ 回调 RSA2 验签。
|
||||
|
||||
密钥未配置(开发环境)时:下单返回 dev_mock 占位参数便于 App 联调,回调一律验签失败拒绝入账。
|
||||
生产接入:配置 ALIPAY_APP_ID / ALIPAY_PRIVATE_KEY(应用私钥)/ ALIPAY_PUBLIC_KEY(支付宝公钥)
|
||||
及 ALIPAY_NOTIFY_URL 后自动启用真实签名与验签。
|
||||
"""
|
||||
import json
|
||||
from datetime import datetime
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from app.config import settings
|
||||
from app.payment.base import build_sign_content, load_public_key, rsa2_sign, rsa2_verify
|
||||
|
||||
METHOD_APP_PAY = "alipay.trade.app.pay"
|
||||
PRODUCT_CODE = "QUICK_MSECURITY_PAY"
|
||||
DEFAULT_SUBJECT = "积分充值"
|
||||
ORDER_EXPIRE = "30m" # 与订单有效期保持一致
|
||||
|
||||
|
||||
def is_configured() -> bool:
|
||||
return bool(settings.alipay_app_id and settings.alipay_private_key and settings.alipay_public_key)
|
||||
|
||||
|
||||
def create_app_pay_params(order_no: str, amount_fen: int) -> dict:
|
||||
"""生成 App SDK 调起参数 order_string(未配置密钥时返回 dev 占位)"""
|
||||
if not is_configured():
|
||||
return {"dev_mock": True, "order_string": f"mock://alipay/{order_no}"}
|
||||
|
||||
biz_content = json.dumps({
|
||||
"out_trade_no": order_no,
|
||||
"total_amount": f"{amount_fen / 100:.2f}",
|
||||
"subject": DEFAULT_SUBJECT,
|
||||
"product_code": PRODUCT_CODE,
|
||||
"timeout_express": ORDER_EXPIRE,
|
||||
}, ensure_ascii=False, separators=(",", ":"))
|
||||
|
||||
params = {
|
||||
"app_id": settings.alipay_app_id,
|
||||
"method": METHOD_APP_PAY,
|
||||
"format": "JSON",
|
||||
"charset": "utf-8",
|
||||
"sign_type": "RSA2",
|
||||
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"version": "1.0",
|
||||
"biz_content": biz_content,
|
||||
}
|
||||
if settings.alipay_notify_url:
|
||||
params["notify_url"] = settings.alipay_notify_url
|
||||
if settings.alipay_return_url:
|
||||
params["return_url"] = settings.alipay_return_url
|
||||
|
||||
# 签名串不含 sign_type/sign,按 key 字典序拼接
|
||||
params["sign"] = rsa2_sign(build_sign_content(params), settings.alipay_private_key)
|
||||
# order_string 为全参数(含 sign)按 key 字典序 URL 编码后的查询串
|
||||
return {"order_string": urlencode(sorted(params.items()))}
|
||||
|
||||
|
||||
def verify_callback(form: dict) -> bool:
|
||||
"""RSA2 验签:用支付宝公钥校验回调 sign(未配置/格式错误一律拒绝)"""
|
||||
sign = form.get("sign", "")
|
||||
if not sign or not settings.alipay_public_key:
|
||||
return False
|
||||
try:
|
||||
load_public_key(settings.alipay_public_key)
|
||||
except Exception: # noqa: BLE001
|
||||
return False
|
||||
return rsa2_verify(build_sign_content(form), sign, settings.alipay_public_key)
|
||||
Reference in New Issue
Block a user