2012-06-26 10 views
5

He escrito una aplicación muy simple para actualizar mi estado de Twitter en una condición dada. He utilizado la documentación de Twitter para comprender los requisitos para crear la firma OAuth y también cómo estructurar el encabezado Authorization. Luego envío la solicitud con cURL en PHP.¿Por qué no puedo autenticarme con OAuth?

Uso de las herramientas de OAuth en el sitio Twitter dev, que en comparación tanto mi cadena de base de la firma y autorización de cabecera, y ambos son exactamente los mismos:

Base Firma cadena

POST&https%3A%2F%2Fapi.twitter.com%2F1%2Fstatuses%2Fupdate.json&oauth_consumer_key%3DYNxxxxxxxxxxxWnfI6HA%26oauth_nonce%3D31077a3c7b7bee4e4c7e2b5185041c12%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1340729904%26oauth_token%3D2991771-4csoiO2fxmWgSxxxxxxxxxxDjWj2AbyxATtiuadNE%26oauth_version%3D1.0%26status%3Dblah%2520test%2520blah. 

Autorización encabezado

Authorization: OAuth oauth_consumer_key="YN4FLBxxxxxxxxxxI6HA", oauth_nonce="31077a3c7b7bee4e4c7e2b5185041c12", oauth_signature="M2cXepcxxxxxxxxxxAImeAjE%2FHc%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1340729904", oauth_token="2991771-4cxxxxxxxxxxSmRvjzMoooMDjWj2AbyxATtiuadNE", oauth_version="1.0" 

Obviamente he reemplazado s Algunos caracteres con x para ocultar mis datos, pero al comparar los dos caracteres para el carácter se obtiene exactamente el mismo resultado. Como referencia, codifico la marca de tiempo y la fecha de nacimiento que genera la herramienta OAuth para que mis valores puedan ser los mismos para la verificación. Mi nivel de acceso está configurado para Leer y escribir. En esa misma página hay un último ejemplo: el comando para ejecutar con cURL en la línea de comando. Cuando ejecuto este comando, funciona perfectamente y se publica en mi feed de Twitter sin problemas.

Teniendo esto en cuenta, creo que todo lo que he creado hasta ahora está bien, y no creo que haya mucho más que publique el código que genera los detalles mencionados anteriormente. Sin embargo, el código que utilizo para hacer la llamada, usando cURL, creo que es el culpable, pero no puede decir por qué:

<?php 
// ... 
$curl = curl_init(); 

curl_setopt($curl, CURLOPT_URL, $baseUrl); 
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 
curl_setopt($curl, CURLOPT_POST, true); 
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); 
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: $header")); 
curl_setopt($curl, CURLOPT_POSTFIELDS, array('status' => $status)); 
$result = json_decode(curl_exec($curl)); 
curl_close($curl); 

var_dump($result); 

Tenga en cuenta que $baseUrl, $header y $status son las mismas variables utilizadas en la generación de la firma cadena de base y encabezado de autorización, que coinciden muy bien.

La salida de la página cuando el funcionamiento es:

object(stdClass)#1 (2) { ["error"]=> string(34) "Could not authenticate with OAuth." ["request"]=> string(23) "/1/statuses/update.json" } 

espero que haya suficientes detalles aquí para que alguien me punto en la dirección correcta!

+0

¿Ha consultado https://dev.twitter.com/discussions/305 (por ejemplo, consulte la URL) y https://dev.twitter.com/discussions/308 (por ejemplo, verifique las opciones de HTTPS)? – Will

+0

Lamentablemente, sí. Como dije, la cadena base de la firma y el encabezado de autorización son exactamente iguales, y como la curva de línea de comando funciona perfectamente, no puede ser ninguna de estas. – LeonardChallis

+0

Tenía exactamente el mismo problema. ¡Gracias! – bozdoz

Respuesta

2

Después de mucho más penetrante, de prueba con apache_request_headers() y siendo fiel a la idea de que mis datos estaba bien y era cURL donde colocó el problema, me di cuenta de que se curvan se ponía el Content-type de la solicitud como multipart/form-data; y añadiendo información de límites, obviamente, con un campo más largo Content-Length también. Esto significaba que el estado no se enviaba correctamente, supongo que debido a una solicitud mal formada multipart/form-data;.

La solución fue enviarlo como una cadena.Por ejemplo, esto funciona:

curl_setopt($curl, CURLOPT_POSTFIELDS, 'status='. rawurlencode($status)); 

pero he encontrado que hay una manera aún más agradable (especialmente con múltiples valores, cuando quiero utilizar una matriz):

$postfields = array('status' => $status); 
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($postfields)); 

que se ve en mi humilde opinión mucho más agradable.

1

Creo que es su nonce. Del docs: "El parámetro oauth_nonce es un token único que su aplicación debe generar para cada solicitud única" (énfasis mío).

Advertencia: Estoy más familiarizado con OAuth 2 + Java o JavaScript que con OAuth 1 + PHP.

Si eso no es (o no es lo único), podría comparar su solicitud HTTP real (por ejemplo, utilizando WireShark) con la solicitud de muestra que documentan en esa página. La nota allí en "Construyendo la cadena del encabezado" también puede ser útil.

+0

No habría forma de distinguir quién generó el nonce. Como ya he dicho, el encabezado de autorización y la cadena base son * exactamente iguales *, por lo que al ejecutar curl, no sabrían/​​se preocupan por quién generó ese nonce primero. El nonce solo estaba codificado para comparar los valores. Creo que comparar la solicitud HTTP es el camino a seguir y, de hecho, cambié '$ baseUrl' a mi propia página y probé con la línea de comando cURL en comparación con PHP cURL call, pero no ha surgido nada obvio. – LeonardChallis

+0

Estoy bastante seguro de que Twitter cachearía nonces y rechazaría repeticiones, evitando así los ataques de repetición. Ver http://oauth.net/core/1.0/#nonce: "El consumidor DEBERÁ generar un valor de Nonce que sea único para todas las solicitudes con esa marca de tiempo. Un nonce es una cadena aleatoria, generada de manera exclusiva para cada solicitud. permite al proveedor de servicios verificar que nunca se haya realizado una solicitud y ayuda a prevenir ataques de repetición cuando las solicitudes se realizan a través de un canal no seguro (como HTTP) ". – Will

+1

No creo que me entiendas. La única vez que codifico el nonce es comparar mi encabezado de autorización y la cadena base de firma con los generados por Twitter. Probé la solicitud de cURL generada cuando coincidían para asegurarme de que se completara, y así fue. No trato de usar ese mismo nonce nuevamente en mi script PHP. Es ** definitivamente no es el momento **. En mi script tengo una función que genera un nonce único. Gracias por su aporte, sin embargo. – LeonardChallis

Cuestiones relacionadas