使用PHP调用WCF服务(带联合安全)

20

我正在尝试从PHP调用一个WCF服务(.NET)。这比仅使用SoapClient要复杂一些,因为该服务使用WS2007FederationHttpBinding进行身份验证。

目前我正在使用的代码如下。我甚至还没有添加凭据,因为我不确定如何添加,但无论如何,我甚至没有到达访问被拒绝错误的点。

$wsdl = "https://slc.centershift.com/sandbox40/StoreService.svc?wsdl";
$client = new SoapClient($wsdl,array(
         //'soap_version'=>SOAP_1_2 // default 1.1, but this gives 'Uncaught SoapFault exception: [HTTP] Error Fetching http headers'
        ));
$params = array();
$params['SiteID'] = 123;
$params['GetPromoData'] = false;

$ret = $client->GetSiteUnitData(array('GetSiteUnitData_Request'=>$params));
print_r($ret);
  1. 我应该指向哪个WSDL?

  2. 我需要指定SOAP 1.2吗?当我指定时,出现连接超时错误([HTTP] Error Fetching http headers)。当我不指定时,使用了SOAP 1.1的默认值,我得到了一个错误[HTTP] Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'。这是因为我还没有认证,还是因为我使用了错误的SOAP版本?

  3. 如何在PHP中进行身份验证?这是相应的.NET/C#代码。我是否需要将它们作为SOAP头部的一部分进行传递?或者我考虑得有问题,我需要在调用方法之前进行某种类型的身份验证(从我读到的信息中,我应该得到一个令牌,然后将其用于所有未来的方法调用——我认为我在Stack Overflow上的一个答案中看到了一个示例。

如果我使用任何WSDL和任何SOAP版本调用$client->__getFunctions(),我都会获得一个有效的所有函数列表,因此我认为这两者都可以正常工作,而我的真正问题是身份验证。

我与其他程序员交流过,他们花费时间尝试使其工作,但最终放弃并在.NET中实现了一个代理。他们将参数从PHP传递到自己的不安全的.NET服务,然后调用该安全服务。这是可行的,但对我来说似乎效率很低,并且适得其反,因为WCF的目的是支持所有类型的客户端(甚至是非HTTP的客户端!)。

我已经阅读了MSDN上的 How to: Create a WSFederationHttpBinding,但没有帮助。


可以使用“?wsdl”或“?singleWsdl”。前者引用按目的拆分的多个文档,后者将所有内容放在一个地方。WSDL确实指定了正在使用的SOAP版本,因此在下载WSDL之后仍然需要告知它要使用哪个SOAP版本似乎有些奇怪。如果除了WSDL之外还需要提供这些基本信息,我会认为该库不够成熟/质量不高,并且我不希望您尝试使用它来进行联合。我建议寻找其他/更好的SOAP库。 - MattC
谢谢您的评论,@MattC。很高兴了解到WSDL的相关信息,但希望SOAP库不会成为问题(它是PHP原生的)。我查看了nuSoap,但似乎没有什么优势。 - Shane N
我真的不想听起来刻薄,@ShaneN,但内置于PHP中并不保证质量。例如,请参见糟糕的mail()。我没有使用过PHP的SOAP,所以无法提供帮助。 - Palec
我尝试通过编辑问题使其更易阅读来至少提供帮助。请使用实际代码块替换代码截图。将代码发布为截图会防止其他人进行调整。 - Palec
3个回答

1
  1. You can use this URL for WSDL https://slc.centershift.com/Sandbox40/StoreService.svc?singleWsdl. This WSDL has all definitions.

  2. You have to use 1.2 because this webservice works with SOAP 1.2 version. I tried it with 1.1 and 1.2 and both of them gived error. 1.1 is version error, 1.2 is timeout error. I think there is an error at this test server. I used it with svcutil to generate code but it gived error too. Normaly it should get information and generate the code example to call service.

  3. Normally you can add authenticate parameters with SoapHeader or directly add to options in SoapClient consruct (if service authentication is basic authentication). I write below code according to your screenshot. But it gives timeout after long wait.

    $wsdl = "https://slc.centershift.com/sandbox40/StoreService.svc?wsdl";
    $client = new SoapClient($wsdl,array('trace' => 1,'soap_version'   => SOAP_1_2));
    
    $security = array(
    'UserName' => array(
        'UserName'=>'TestUser',
        'Password'=>'TestPassword',
        'SupportInteractive'=>false
     )
    );
    
    $header = new SoapHeader('ChannelFactory','Credentials',$security, false);
    $client->__setSoapHeaders($header);
    
    
    
    $params = array();
    $params['SiteID'] = 100000000;
    $params['Channel'] = 999;
    try {
        $ret = $client->GetSiteUnitData($params);
        print_r($ret);
    }catch(Exception $e){
      echo $e->getMessage();
    }
    

    __getFunctions works, because it prints functions defined in WSDL. There is no problem with getting WSDL information at first call. But real problem is communication. PHP gets WSDL, generates required SOAP request then sends to server, but server is not responding correctly. SOAP server always gives a response even if parameters or request body are not correct.

    You should communicate with service provider, I think they can give clear answer to your questions.


非常感谢您的回复。不幸的是,服务提供商不愿意提供帮助。他们声称他们的服务适用于.NET客户端,因此他们没有理由调查它为什么不能为任何其他客户端类型工作。本质上,他们强迫我们使用微软堆栈,而我们不愿意只为了他们而这样做。 - Shane N

1

我曾经在PHP中使用过.NET WS,我认为你需要在PHP中创建与.NET期望的类名相匹配的对象。 WSDL应该告诉您它所期望的类型。希望这可以帮助您前进!


0
如果从C#应用程序中进行SOAP调用成功,您可以使用Wireshark(使用过滤器ip.dst == 204.246.130.80)查看实际请求,然后从php构建类似的请求。
请查看this answer以了解如何进行自定义SOAP调用。
还有一种选择是使用原始curl请求,因为它可能更容易构建您的xml正文,但是您需要使用simplexml自己解析响应。

我尝试过了,但请求都是通过SSL完成的,因此消息的任何有效负载都是加密的。有一种方法可以加载证书以便解密它,我尝试过了,但对我没有起作用(我认为我需要他们的私钥,但我没有)。 - Shane N
如果在http连接上无法工作,那么查看数据包最简单的方法是为连接设置代理,并使用Fiddler作为代理来捕获和查看数据。 - Catalin

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