Python SOAP客户端使用Zeep - 身份验证

5
我正在尝试使用Zeep实现SOAP客户端,因为它似乎是目前唯一维护的库:
- ZSI看起来非常好,但其在pypi上的最新版本可以追溯到2006年。 - suds似乎是一个受欢迎的替代方案,但自2011年以来,其主要代码未得到维护,虽然有很多分支,但没有一个足够“官方”和“最新”,可以用于大型项目。
因此,尝试使用Zeep时,我被服务器要求进行身份验证才能访问WSDL所困扰。
使用ZSI进行此操作相当容易:
from ZSI.client import Binding
from ZSI.auth import AUTH

b = Binding(url='http://mysite.dom/services/MyWebServices?WSDL')
b.SetAuth(AUTH.httpbasic, 'userid', 'password')

而且我在 Zeep 的 __main__.py 文件中找到了类似的东西:

from six.moves.urllib.parse import urlparse
from zeep.cache import InMemoryCache, SqliteCache
from zeep.client import Client
from zeep.transports import Transport

cache = SqliteCache() if args.cache else InMemoryCache()
transport_kwargs = {'cache': cache}
result = urlparse(args.wsdl_file)
if result.username or result.password:
    transport_kwargs['http_auth'] = (result.username, result.password)
transport = Transport(**transport_kwargs)
client = Client(args.wsdl_file, transport=transport)

但在我的情况下不起作用,我会收到一个错误:
Exception: HTTPConnectionPool(host='schemas.xmlsoap.org', port=80): Max retries exceeded with url: /soap/encoding/ (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7f3dab9d30b8>: Failed to establish a new connection: [Errno 110] Connection timed out',))

在我的情况下,我必须通过_soapheaders发送它。请查看我的答案 - John Prawyn
@Pintun,你能否更改已接受的答案,因为当前的答案已经过时了? - jan-seins
3个回答

31

可能使用更新版本的zeep,旧的解决方案不再有效。 这里是新方法:

from requests.auth import HTTPBasicAuth  # or HTTPDigestAuth, or OAuth1, etc.
from requests import Session
from zeep import Client
from zeep.transports import Transport

session = Session()
session.auth = HTTPBasicAuth(user, password)
client = Client('http://my-endpoint.com/production.svc?wsdl',
            transport=Transport(session=session))

是的,这个解决方案肯定可以正常工作。上面那个对于当前版本的zeep不起作用。 “Transport”类不接受“http_auth”参数。 - tombishop83

10

对于基本访问身份验证,您可以使用requests模块中的HTTPBasicAuth类,正如Zeep文档http://docs.python-zeep.org/en/master/transport.html中所解释的那样:

from requests.auth import HTTPBasicAuth  # or HTTPDigestAuth, or OAuth1, etc.
from zeep import Client
from zeep.transports import Transport

client = Client('http://my-endpoint.com/production.svc?wsdl',
    transport=Transport(http_auth=HTTPBasicAuth(user, password)))

非常棒,非常感谢。我现在遇到的问题是WSDL托管在内部网络中,尝试从互联网导入命名空间('<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>'),但客户端机器上无法访问。您知道是否有一种方法可以防止zeep客户端这样做吗? - Pintun
1
我认为没有简单的解决方法。你要么修改WSDL使所有命名空间本地化(例如在客户端机器上有一份WSDL副本,Zeep可以使用它),要么以某种方式在企业内网提供模式的本地副本并使用相应的URL。 - Moisés Hiraldo
我已经找到了一个解决方案,通过覆盖传输类使用本地副本。参见这个问题 - Pintun
5
嗨,我知道您是去年十月写的这篇文章,但我认为现在已经有所改变了:请参见http://docs.python-zeep.org/en/master/transport.html#http-authentication(基本上您需要执行session = Session()并将传输放到会话中)。非常感谢您的回答,否则我就找不到这个地方了。(我认为这是Requests而不是Zeep的更改)。 - Jmons

5
在我的情况下,我正在使用的API需要WS-Security(WSSE)而不是HTTP。
from zeep import Client
from zeep.wsse.username import UsernameToken

client = Client(<wsdl_url>, wsse=UsernameToken(<username>, <password>)

1
适用于WCF服务。 - Max

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接