使用 PHP POST 到 Web 服务的摘要式身份验证的客户端部分
Posted
技术标签:
【中文标题】使用 PHP POST 到 Web 服务的摘要式身份验证的客户端部分【英文标题】:Client part of the Digest Authentication using PHP POST to Web Service 【发布时间】:2013-09-06 19:13:00 【问题描述】:我正在尝试发布到 Web 服务(不是 RESTful)并通过 php 获得响应。但是,该 Web 服务需要摘要式身份验证。
我一直在网上搜索,发现大多数讨论和文章都是关于相反的方式(向用户请求摘要身份验证),而不是使用 PHP 响应它。
我可以使用该线程提供的代码生成摘要响应:HTTP Digest authenticating in PHP,但问题是与(或不?)POST 数据一起发送它。
这是我正在使用的代码:
$domain = "https://api.example.com";
$uri = "/ws.asmx/do";
// get headers
$response1_array = get_headers($web_service_url);
// get request part of digest auth
$response1 = $response1_array[5];
// get things behind "WWW-Authenticate:"
$response1 = substr($response1, 18);
// response() is a invented function to calculate the response according to the RFC2617
$response2 = response($response1, "username", "password", "GET", $uri);
// manually add some headers for POST, and fill out the parts that the calculation function missed
// for auth
$header =
"Host: api.example.com\r\n" .
"Content-Type: application/x-www-form-urlencoded\r\n" .
"Authorization: " . $response2 . ", nc=\"00000001\", opaque=\"0000000000000000\"" . "\r\nContent-Length: 0\r\n\r\n";
// echo the response from server
echo do_post_request($web_service_url, "", $header);
function do_post_request($url, $data, $optional_headers = null)
$params = array('http' => array(
'method' => 'POST',
'content' => $data
));
if ($optional_headers !== null)
$params['http']['header'] = $optional_headers;
$ctx = stream_context_create($params);
$fp = fopen($url, 'rb', false, $ctx);
if (!$fp)
throw new Exception("Problem with $url");
$response = stream_get_contents($fp);
if ($response === false)
throw new Exception("Problem reading data from $url");
return $response;
在回复中:
$response1(from web service):
Digest realm="example.com", nonce="OS82LzIwMTMgMTI6MDI6NDYgUE0", opaque="0000000000000000", stale=false, algorithm=MD5, qop="auth"
$response2(I calculated given the server response):
Digest username="username", realm="example.com", nonce="OS82LzIwMTMgMTI6MDI6NDYgUE0", uri="/ws.asmx/do", cnonce="1378494106", nc="1", response="0f96788854cf2098ba22c6121529d7de", qop="auth"
the final (2nd) response from server:
Warning: fopen(https://api.example.com/ws.asmx/do): failed to open stream: HTTP request failed! HTTP/1.1 500 Internal Server Error in ...
我不明白为什么在这种情况下服务器会响应 500 错误。代码有什么问题吗?或者有没有人遇到过这个问题并解决了它并可以帮助我解决问题?
问候,
米洛
【问题讨论】:
【参考方案1】:经过 2 天的摸索,最终用 cURL 解决了这个问题。我想这是第一次发布一段现成的用于摘要身份验证的 PHP 代码,希望它可以帮助和我在同一个沟里的人。
代码:
<?php
error_reporting(E_ALL);
ini_set( 'display_errors','1');
$url = "https://api.example.com/ws.asmx/do";
$username = "username";
$password = "pwd";
$post_data = array(
'fieldname1' => 'value1',
'fieldname2' => 'value2'
);
$options = array(
CURLOPT_URL => $url,
CURLOPT_HEADER => true,
CURLOPT_VERBOSE => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false, // for https
CURLOPT_USERPWD => $username . ":" . $password,
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($post_data)
);
$ch = curl_init();
curl_setopt_array( $ch, $options );
try
$raw_response = curl_exec( $ch );
// validate CURL status
if(curl_errno($ch))
throw new Exception(curl_error($ch), 500);
// validate HTTP status code (user/password credential issues)
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status_code != 200)
throw new Exception("Response with Status Code [" . $status_code . "].", 500);
catch(Exception $ex)
if ($ch != null) curl_close($ch);
throw new Exception($ex);
if ($ch != null) curl_close($ch);
echo "raw response: " . $raw_response;
?>
【讨论】:
【参考方案2】:如果你想用 PUT 方法发送 JSON 数据:
<?php
error_reporting(E_ALL);
ini_set( 'display_errors','1');
$url = "https://api.example.com/ws.asmx/do";
$username = "username";
$password = "pwd";
$post_data = array(
'fieldname1' => 'value1',
'fieldname2' => 'value2'
);
$options = array(
CURLOPT_URL => $url,
CURLOPT_HEADER => true,
CURLOPT_VERBOSE => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false, // for https
CURLOPT_USERPWD => $username . ":" . $password,
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode($post_data) ,
);
$ch = curl_init();
curl_setopt_array( $ch, $options );
try
$raw_response = curl_exec( $ch );
// validate CURL status
if(curl_errno($ch))
throw new Exception(curl_error($ch), 500);
// validate HTTP status code (user/password credential issues)
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status_code != 200)
throw new Exception("Response with Status Code [" . $status_code . "].", 500);
catch(Exception $ex)
if ($ch != null) curl_close($ch);
throw new Exception($ex);
if ($ch != null) curl_close($ch);
echo "raw response: " . $raw_response;
?>
【讨论】:
以上是关于使用 PHP POST 到 Web 服务的摘要式身份验证的客户端部分的主要内容,如果未能解决你的问题,请参考以下文章
使用带有摘要身份验证、jquery ajax 调用的 RestFul PHP Web 服务
如何获取(收听)POST 和 GET 方法发送到我的服务器 PHP