Pregunta

Tengo que hacer una publicación en la URL https de un tercero para que los datos se procesen y se envíen de vuelta. Y todo lo que tengo como ejemplo es esto:

$signature= foo_string;
$data_to_post = json_dictionary;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $base_url);
curl_setopt($ch, CURLOPT_USERPWD, "$user:$password");
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER,array('Content-Type: application/json'));
curl_setopt($ch, CURLOPT_HTTPHEADER,array("JSON-Signature: $signature"));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_to_post);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($ch);
curl_close($ch);

Mientras trabajamos con ASP .NET C # 2.0, tengo que portar esto, pero siempre obtengo un error no autenticado.

Esto es lo que estoy haciendo:

HttpWebRequest q = (HttpWebRequest)WebRequest.Create(Host + ":" + Port);
                ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(new interhanse().AcceptAllCertifications);                

                q.Method = "POST";
                q.Headers.Add("JSON-Signature:" + GetSignature(data));
                q.ContentType = "application/json";

                q.UseDefaultCredentials = false;
                q.Credentials = new NetworkCredential(user,pwd, Host);

                byte[] buffer = UTF8Encoding.UTF8.GetBytes(data);

                q.ContentLength = data.Length;                

                Stream oStream = q.GetRequestStream();
                StreamWriter oWriter = new StreamWriter(oStream);
                oWriter.Write(buffer);
                oWriter.Close();


                HttpWebResponse reps = q.GetResponse() as HttpWebResponse;

He leído todas las preguntas SO que puedo encontrar sobre esto, pero no obtengo ninguna mejora. Gracias de antemano!

¿Fue útil?

Solución

Bueno, una cosa que estás haciendo mal es asumir que la longitud en bytes es la misma que la longitud en caracteres . Debe usar buffer.Length para la longitud del contenido. También está llamando a StreamWriter.Write con una matriz de bytes . No debes hacer eso, solo debes usar la secuencia, como ya has hecho la codificación:

byte[] buffer = Encoding.UTF8.GetBytes(data);

q.ContentLength = buffer.Length;
using (Stream stream = q.GetRequestStream())
{
    stream.Write(buffer, 0, buffer.Length);
}

Ahora, eso no resolverá el problema de autenticación. Es posible que solo configurar PreAuthenticate resuelva eso:

q.PreAuthenticate = true;

Si eso no funciona, le sugiero que ejecute WireShark y observe las diferencias entre la solicitud a través de Curl y la solicitud de .NET.

Otros consejos

Creo que no debe proporcionar el host en la autenticación ...

q.Credentials = new NetworkCredential(user,pwd);

Que sería algo como:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Host + ":" + Port);
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(new interhanse().AcceptAllCertifications);

request.Method = "POST";
request.Headers.Add("JSON-Signature:" + GetSignature(data));
request.ContentType = "application/json";

request.UseDefaultCredentials = false;
request.Credentials = new NetworkCredential(user, pwd);

byte[] buffer = UTF8Encoding.UTF8.GetBytes(data);

request.ContentLength = buffer.Length;
using (Stream oStream = request.GetRequestStream()) {
    oStream.Write(buffer, 0, buffer.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
    // load data from response here
}

También debe evitar asignar el delegado de validación de punto de servicio en cada solicitud, esto puede ralentizar las solicitudes cada vez más porque la validación se realiza varias veces y también es una especie de pérdida de memoria.

curl_setopt($ch, CURLOPT_USERPWD, "$user:$password");

Así es como agrega ese CURLOPT_USERPWD en Asp.Net:

    private async Task<string> Execute(string url, string query, string user, string pasword)
    {
        HttpClient httpClient = new HttpClient();
        var baseUri = new Uri(url, UriKind.Absolute);  // e.g. http://somedomain.com/endpoint
        Uri request = new Uri(baseUri, query);    // with query e.g. http://somedomain.com/endpoint?arg1=xyz&arg2=abc

        // Add a new Request Message
        HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, request);

        // add headers -> CURLOPT_USERPWD equivalent
        var encodedStr = Convert.ToBase64String(Encoding.Default.GetBytes(string.Format("{0}:{1}", user, password)));
        var authorizationKey = "Basic" + " " + encodedStr;    // Note: Basic case sensitive
        requestMessage.Headers.Add("Authorization", authorizationKey);

        // if POST - do this instead
        // content
        //HttpContent content = new StringContent(jsonContent);     // string jsonContent i.e. JsonConvert.SerializeObject(YourObject);
        //requestMessage.Content = content;
        //requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

        // execute
        HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
        var responseString = await responseMessage.Content.ReadAsStringAsync();    // reads it as string; 

        // if json and you need to convert to an object do this
        // var myresponse = JsonConvert.DeserializeObject<YourMappedObject>(responseString);

        return responseString;
    }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top