Shopware REST Api - 无效或缺少授权

Shopware REST Api - Invalid or missing auth

我正在尝试访问 Shopware 的 REST api。我使用的是 Shopware 5.1.3 版。我正在使用 documentation 的代码。

我总是收到一个 http 代码 400(无效或缺少授权)。

当我尝试通过 Google Chrome 访问 API 时,它在使用 http 身份验证登录后有效,因此凭据应该没问题。

我猜 header Chrome 发送的身份验证与我使用 PHP curl 发送的身份验证不同。

与Chrome:

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:nl-NL,nl;q=0.8,en-US;q=0.6,en;q=0.4
Authorization:Digest username="demo", realm="Shopware REST-API", nonce="7aa6aa7e8089c60e5930cb45ead39197", uri="/api/articles", algorithm=MD5, response="cee77e425508605dfbcf2deda8f83938", opaque="d75db7b160fe72d1346d2bd1f67bfd10", qop=auth, nc=0000001e, cnonce="8b5121e862c4fce1"
Cache-Control:max-age=0
Connection:keep-alive
Cookie:session-1=2d0cb2941684d2767e76ffeb48c7337706cba39c
Host:shopware.example.com
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36

有PHP卷曲

GET /api/articles? HTTP/1.1\r\n
Host: shopware.example.com\r\n
Authorization: Digest username="demo",realm="",nonce="806c9770a53bf2f82b87734a9d8eb98c",uri="/api/articles?",cnonce="60e6c8db046db8f4e63fece37e38f92e",nc=00000001,algorithm=MD5,response="299069d4659af386a4ec7058796267c2",qop="auth",opaque="d75db7b160fe72d1346d2bd1f67bfd10"\r\n
User-Agent: Shopware shopwareApiClient\r\n
Accept: */*\r\n
Content-Type: application/json; charset=utf-8\r\n
Content-Length: 2\r\n

用于获取 header 信息的额外 PHP curl 指令:

curl_setopt($this->cURL, CURLINFO_HEADER_OUT, true);
print_r(curl_getinfo($this->cURL, CURLINFO_HEADER_OUT ));

我使用的代码:

<?php

namespace App;

class shopwareApiClient
{

    const METHOD_GET = 'GET';
    const METHOD_PUT = 'PUT';
    const METHOD_POST = 'POST';
    const METHOD_DELETE = 'DELETE';

    protected $validMethods = array(
        self::METHOD_GET,
        self::METHOD_PUT,
        self::METHOD_POST,
        self::METHOD_DELETE
    );
    protected $apiUrl;
    protected $cURL;

    public function __construct($apiUrl, $username, $apiKey)
    {
        $this->apiUrl = rtrim($apiUrl, '/') . '/';
        //Initializes the cURL instance
        $this->cURL = curl_init();
        curl_setopt($this->cURL, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($this->cURL, CURLOPT_FOLLOWLOCATION, false);
        curl_setopt($this->cURL, CURLOPT_USERAGENT, 'Shopware shopwareApiClient');
        curl_setopt($this->cURL, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
        curl_setopt($this->cURL, CURLOPT_USERPWD, $username . ':' . $apiKey);
        curl_setopt($this->cURL, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json; charset=utf-8',
        ));
        curl_setopt($this->cURL, CURLINFO_HEADER_OUT, true);
    }

    public function call($url, $method = self::METHOD_GET, $data = array(), $params = array())
    {
        if (!in_array($method, $this->validMethods))
        {
            throw new Exception('Invalid HTTP-Methode: ' . $method);
        }
        $queryString = '';
        if (!empty($params))
        {
            $queryString = http_build_query($params);
        }
        $url = rtrim($url, '?') . '?';
        $url = $this->apiUrl . $url . $queryString;
        $dataString = json_encode($data);
        curl_setopt($this->cURL, CURLOPT_URL, $url);
        curl_setopt($this->cURL, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($this->cURL, CURLOPT_POSTFIELDS, $dataString);
        $result = curl_exec($this->cURL);
        dd(curl_getinfo($this->cURL, CURLINFO_HEADER_OUT ));
        $httpCode = curl_getinfo($this->cURL, CURLINFO_HTTP_CODE);
        return $this->prepareResponse($result, $httpCode);
    }

    public function get($url, $params = array())
    {
        return $this->call($url, self::METHOD_GET, array(), $params);
    }

    public function post($url, $data = array(), $params = array())
    {
        return $this->call($url, self::METHOD_POST, $data, $params);
    }

    public function put($url, $data = array(), $params = array())
    {
        return $this->call($url, self::METHOD_PUT, $data, $params);
    }

    public function delete($url, $params = array())
    {
        return $this->call($url, self::METHOD_DELETE, array(), $params);
    }

    protected function prepareResponse($result, $httpCode)
    {
        echo "<h2>HTTP: $httpCode</h2>";
        if (null === $decodedResult = json_decode($result, true))
        {
            $jsonErrors = array(
                JSON_ERROR_NONE => 'No error occurred',
                JSON_ERROR_DEPTH => 'The maximum stack depth has been reached',
                JSON_ERROR_CTRL_CHAR => 'Control character issue, maybe wrong encoded',
                JSON_ERROR_SYNTAX => 'Syntaxerror',
            );
            echo "<h2>Could not decode json</h2>";
            echo "json_last_error: " . $jsonErrors[json_last_error()];
            echo "<br>Raw:<br>";
            echo "<pre>" . print_r($result, true) . "</pre>";
            return;
        }
        if (!isset($decodedResult['success']))
        {
            echo "Invalid Response";
            return;
        }
        if (!$decodedResult['success'])
        {
            echo "<h2>No Success</h2>";
            echo "<p>" . $decodedResult['message'] . "</p>";
            return;
        }
        echo "<h2>Success</h2>";
        if (isset($decodedResult['data']))
        {
            echo "<pre>" . print_r($decodedResult['data'], true) . "</pre>";
        }
        return $decodedResult;
    }
}

编辑:找到一个 php bug report,其中指出在 5.6 及更高版本的 PHP 和 Windows 中存在错误。我在 Windows 上使用 XAMP。我打算在 linux 上试一试,看看它是否有效。

bug report 是正确的。我在 Windows.

上使用带有 PHP 5.6 的 XAMP

将我的 PHP 代码放到 linux 机器上后,代码就可以工作了。

引用错误报告:

[2015-07-19 09:51 UTC] roeycohen at gmail dot com

Description:

trying to use curl_exec with digest authentication does not work properly. running the test script always fails to pass the security challenge. using the browser or wget directly works perfectly.

also, trying to run the same test on another server of mine, works from an amazon linux with php 5.5.21 but does not work from my windows 7 x64 machine with php 5.6.11.

trying to run the test with php 5.5 or 5.4 using CLI on several windows machines caused a complete crush of the php executable.

it seems like bug #69088 is related, but this bug also happens on linux (5.5).

Test script:

<?
$curl = curl_init();

$curl_options = [
    CURLOPT_HTTPAUTH => CURLAUTH_ANY,

    CURLOPT_USERPWD => 'test_user:password',
    CURLOPT_URL => 'http://test_user:password@httpbin.org/digest-auth/auth/user/password',
    CURLOPT_HEADER => true,
];
curl_setopt_array($curl, $curl_options);

curl_exec($curl);
curl_close($curl);

Expected result:

{
  "authenticated": true, 
  "user": "user"
}

Actual result:

"Authentication failed" (with header 401)

[2015-12-28 16:33 UTC] gohel at basicguru dot de

I have the same problem with PHP-clients/scripts and the CalDAV/SabreDAV-framework (also included in Owncloud, Baikal, etc.) on my Apache 2.4.17 (Win32/VC11 from Apachelounge on Win7/64).

I've played a little bit with different versions of the PHP 5.6.x releases and found the following:

  • php_curl.dll <= v5.6.4 - no problems
  • php_curl.dll v5.6.5/v5.6.6 - crash with Auth_Digest
  • php_curl.dll => v5.6.7 - Auth_Digest failed

The bug is also in the PHP 5.5 release and PHP 5.4 (last stable PHP_CURL.DLL I've found in v5.4.36)