简体   繁体   English

Web服务 - C#客户端和Apache服务器基本身份验证 - 错误HTTP 400错误请求

[英]Web Service - C# Client and Apache Server Basic Authentication - Error HTTP 400 Bad Request

I write here because I'm working to transform a PHP webservice client to C# (VS2010). 我在这里写,因为我正在努力将PHP Web服务客户端转换为C#(VS2010)。

Project are in Framework4 but the web service was added in VS2010 like a web service compatible with Framework2 (Web Reference with WSDL). Project在Framework4中,但是在VS2010中添加了Web服务,就像与Framework2兼容的Web服务(使用WSDL的Web Reference)。

Actually I'm working only on a classical webservice (a Helloworld test). 实际上我只是在经典的网络服务(Helloworld测试)上工作。

With the client C# I have no problem I send a text to the web service and the web service responds by returing the text. 使用客户端C#我没有问题我将文本发送到Web服务,Web服务通过撤回文本来响应。 I have no error in the Apache Server. 我在Apache Server中没有错误。

If I activate the basic authentification in the .htaccess apache server (host the webservice server), so in the client C# I have this error : 如果我在.htaccess apache服务器(托管webservice服务器)中激活基本身份验证,那么在客户端C#中我有这个错误:

Exception : WebException Bad Request with state HTTP 400 : Bad Request. 例外:WebException Bad Request with state HTTP 400:Bad Request。

In Apache error log I see this line : 在Apache错误日志中,我看到这一行:

[Thu Feb 02 23:52:06 2012] [error] [client XX.XX.XX.XX] Invalid URI in request
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"     
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:tns="https://www.domaine.com/api/helloworld/webservices.php?wsdl" 
xmlns:types="https://www.domaine.com/api/helloworld/webservices.php?wsdl/encodedTypes" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org
/2001/XMLSchema">
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<tns:bonjour><prenom xsi:type="xsd:string">Toto</prenom></tns:bonjour>
</soap:Body>
</soap:Envelope>
POST /api/helloworld/webservices.php HTTP/1.1

.

I'm sure is the credentials who are not working because when I try with a false user and password I have always the 400 Bad Request. 我确定是不工作的凭据,因为当我尝试使用虚假用户和密码时,我总是有400个错误请求。

The code of C# Client are : // We create the webservice WebService mywebservice = new WebService(); C#Client的代码是://我们创建webservice WebService mywebservice = new WebService();

// We define BASIC Authentication             
CredentialCache myCredentials = new CredentialCache();         
NetworkCredential netCred = new NetworkCredential("User1", "Pass1");     
myCredentials.Add(new Uri(mywebservice.Url), "Basic", netCred);
myCredentials.PreAuthenticate = true;
mywebservice.Credentials = myCredentials;

// We define the UserAgent
mywebservice.UserAgent = ".NET Framework";

// We call the function of webservice
string retour = mywebservice.bonjour("Tata");

// We show the return
MessageBox.Show(retour, "Retour de l'API", MessageBoxButtons.OK, MessageBoxIcon.Information);

.

The .htaccess : # Don't show directory listings for URLs which map to a directory. .htaccess:#不显示映射到目录的URL的目录列表。 Options -Indexes 选项 - 索引

# Se logue avec un compte AD
AuthType Basic
AuthBasicProvider ldap
AuthName "Acces au webservice"
AuthLDAPURL ldap://127.0.0.1:389/ou=clients,dc=domaine,dc=com?mail
Require valid-user 

.

If I delete the .htaccess file everything it's working ... but without authentication :( 如果我删除.htaccess文件它正在工作...但没有身份验证:(

I post also the request and response with .htaccess (not working) : 我也发布了.htaccess的请求和响应(不工作):

POST https://www.domaine.com/api/login_ovh_pnp/webservices.php HTTP/1.1
User-Agent: .NET Framework
VsDebuggerCausalityData: uIDPo9/Tb/xbJxtKvSNra7boyJsAAAAAQcQin1OhXXXXXXXXXXX/KqROJW0w1FhAcrrhI1sGQACQAA
Content-Type: text/xml; charset=utf-8
SOAPAction: "https://www.domaine.com/api/login_ovh_pnp/webservices.php?wsdl#bonjour"
Authorization: Basic bHZlaXJtYW5AYXF1aWxhLWXXXXXXXXXXXbmcuZnI6ZHluYXRlcmE3OA==
Host: www.domaine.com
Content-Length: 623
Expect: 100-continue

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:tns="https://www.domaine.com/api/login_ovh_pnp/webservices.php?wsdl" 
xmlns:types="https://www.domaine.com/api/login_ovh_pnp/webservices.php?wsdl
/encodedTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<tns:bonjour>
<prenom xsi:type="xsd:string">Tata</prenom>
</tns:bonjour>
</soap:Body>    
</soap:Envelope>

=====================================
=====================================

HTTP/1.1 400 Bad Request
Date: Mon, 06 Feb 2012 13:40:32 GMT
Server: Apache
Vary: Accept-Encoding
Content-Length: 226
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
</body></html>

.

And for finish the request without .htaccess : 并且在没有.htaccess的情况下完成请求:

