Amadeus e-Power Web 服务 - SOAP 身份验证设置问题 headers

Amadeus e-Power Web Service - issues setting SOAP auth headers

我在为 Amadeus e-Power 服务设置 AuthenticationSoapHeader 时遇到问题。我正在使用 PHP 的内置 SoapClient。

WSDL: https://staging-ws.epower.amadeus.com/ws_usitcolours/EpowerService.asmx?WSDL

基本 class 我已经做了测试:

class AmadeusSoapClient
{
    private $_client;
    private $_config = [
        'wsdl' => 'https://staging-ws.epower.amadeus.com/ws_usitcolours/EpowerService.asmx?WSDL',
        'namespace' => 'https://epowerv5.amadeus.com.tr/WS', 
        'auth' => [
            'username' => '...',
            'password' => '...'
        ], 
        'debug' => true
    ];

    // Construct
    public function __construct()
    {   
        // Client
        $this->_client = new \SoapClient($this->_config['wsdl'], [
            'trace' => $this->_config['debug']
        ]); 

        // Headers
        $headers = [ 
            // Auth
            new \SoapHeader($this->_config['namespace'], 'AuthenticationSoapHeader', [
                'WSUserName' => $this->_config['auth']['username'], 
                'WSPassword' => $this->_config['auth']['password']
            ]),     
        ]; 

        // Set headers 
        $this->_client->__setSoapHeaders($headers);
    }  

    // Request: CurrencyConversion
    public function currencyConversion($fromCurrency = 'BGN', $toCurrency = 'EUR', $amount = 1.00)
    { 
        $method = 'CurrencyConversion';
        $params = [
            'OTA_CurrencyConversionRQ' => [
                '_' => '',
                'FromCurrency' => $fromCurrency,
                'ToCurrency' => $toCurrency,
                'Amount' => $amount,
            ], 
        ];

        try { 
            return $this->_client->__call($method, [$params]);  
        } catch (\Exception $e) {
            // ...
        }  
    } 
}

示例用法:

$client = new \AmadeusSoapClient();
$client->currencyConversion(); 

收到错误:

stdClass Object
(
    [OTA_CurrencyConversionRS] => stdClass Object
        (
            [Errors] => stdClass Object
                (
                    [Error] => Array
                        (
                            [0] => stdClass Object
                                (
                                    [_] => 
                                    [Type] => EpowerInternalError
                                    [ErrorCode] => EPW.0000
                                    [ShortText] => User Name is required
                                    [Code] => A001
                                    [NodeList] => EPower
                                    [BreakFlow] => 
                                )

                            [1] => stdClass Object
                                (
                                    [_] => 
                                    [Type] => EpowerInternalError
                                    [ErrorCode] => EPW.0000
                                    [ShortText] => Password is required
                                    [Code] => A001
                                    [NodeList] => EPower
                                    [BreakFlow] => 
                                )
                        )
                )
        )
)

无论我用 __setSopHeaders 设置 headers 还是用 __call 方法传递它们,它们总是被忽略.. 任何其他如何设置的想法他们?

对不需要身份验证的方法的请求工作正常。

有趣的是,同一个请求对 Postman 有效,但对 PHP SoapClient 或 SoapUI 无效。

问题出在 PHP 的内置 SoapClient 和 Amadeus 的 .NET 服务器之间的 SSL 通信中。 无论如何,无法建立 SSL 连接,无论我如何设置(强制)Soap 使用 SSL 我总是收到 https connection must be used 错误。

遗憾的是,我没有更多的空闲时间来进一步调查,因此我决定改用 cURL。 这是我做的简单的class。希望对大家有帮助!

class AmadeusClient
{
    private $_config = [
        'wsdl' => 'https://staging-ws.epower.amadeus.com/ws_usitcolours/EpowerService.asmx?WSDL',
        'namespace' => 'http://epowerv5.amadeus.com.tr/WS',
        'auth' => [
            'username' => '...',
            'password' => '...'
        ],
        'sessionCookieName' => 'ASP.NET_SessionId',
        'debug' => true
    ];

    public function testCall()
    {
        $fromCurrency = 'BGN';
        $toCurrency = 'USD';        
        $amount = 15.00;
        $result = $this->currencyConversionRequest($fromCurrency, $toCurrency, $amount);
        echo '<pre>';
        var_dump($result);
        exit; 
    }

    // Request: Currency conversion
    public function currencyConversionRequest($fromCurrency = 'BGN', $toCurrency = 'EUR', $amount = 1.00)
    {
        $method = 'CurrencyConversion';
        $params = [
            'OTA_CurrencyConversionRQ' => [
                '_attributes' => [
                    'FromCurrency' => $fromCurrency,
                    'ToCurrency' => $toCurrency,
                    'Amount' => $amount,
                ]
            ],
        ];

        $result = $this->sendRequest($method, $params);
        if (isset($result->Body->CurrencyConversionResponse->OTA_CurrencyConversionRS->Success)) {
            $array = (array) $result->Body->CurrencyConversionResponse->OTA_CurrencyConversionRS->attributes();
            if (!empty($array['@attributes'])) {
                return $array['@attributes'];
            }
        }
        return false;
    } 

    public function sendRequest($method, $params)
    {
        $body = \Helpers\ArrayToXml::convert($params, [
            'rootElementName' => $method,
            '_attributes' => [
                'xmlns' => $this->_config['namespace']
            ]
        ]);
        $requestBody = '
            <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
                <soap:Header>
                    <AuthenticationSoapHeader xmlns="'. $this->_config['namespace'] .'">
                        <WSUserName>'. $this->_config['auth']['username'] .'</WSUserName>
                        <WSPassword>'. $this->_config['auth']['password'] .'</WSPassword>
                    </AuthenticationSoapHeader>
                </soap:Header>
                <soap:Body>
                    '. str_replace('<?xml version="1.0"?>', '', $body) .'
                </soap:Body>
            </soap:Envelope>
        '; 

        $headers = [
            'Content-type: text/xml; charset=utf-8',
            'Accept: text/xml',
            'Cache-Control: no-cache',
            'Pragma: no-cache',
            'SOAPAction: '. $this->_config['namespace'] .'/'. $method,
            'Content-length: '. mb_strlen($requestBody),
        ];
        $ch = curl_init($this->_config['wsdl']);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_VERBOSE, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        $output = curl_exec($ch);
        curl_close($ch);

        $cleanXml = str_ireplace(['SOAP-ENV:', 'SOAP:'], '', $output);
        return simplexml_load_string($cleanXml);
    }
}

从 \Helpers\ArrayToXml 开始,它只是 Spatie 的一个简单的 class,将 PHP 数组转换为 XML。 资料来源:https://github.com/spatie/array-to-xml

上面生成的请求XMLclass:

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header>
        <AuthenticationSoapHeader xmlns="http://epowerv5.amadeus.com.tr/WS">
            <WSUserName>...</WSUserName>
            <WSPassword>...</WSPassword>
        </AuthenticationSoapHeader>
    </soap:Header>
    <soap:Body>
        <CurrencyConversion xmlns="http://epowerv5.amadeus.com.tr/WS">
            <OTA_CurrencyConversionRQ FromCurrency="BGN" ToCurrency="USD" Amount="15"/>
        </CurrencyConversion>
    </soap:Body>
</soap:Envelope>

响应:

array(3) {
  ["Amount"]=>
  string(4) "9.00"
  ["TruncatedAmount"]=>
  string(4) "8.67"
  ["OtherChargesAmount"]=>
  string(4) "8.67"
}