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

Python Zeep 使用接口返回证书加密SOAP请求body解决方案求助

问题核心

你当前使用的Zeep库原生仅支持SOAP消息签名能力,不内置符合W3C XML Encryption规范的请求体加密功能,签名和加密是两类完全独立的WS-Security操作,所以你之前按照签名文档配置的逻辑无法满足接口要求。

可行实现方案

方案1:基于Zeep自定义插件实现加密(适配现有代码)

你可以通过Zeep的插件机制,拦截生成的原始请求XML,调用xmlsec库完成Body加密后再发送,无需重构现有业务代码。

依赖准备

  • 系统依赖:先安装libxmlsec1相关组件,Debian/Ubuntu执行apt install libxmlsec1-dev libxml2-dev libxslt1-dev,CentOS执行yum install xmlsec1-devel libxml2-devel libxslt-devel,Windows可直接安装预编译的xmlsec wheel包
  • Python依赖:执行pip install lxml xmlsec zeep requests

代码实现

首先定义加密插件:

from zeep import Plugin
from lxml import etree
import xmlsec

class SOAPBodyEncryptPlugin(Plugin):
    def __init__(self, cert_pem):
        # 加载接口返回的公钥证书
        self.cert = xmlsec.Key.from_memory(cert_pem, xmlsec.KeyFormat.PEM, None)
    
    def egress(self, envelope, http_headers, operation, binding_options):
        # 定位SOAP Body节点
        soap_body = envelope.find("{http://schemas.xmlsoap.org/soap/envelope/}Body")
        if not soap_body:
            soap_body = envelope.find("{http://www.w3.org/2003/05/soap-envelope}Body")
        
        # 初始化加密上下文,指定算法为AES256-CBC
        enc_ctx = xmlsec.EncContext(xmlsec.Transform.AES256_CBC)
        enc_ctx.key = self.cert
        
        # 配置KeyInfo结构匹配接口要求
        key_info = xmlsec.template.ensure_key_info(enc_ctx.enc_ctx)
        sec_token_ref = xmlsec.template.add_security_token_reference(key_info)
        xmlsec.template.add_reference(sec_token_ref, uri="#EK-{}".format(id(self)))
        
        # 加密Body内容
        enc_data = xmlsec.template.encrypted_data_create(
            envelope, 
            xmlsec.Transform.AES256_CBC, 
            type=xmlsec.EncryptionType.CONTENT
        )
        xmlsec.template.encrypted_data_ensure_cipher_value(enc_data)
        soap_body.append(enc_data)
        enc_ctx.encrypt(enc_data, soap_body[0])
        
        # 移除原始明文Body内容,只保留加密后的节点
        for child in list(soap_body):
            if child.tag != "{http://www.w3.org/2001/04/xmlenc#}EncryptedData":
                soap_body.remove(child)
        
        return envelope, http_headers

在你原有代码中添加插件即可:

# 原有获取certPEM的逻辑不变
certPEM = response('body')('content')

# 初始化加密插件,加入Zeep客户端
encrypt_plugin = SOAPBodyEncryptPlugin(certPEM)
client.plugins.append(encrypt_plugin)

# 后续请求会自动加密Body
client.service.secondRequest(_soapheaders=headers, expectedData=expectedData)

方案2:切换到支持WS-Security加密的原生库

如果不想自行实现加密逻辑,可以切换到suds库搭配suds-xenc扩展,原生支持SOAP Body加密,示例代码如下:

from suds.client import Client
from suds.wsse import Security
from suds_xenc import Encryption

# 初始化客户端
client = Client(url)
# 配置加密规则
security = Security()
encryption = Encryption(
    cert=certPEM,
    algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"
)
security.tokens.append(encryption)
client.set_options(wsse=security, verify=False)

# 直接调用接口即可自动加密请求体
response = client.service.secondRequest(headers, expectedData)
注意事项
  • 需确认接口返回的certPEM是标准PEM格式公钥证书,如果返回的是二进制DER格式,需要先转成PEM格式再传入
  • 加密后的节点命名空间、ID规则、KeyInfo结构要和接口示例完全对齐,否则会触发证书校验失败
  • 测试环境关闭SSL校验的配置不要带到生产环境使用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 03:15:08