ForcePilot/backend/package/yuxi/channel/extensions/jd/signature.py
Kris bb8ade9e2b feat(channel): 添加京东渠道扩展
新增京东(JD)渠道扩展,支持在 Yuxi 平台中集成京东客服渠道。

包含以下功能模块:
- client: 京东 API 客户端封装
- config: 渠道配置管理
- gateway: SSE/WebSocket 网关接入
- webhook: Webhook 事件处理
- outbound: 外发消息管理
- pairing: 用户配对与绑定
- security: 安全校验
- signature: 请求签名验证
- crypto: 加解密处理
- dedupe: 消息去重
- monitor: 渠道状态监控
- status: 会话状态管理
- session: 会话管理
- business: 业务逻辑处理
- types: 类型定义
2026-05-21 11:05:40 +08:00

80 lines
2.1 KiB
Python

import base64
import hashlib
import hmac
import json
import time
from urllib.parse import quote
def sign_jos_request(params: dict, app_secret: str) -> str:
sorted_keys = sorted(params.keys())
sign_str = ""
for key in sorted_keys:
raw_value = str(params[key])
encoded = quote(raw_value, safe="")
sign_str += key + encoded
full_str = app_secret + sign_str + app_secret
signature = hmac.new(app_secret.encode("utf-8"), full_str.encode("utf-8"), hashlib.sha256).hexdigest().upper()
return signature
def build_signed_params(
method: str,
biz_params: dict,
app_key: str,
app_secret: str,
access_token: str,
) -> dict:
params = {
"method": method,
"app_key": app_key,
"access_token": access_token,
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"format": "json",
"v": "2.0",
"sign_method": "hmac",
}
biz_json = json.dumps(biz_params, ensure_ascii=False, separators=(",", ":"))
params["360buy_param"] = biz_json
sign = sign_jos_request(params, app_secret)
params["sign"] = sign
return params
def verify_webhook_signature(
raw_body: bytes,
signature_header: str,
timestamp_header: str,
app_secret: str,
tolerance_seconds: int = 300,
algorithm: str = "hmac-sha256",
) -> bool:
try:
request_time = int(timestamp_header)
current_time = int(time.time())
if abs(current_time - request_time) > tolerance_seconds:
return False
except (ValueError, TypeError):
return False
if algorithm == "md5":
sign_str = app_secret + raw_body.decode("utf-8") + app_secret
expected = hashlib.md5(sign_str.encode("utf-8")).hexdigest().upper()
return signature_header.upper() == expected
sign_str = raw_body + timestamp_header.encode("utf-8")
computed = hmac.new(app_secret.encode("utf-8"), sign_str, hashlib.sha256).digest()
try:
expected = base64.b64decode(signature_header)
except Exception:
return False
return hmac.compare_digest(computed, expected)