POST https://www.domaine.com/api/login_ovh_pnp/webservices.php HTTP/1.1
User-Agent: .NET Framework
VsDebuggerCausalityData:    
uIDPo4r/MO3TgmdMkQiWHfkXoWwAAAAA1krYOM0NBkS9vLzFQe3Vmln8F3GXClFNrTWXL/L622YACQAA
Content-Type: text/xml; charset=utf-8
SOAPAction: "https://www.domaine.com/api/login_ovh_pnp/webservices.php?wsdl#bonjour"
Host: www.domaine.com
Content-Length: 623
Expect: 100-continue
Connection: Keep-Alive

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:tns="https://www.domaine.com/api/login_ovh_pnp/webservices.php?wsdl" 
xmlns:types="https://www.domaine.com/api/login_ovh_pnp/webservices.php?wsdl
/encodedTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<tns:bonjour>
<prenom xsi:type="xsd:string">Tata</prenom>
</tns:bonjour>
</soap:Body></soap:Envelope>

=====================================
=====================================

HTTP/1.1 200 OK
Date: Mon, 06 Feb 2012 13:51:31 GMT
Server: Apache
X-SOAP-Server: NuSOAP/0.9.5 (1.123)
Content-Length: 575
Vary: Accept-Encoding
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/xml; charset=ISO-8859-1

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:bonjourResponse xmlns:ns1="https://supervision.dynatera.net/api/login_ovh_pnp/webservices.php?wsdl">
<return xsi:type="xsd:string">Bonjour Tata</return></ns1:bonjourResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

.

Thank you very much for your help on this complex problem because I searched many times without found anything to fix this issue. 非常感谢您对这个复杂问题的帮助,因为我搜索了很多次而没有发现任何问题来解决这个问题。

I've also had this problem... When you define NetworkCredentials it does not get sent in the HTTP header, and thus no 'Authorization' header... 我也遇到过这个问题......当你定义NetworkCredentials时,它不会在HTTP头中发送,因此没有'Authorization'标题......

What I did and it worked for me was: 我所做的和它对我有用的是:

I created a class that implements IClientMessageInspector and implement the BeforeSendRequest method: 我创建了一个实现IClientMessageInspector的类并实现了BeforeSendRequest方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;

namespace BasicAuth
{
    public sealed class MessageHttpHeaderInspector : IClientMessageInspector
    {  
        private string userName;
        private string password;

        #region Constructor

        public MessageHttpHeaderInspector(string userName, string password)
        {
            this.userName = userName;
            this.password = password;
        }

        #endregion

        #region IClientMessageInspector Members

        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
            //throw new NotImplementedException();
        }

        public object BeforeSendRequest(ref Message request, System.ServiceModel.IClientChannel channel)
        {
            HttpRequestMessageProperty httpRequest;

            if (request.Properties.ContainsKey(HttpRequestMessageProperty.Name))
            {
                httpRequest = request.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
            }
            else
            {
                httpRequest = new HttpRequestMessageProperty();
                request.Properties.Add(HttpRequestMessageProperty.Name, httpRequest);
            }

            if (httpRequest != null)
            {
                string credentials = this.CreateBasicAuthenticationCredentials(this.userName, this.password);
                httpRequest.Headers.Add(System.Net.HttpRequestHeader.Authorization, credentials);
            }

            return request;
        }

        #endregion

        #region Private Worker Methods

        private string CreateBasicAuthenticationCredentials(string userName, string password)
        {
            string returnValue = string.Empty;
            string base64UsernamePassword = Convert.ToBase64String(Encoding.ASCII.GetBytes(String.Format("{0}:{1}", userName, password)));

            returnValue = String.Format("Basic {0}", base64UsernamePassword);

            return returnValue; 
        }

        #endregion
    }
}

Then I created a class that implements IEndpointBehavior and implements the ApplyClientBehavior method: 然后我创建了一个实现IEndpointBehavior的类并实现了ApplyClientBehavior方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

namespace BasicAuth
{
    public sealed class CustomEndpointCallBehavior : IEndpointBehavior
    {   
        private string userName;    
        private string password;

        #region Constructor

        public CustomEndpointCallBehavior(string userName, string password)
        {
            this.userName = userName;    
            this.password = password;
        }

        #endregion

        #region IEndpointBehavior Members

        public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
            //throw new NotImplementedException();
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(new MessageHttpHeaderInspector(this.userName, this.password));
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            //throw new NotImplementedException();
        }

        public void Validate(ServiceEndpoint endpoint)
        {
            //throw new NotImplementedException();
        }

        #endregion
    }
}

Then you need to apply this behavior to the proxy: 然后,您需要将此行为应用于代理:

mywebservice.Endpoint.Behaviors.Add(new CustomEndpointCallBehavior("User1", "Pass1"));

Have a look at the following: 看看以下内容:

This should do the trick... Hope it works for you! 这应该是诀窍...希望它适合你!

Credentials set in your code does not match credentials sent in request 代码中设置的凭据与请求中发送的凭据不匹配

Authorization: Basic bHZlaXJtYW5AYXF1aWxxxxxx1bHRpbmcuZnI6ZHluYXRlcmE3OA==

Your code set next credential for basic authentication: 您的代码为基本身份验证设置了下一个凭据:

// We define BASIC Authentication             
CredentialCache myCredentials = new CredentialCache();         
NetworkCredential netCred = new NetworkCredential("User1", "Pass1"); 

But credentials inside Authorization Request token are: 但授权请求令牌中的凭据是:

"lveirman@aquila-XXXXXXX.fr:dynXXXXXXX"

(I recommend you to edit your post and remove the base64 Authentication tokens, additionally is a good idea to change your network password ASAP << DONE) (我建议您编辑帖子并删除base64身份验证令牌,另外最好尽快更改网络密码<< DONE)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM