使用PHP的Curl发送POST请求到外部Oath2 API

3

我将尝试概述我们的情况:

我们卡住的是库中的executeRequest方法。 该方法可以在https://github.com/adoy/PHP-OAuth2/blob/master/src/OAuth2/Client.php的404行(啊,讽刺)找到。

现在,正如我所说,我对PHP的经验很少,因此我的调试方式只是在脚本中给定点处输出变量的状态。 虽然这可能很业余,但我至少可以验证URL和参数是否正确。 我可以打印完整的URL(当然是虚拟参数值):

请注意以下使用的参数:coderedirect_urigrant_typeclient_idclient_secret

https://oauth.smartschool.be/OAuth/index/token?code=irsyB0VSmg4V5dVjHFgdl85iRvvu3gYpsuIE4cOk&redirect_uri=https%3A%2F%2Fmycallbackurl.com%2Fmy-page%2F&grant_type=authorization_code&client_id=5d6t5ev5a6d8&client_secret=pada9c54a6sc

当您执行此请求时,将收到JSON错误消息。这是正常的,因为我不能提供我们的client_id和client_secret:

{"error":"error_occured","error_description":"Client authentication failed."}

当我在浏览器中手动执行此操作时(使用正确的参数值),我得到所需的JSON结果:
{"access_token":"fa4a6s4axsaxxsfacc56c4aca8acac4q6d5z4fsv","token_type":"Bearer","expires_in":3600,"refresh_token":"X5s1aq56xaq6bhz56aGY6SCb9845465czxqde56a"}
问题是,当CURL构建并执行此操作作为POST请求时,我会得到一个错误的JSON结果:
{"error":"error_occured","error_description":"The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \u0022code\u0022 parameter."}

我可以验证以下CURL选项的状态(请注意,代码绕过ssl验证,在Client.php文件的第462行):

  • CURLOPT_RETURNTRANSFER = true
  • CURLOPT_SSL_VERIFYPEER = false
  • CURLOPT_SSL_VERIFYHOST = false
  • CURLOPT_CUSTOMREQUEST = 'POST'
  • CURLOPT_POST = true
  • CURLOPT_POSTFIELDS = url编码参数字符串

例如: code=irsyB0VSmg4V5dVjHFgdl85iRvvu3gYpsuIE4cOk&redirect_uri=https%3A%2F%2Fmycallbackurl.com%2Fmy-page%2Fgrant_type=authorization_code&client_id=5d6t5ev5a6d8&client_secret=pada9c54a6sc

当像这样执行Curl处理程序时:

$result = curl_exec($ch);

他成功地与API建立了联系并返回了结果,但JSON结果显示参数错误,并声称代码是不正确的。但我知道它是正确的,因为当我通过浏览器手动执行请求时,它可以运行。如果直接跳转到没有参数的 https://oauth.smartschool.be/OAuth/index/token ,你会得到完全相同的错误。
这让我想知道curl是否完全传递任何参数。
您能否告诉我在提供的信息中是否发现错误,也许在curl选项中?或者您能够指导我以适当的方式调试此curl执行(请记住,我在WordPress上,如果这有任何影响)。
如果这篇文章缺少所需的信息,请告诉我。
谢谢您提前提供帮助。
-编辑:
库代码由以下代码触发(再次使用虚拟客户端ID和密钥)。此方法可以在 https://github.com/adoy/PHP-OAuth2/blob/master/src/OAuth2/Client.php 的第211行找到。
$client = new Client('5d6t5ev5a6d8', 'pada9c54a6sc');
$callBackUrl = 'https://mycallbackurl.com/my-page';
$myResponse = $client->getAccessToken('https://oauth.smartschool.be/OAuth/index/token', 'authorization_code', ['code'=> $_GET['code'], 'redirect_uri' => $callBackUrl]);

我已经删除了设置头选项为一个空数组的代码,只是为了确保。但是当使用CURLINFO_HEADER_OUT进行调试时,结果仍然相同。它确实默认为Content-Type: application/x-www-form-urlencoded。 这是完整的curl_getinfo()数组:

