使用 PHP POST 到 Web 服务的摘要式身份验证的客户端部分


Client part of the Digest Authentication using PHP POST to Web Service

我正在尝试发布到Web服务(不是RESTful)并通过PHP获得响应。但是,该 Web 服务需要摘要式身份验证。

我一直在网上搜索,发现大多数讨论和文章都是关于相反的方式(向用户请求摘要式身份验证),而不是使用 PHP 来响应它。

我能够使用此线程提供的代码生成摘要响应:PHP 中的 HTTP 摘要身份验证,但问题是将其与 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 错误。代码中有什么问题吗?或者以前有没有人遇到过这个问题并解决了它,可以帮助我解决问题?

问候

迈洛

经过 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; 
?>

如果要使用 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; 
?>