【问题标题】:PHP NTLM authentication + soap clientPHP NTLM认证+soap客户端
【发布时间】:2016-10-24 12:28:39
【问题描述】:

我遇到了需要实施受 NTLM 身份验证保护的 Web 服务的项目。

我尝试通过 PHP SoapClient:

$client = new \SoapClient("http://hostname.com/webservice",
            array(
                'cache_wsdl' => WSDL_CACHE_NONE,
                'login' => "username",
                'password' => "password"
            ));

这会引发此错误:

PHP 致命错误:SOAP-ERROR: Parsing WSDL: Couldn't load from 'http://hostname.com/webservice' : 加载外部实体失败 "http://hostname.com/webservice"

我通过 CURL 试了一下:

curl --ntlm -u username:password "http://hostname.com/webservice" --verbose

它按预期工作并返回正确的 xml。

但同样SoapClient 不支持 NTLM 身份验证。

有人知道PHP Soap+NTLM吗?

提前致谢

【问题讨论】:

    标签: php web-services soap-client


    【解决方案1】:

    我最近也遇到了这个问题。

    这是我找到的解决方案:

    使用以下内容创建NTLMStream.php

    <?php
    /*
    * Original https://thomas.rabaix.net/blog/2008/03/using-soap-php-with-ntlm-authentication
    * Modified by http://blogs.msdn.com/b/freddyk/archive/2010/01/19/connecting-to-nav-web-services-from-php.aspx:
    */
    
    class NTLMStream
    {
        private $path;
        private $mode;
        private $options;
        private $opened_path;
        private $buffer;
        private $pos;
        
        public function stream_open($path, $mode, $options, $opened_path) {
            $this->path = $path;
            $this->mode = $mode;
            $this->options = $options;
            $this->opened_path = $opened_path;
            $this->createBuffer($path);
            return true;
        }
        public function stream_close() {
            curl_close($this->ch);
        }
        public function stream_read($count) {
            if(strlen($this->buffer) == 0) {
                return false;
            }
            $read = substr($this->buffer,$this->pos, $count);
            $this->pos += $count;
            return $read;
        }
        public function stream_write($data) {
            if(strlen($this->buffer) == 0) {
                return false;
            }
            return true;
        }
        public function stream_eof() {
            return ($this->pos > strlen($this->buffer));
        }
        public function stream_tell() {
            return $this->pos;
        }
        public function stream_flush() {
            $this->buffer = null;
            $this->pos = null;
        }
        public function stream_stat() {
            $this->createBuffer($this->path);
            $stat = array(
                'size' => strlen($this->buffer),
            );
            return $stat;
        }
        public function url_stat($path, $flags) {
            $this->createBuffer($path);
            $stat = array(
                'size' => strlen($this->buffer),
            );
            return $stat;
        }
        private function createBuffer($path) {
            if($this->buffer) {
                return;
            }
            $this->ch = curl_init($path);
            curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($this->ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
            curl_setopt($this->ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
            curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($this->ch, CURLOPT_USERPWD, USERPWD);
            $this->buffer = curl_exec($this->ch);
            $this->pos = 0;
        }
    }
    
    class NTLMSoapClient extends \SoapClient
    {
        function __doRequest($request, $location, $action, $version, $one_way = 0) {
            $headers = array(
                'Method: POST',
                'Connection: Keep-Alive',
                'User-Agent: PHP-SOAP-CURL',
                'Content-Type: text/xml; charset=utf-8',
                'SOAPAction: "'.$action.'"',
            );
            $this->__last_request_headers = $headers;
            $ch = curl_init($location);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            curl_setopt($ch, CURLOPT_POST, true );
            curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
            curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
            curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_USERPWD, USERPWD);
            $response = curl_exec($ch);
            return $response;
        }
        function __getLastRequestHeaders() {
            return implode("\n", $this->__last_request_headers)."\n";
        }
    }
    

    然后在你的test.php

    <?php
    define('USERPWD', 'domain\username:password');
    require_once("NTLMStream.php");
    stream_wrapper_unregister("https");
    stream_wrapper_register("https", "NTLMStream");
    $params = [
        'stream_context' => stream_context_create([
               'ssl' => [
                'ciphers'=>'RC4-SHA', 
                'verify_peer'=>false, 
                'verify_peer_name'=>false, 
                'allow_self_signed'=>true,
            ]]),
        'cache_wsdl' => WSDL_CACHE_NONE,
        'soap_version' => SOAP_1_1,
        'trace' => 1,
        'connection_timeout' => 180, 
        'features' => SOAP_SINGLE_ELEMENT_ARRAYS
    ];
    $client = new NTLMSoapClient("https://hostname.com/webservice", $params);
    $retVal = $client->ReadMultiple(...
    ...
    

    用 http:// 代替 https:// 代替:

    stream_wrapper_register("http", "NTLMStream")
    stream_wrapper_register("https", "NTLMStream")
    

    【讨论】:

    • 在您的 test.php 中,parem 字段未正确关闭。请更新您的答案。因为它对任何人都没有帮助。
    【解决方案2】:

    这个库帮助了我(我使用作曲家): https://packagist.org/packages/matejsvajger/ntlm-soap-client

    $url = 'URL_TO_WEBSERVICE_WSDL';
    $config = new matejsvajger\NTLMSoap\Common\NTLMConfig([
        'domain'   => 'domain',
        'username' => 'username',
        'password' => 'password'
    ]);
    
    $client = new matejsvajger\NTLMSoap\Client($url, $config);
    
    $response = $client->ReadMultiple(['filter'=>[], 'setSize'=>1]);
    
    foreach ($response->ReadMultiple_Result->CRMContactlist as $entity) {
        print_r($entity);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-17
      • 1970-01-01
      • 2014-08-21
      • 1970-01-01
      • 1970-01-01
      • 2022-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多