数组([url] => https://oauth.smartschool.be/OAuth/index/token [content_type] => application/json [http_code] => 200 [header_size] => 7414 [request_size] => 363 [filetime] => -1 [ssl_verify_result] => 0 [redirect_count] => 0 [total_time] => 0.073514 [namelookup_time] => 3.9E-5 [connect_time] => 0.006093 [pretransfer_time] => 0.028232 [size_upload] => 216 [size_download] => 231 [speed_download] => 3142 [speed_upload] => 2938 [download_content_length] => -1 [upload_content_length] => 216 [starttransfer_time] => 0.073476 [redirect_time] => 0 [redirect_url] => [primary_ip] => xxx.xxx.xxx.xxx [certinfo] => 数组()[primary_port] => xxxxx [local_ip] => xxx.xxx.xxx.xxx [local_port] => xxxxx [request_header] => POST /OAuth/index/token HTTP/1.1 Host: oauth.smartschool.be Accept: */* Content-Length: 216 Content-Type: application/x-www-form-urlencoded )

然而,结果仍然相同(仍然指示根本没有传递任何参数):

数组([result] => 数组([error] => error_occured [error_description] => 请求缺少必需的参数,包括无效的参数值,包括一个参数多次,或者格式不正确。检查“code”参数。)[code] => 200 [content_type] => application/json)

有没有办法打印此curl请求的参数/ post字段/正文,以验证是否发送了所有信息?

--编辑2:

在使用Tobias提供的httbin.org/post链接之后,我得到了以下结果:

Array ( 
    [args] => Array 
        (
        ) 

    [data] => 
    [files] => Array 
        ( 
        ) 

    [form] => Array 
        ( 
            [client_id] => 5d6t5ev5a6d8
            [client_secret] => pada9c54a6sc
            [code] => fa4a6s4axsaxxsfacc56c4aca8acac4q6d5z4fsv
            [grant_type] => authorization_code 
            [redirect_uri] => https://mycallbackurl.com/my-page
        ) 

    [headers] => Array 
        ( 
            [Accept] => */* 
            [Connection] => close 
            [Content-Length] => 216 
            [Content-Type] => application/x-www-form-urlencoded 
            [Host] => httpbin.org 
        ) 

    [json] => 
    [origin] => 83.xxx.xx.xx
    [url] => https://httpbin.org/post 
) 

与Tobias的示例进行比较,我没有看到任何值得注意的区别。我假设这意味着我们的POST请求至少包含了所有必需的数据。那么,我们仍然不知道API不接受参数的可能原因。如果您想到其他可能的解决方案,请不要犹豫附加它们。感谢提供这个链接,真的很有用!


2
你能添加调用 "executeRequest()" 和传递给它的参数的代码行吗? - Jannes Botis
我已经添加了触发getAccessToken()的代码行。该方法最终调用executeRequest()。 - J. Michiels
我已经尝试使用提供的信息和编辑来设置一个MCVE,链接如下:https://pastebin.com/HGpW3dLx - 但是当我调用它时,我立即得到了所需的“客户端身份验证失败”的响应。我正在使用PHP 7.2.2。在您的环境中调用该脚本时是否也会出现错误? - Tobias K.
1个回答

5

在浏览器中进行测试和实际代码之间有所不同:在浏览器中,您将变量作为GET参数传递,而在代码中,您正在发送POST正文。

为了调试此类问题,我经常发现在转到 PHP 之前使用 CLI curl 更容易。当我像这样发送请求时(注意Content-Type标题),我成功获得了积极的结果:

curl -X POST --data "code=irsyB0VSmg4V5dVjHFgdl85iRvvu3gYpsuIE4cOk&redirect_uri=https%3A%2F%2Fmycallbackurl.com%2Fmy-page%2F&grant_type=authorization_code&client_id=5d6t5ev5a6d8&client_secret=pada9c54a6sc" "https://oauth.smartschool.be/OAuth/index/token" -H "Content-Type: application/x-www-form-urlencoded"
{"error":"error_occured","error_description":"Client authentication failed."}

如果我在没有这个头部信息的情况下强制发送请求,我就能够重现你的错误。这其实并不容易,因为使用 --data 命令会自动添加这个头部信息:

curl -X POST --data "code=irsyB0VSmg4V5dVjHFgdl85iRvvu3gYpsuIE4cOk&redirect_uri=https%3A%2F%2Fmycallbackurl.com%2Fmy-page%2F&grant_type=authorization_code&client_id=5d6t5ev5a6d8&client_secret=pada9c54a6sc" "https://oauth.smartschool.be/OAuth/index/token" -H "Content-Type: "
{"error":"error_occured","error_description":"The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \u0022grant_type\u0022 parameter."}

您需要确保您的代码发送请求时带有头部信息:Content-Type: application/x-www-form-urlencoded
我猜测使用PHP-curl时,当使用POST(FIELDS)(类似于CLI版本)时也会隐式地添加它,您的问题可能是您“强制”将CURLOPT_HTTPHEADER设置为空数组,并因此删除了它。
为了调试正在发送的头部信息,您可以使用:
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
// curl_exec
$information = curl_getinfo($ch);
print_r($information);

编辑:

实际上更好的调试方法是更改您的OAuth-URL,将POST发送到 https://httpbin.org/post 。 这将仅镜像发送到它的所有内容,因此转储您收到的响应,它应该看起来像:

Array
(
    [result] => Array
        (
            [args] => Array
                (
                )

            [data] =>
            [files] => Array
                (
                )

            [form] => Array
                (
                    [client_id] => 5d6t5ev5a6d8
                    [client_secret] => pada9c54a6sc
                    [code] => irsyB0VSmg4V5dVjHFgdl85iRvvu3gYpsuIE4cOk
                    [grant_type] => authorization_code
                    [redirect_uri] => https://mycallbackurl.com/my-page
                )

            [headers] => Array
                (
                    [Accept] => */*
                    [Connection] => close
                    [Content-Length] => 180
                    [Content-Type] => application/x-www-form-urlencoded
                    [Host] => httpbin.org
                )

            [json] =>
            [origin] => 217.***.***.***
            [url] => https://httpbin.org/post
        )

    [code] => 200
    [content_type] => application/json
)

你有望从那里识别正在发送的内容(和未发送的内容),包括正文数据。不幸的是,即使是 curl 的详细模式也无法显示。


1
感谢您的努力重现问题并进行解释。我已经在我的帖子中添加了更多信息,展示了我的curl_getinfo的结果。您能否再次查看结果并告诉我是否还有其他问题?谢谢。 - J. Michiels
我添加了另一种使用https://httpbin.org/调试请求的方法。此外,我在您的问题中添加了一个作为评论的MCVE,但它对我有效。 - Tobias K.
1
谢谢你的额外提示,Tobias。我还没有时间进一步测试,明天会去做。我已经授予你赏金以感谢你迄今为止的帮助,否则它将过期。非常感谢你! - J. Michiels

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