使用.NET客户端消费PHP Web服务的问题

时间:2011-07-05 12:21:11

标签: c# php .net

我有一个关于用PHP编写的Web服务的问题。

要使用PHP实例化SoapClient,我在PHP中的SoapClient方法上传递以下参数,如下所示:

$client = new SoapClient("some.wsdl", 
                         array('login' => "some_name",
                               'password' => "some_password"
                         ));

要使用PHP调用Web服务上的方法,这样可以正常工作。但我的同事在使用.NET发送凭据时遇到了麻烦。

有人知道这是如何在.NET中传递的吗?

更新,网络客户端配置

<basicHttpBinding> 
   <binding name="webserviceControllerBinding"> 
       <security mode="TransportCredentialOnly"> 
           <transport clientCredentialType="Basic"/> 
       </security> 
    </binding> 
</basicHttpBinding> 

在代码中:

client.ClientCredentials.UserName.UserName = "username";
client.ClientCredentials.UserName.Password = "password";

更新2:

构建客户端(用PHP)

$client = new 
SoapClient("http://***.***.***/********/httpdocs/webservice/wsdl?wsdl", 
    array(
        'uri'      => "http://***.***.***/***/httpdocs/webservice/webservice",
        'login'    => "*****",
        'password' => "*****"
));

处理请求并引用该类的服务器。

public function webservice()
  parent::__construct();
  ini_set( 'soap.wsdl_cache_enabled', 0);
  $this->presenter     = "NONE";
  $server              = new SoapServer("http://***.***.***/***/httpdocs/webservice/wsdl?wsdl", array('uri' => "http://***.***.***/"));

  $server->setClass(   "Model_Webservice");
  $server->handle();

webservice类中的这个部分处理用户名和密码验证。

class Model_Webservice extends Object_Database
{

public function __construct()
{
  parent::__construct();

  $accesslog     = Log::factory('file', $this->config->log->access , 'ACCESS LOG');

  if(!isset($_SERVER['PHP_AUTH_USER']) || trim($_SERVER['PHP_AUTH_USER']) == "")
  {
     $accesslog->log("[denied] [soapclient " . $_SERVER['REMOTE_ADDR'] . "] no username supplied");
     throw new SOAPFault("Authentication failed - reason: no username supplied", 401);
  }
  elseif(!isset($_SERVER['PHP_AUTH_PW']) || trim($_SERVER['PHP_AUTH_PW']) == "")
  {
     $accesslog->log("[denied] [soapclient " . $_SERVER['REMOTE_ADDR'] . "] no password supplied");
     throw new SOAPFault("Authentication failed - reason: no password supplied", 401);
  }
  else
  {
     $user = new User(null, $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);

     if($user->getId() > 0)
     {
        $accesslog->log("[approved] [soapclient " . $_SERVER['REMOTE_ADDR'] . "] User logged in");
     }
     if(!$user->getId() > 0)
     {
        $accesslog->log("[denied] [soapclient " . $_SERVER['REMOTE_ADDR'] . "] incorrect username and password combination");
        throw new SOAPFault("Authentication failed - reason: incorrect username and password combination", 401);
     }
  }
}

更新3

我根据调整后的配置

收到以下错误消息
  <bindings>
        <basicHttpBinding>
            <binding name="webserviceControllerBinding">
                <security mode="Message">                   
                    <message clientCredentialType="UserName" algorithmSuite="Default" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
  

BasicHttp绑定要求BasicHttpBinding.Security.Message.ClientCredentialType等效于安全消息的BasicHttpMessageCredentialType.Certificate凭据类型。   为UserName凭据选择Transport或TransportWithMessageCredential安全性。

我不想使用证书或https。

3 个答案:

答案 0 :(得分:1)

我建议使用像Fiddler这样的工具来捕获正在运行的PHP客户端和非功能性.NET客户端发送的实际SOAP XML数据。

如果你比较这两个请求,你很有可能会看到差异,并能够找出解决方法。

希望有所帮助。

答案 1 :(得分:1)

我敢打赌,除非从网络服务中获取挑战,否则.NET中的WCF不会发送身份验证标头(默认情况下)。

如果没有提供用户名或密码,则应返回HTTP状态代码401;如果用户名/密码不正确,则应返回http状态代码403.

换句话说:删除SoapException并返回正确的HTTP状态代码。

更新以响应更新3

好。该例外与PHP Web服务无关。这是一个完全不同的问题。抛出错误,因为使用没有证书的BASIC auth会在CLEAR TEXT中发送密码。

我会切换到像DIGEST身份验证这样更安全的东西。

答案 2 :(得分:0)

MessageHeader header= MessageHeader.CreateHeader("My-CustomHeader","http://myurl","Custom Header.");

       using (phptoebiTestclient.ServiceReference1.webserviceControllerPortTypeClient client = new phptoebiTestclient.ServiceReference1.webserviceControllerPortTypeClient())
       {
           using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
           {
               OperationContext.Current.OutgoingMessageHeaders.Add(header);
               HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty();
               byte[] toEncodeAsBytes    = System.Text.ASCIIEncoding.ASCII.GetBytes("username:password");                       
               httpRequestProperty.Headers.Add("Authorization: Basic "+ System.Convert.ToBase64String(toEncodeAsBytes));                                              
               OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;
               string str = client.getVacanciesReference("");
           }                                 
       }

上面的代码解决了我的问题(我使用这些网址作为参考)

http://caught-in-a-web.blogspot.com/2008/04/how-to-add-custom-http-header-in-wcf.html http://en.wikipedia.org/wiki/Basic_access_authentication