美文网首页程序员
Python3如何访问需要NTLM认证的Web Service

Python3如何访问需要NTLM认证的Web Service

作者: 玩物励志老乐 | 来源:发表于2020-10-26 18:52 被阅读0次

    背景

    项目的业务流程中有一个环节,需要访问供应商提供的web service。不同于公共的服务,由于系统涉及财务,这个服务必须通过认证才能访问。认证的方式是NTLM,是一种windows特有的认证方式,而常规的Http认证会报401错误。

    常规的处理思路是用大名鼎鼎的suds库(python3环境下,需要suds-jurko + suds-py3这两个库搭配使用)来创建一个Client示例,然后直接打点访问对应的SOAP方法。类似的代码网上随处可见,我就不写了。我这里却遇到了问题(ntml-auth库报错),而不得不另寻出路。

    思路

    我们都知道SOAP协议,其实也是源自HTTP协议传输的,只是通过XML对方法做了预定义,相比较常见的开放接口而言,WSDL具有很好的方法发现特效。

    既然如此,那我们完全可以用http的方式去调用,只要我们自己能够处理好认证、报文和http头即可。

    需要用到的库

    • requests
    • requests-ntlm

    代码示例

    import requests
    from requests_ntlm import HttpNtlmAuth
    
    url = "http://xxxx/aaaaa/bbbb/cccc"
    username = "username"
    password = "password"
    
    headers = {
        "Content-Type": "text/xml",
        "SOAPAction": "action" # 你要访问的方法名。必填,否则无法访问到方法,这个地方卡我好久
    }
    
    postcontent='<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><action xmlns="urn:microsoft-dynamics-schemas/codeunit/cccc"><p1>6541</p1><p2>0</p2></action></soap:Body></soap:Envelope>'
    req = requests.post(url, headers=headers, auth=HttpNtlmAuth(username, password), data=postcontent.encode('utf-8'))
    print(req, req.text)
    

    要点讲解

    • 报文尽量一行写完,别换行。由于提供的web service是由版本比较低的Nav提供的,xml格式并不是特别规范,如果我们的报文有回车、制表符等字符的话,会报500错误,提示无效的数据。
    • SOAP的报文,可以通过下一节提到的接口测试工具SoupUI得到
    • headers里的Content-Type和SOAPAction都是必填的。Content-Type固定写text/xml,SOAPAction写你要调用的方法名。
    • requests想通过NTLM认证,需要配合使用requests_ntlm.HttpHtlmAuth

    接口测试工具

    我们在开始写代码之前,可以先用接口测试工具检查一下接口的访问性。这里推荐两个工具,(1)SoupUI,(2)Postman

    1. SoupUI

    操作步骤如图:
    (1)创建SOAP项目

    soupui-1.png
    (2)获取方法,替换参数并运行
    soupui-2.png
    上图第2步所指的XML就是报文了,我们可以复制下来写在python里。

    (3)如果需要认证,请看这里


    soupui-3.png

    理论上SoupUI就能搞定的ws,可以直接用suds来操作。

    2. Postman

    SoupUI成功了,就可以用Postman来模拟HTTP Request了。这一步再成功了,python下实现就轻而易举了。
    操作请看图:
    (1)认证这样写,注意TYPE选择NTLM Authentication


    postman-1.png

    (2)头信息这么写


    postman-2.png

    (3)报文这么写,要在Body里选择raw,soap:body尽量别换行,整体不换行也没问题


    postman-3.png

    小结

    感觉现在用web service的人很少,所以遇到问题可查阅的资料就更少了。到现在为止,我也不知道自己用suds配合ntlm-auth做的报错原因是什么,不过可以确定的是,错误出在认证这块,不知道是这个wsdl不规范导致ntlm-auth出现了兼容性问题,还是这个库本身就有bug存在。

    常规的postman/requests访问web service,网上的资料几乎都有说在headers里加Content-Type的,但是这个SOAPAction几乎没有人提到,要不是我这边瞎几把试,给试出来,我也不知道这个参数这么重要。没有它,只会返回WSDL定义。

    这次的头疼之路,通过SoupUI -> Postman -> request 这样的路径解决了。核心就是解决了ntlm验证之后,header里加上SOAPAction这个字段。

    这次的事情和爱人讲了,她立刻想到一部讲述图灵的电影(名字忘记了),大概就是图灵在破译敌方电报情报时,通过在电报的头信息里构造了一些数字之后,就成功的破译了,听起来似乎和我这次遇到的情况很像呢。

    相关文章

      网友评论

        本文标题:Python3如何访问需要NTLM认证的Web Service

        本文链接:https://www.haomeiwen.com/subject/wrqzmktx.html