2010-06-03 22 views
5

Intenté implementar OAuth para mi idea de programación en Java, pero fallé miserablemente. No sé por qué, pero mi código no funciona. Cada vez que ejecuto mi programa, se lanza una IOException con el motivo "java.io.IOException: El servidor devolvió el código de respuesta HTTP: 401" (401 significa "No autorizado"). Eché un vistazo de cerca a los documentos, pero realmente no entiendo por qué no funciona. Mi proveedor OAuth que quería usar es twitter, donde también he registrado mi aplicación.
Gracias de antemano
phineasImplementar OAuth en Java


OAuth docs
Twitter API wiki
Class Base64Coder

import java.io.InputStreamReader; 
import java.io.BufferedReader; 
import java.io.OutputStream; 
import java.io.IOException; 
import java.io.UnsupportedEncodingException; 
import java.net.URL; 
import java.net.URLEncoder; 
import java.net.URLConnection; 
import java.net.MalformedURLException; 
import javax.crypto.Mac; 
import javax.crypto.spec.SecretKeySpec; 
import java.security.NoSuchAlgorithmException; 
import java.security.InvalidKeyException; 

public class Request { 
    public static String read(String url) { 
     StringBuffer buffer = new StringBuffer(); 
     try { 
     /** 
     * get the time - note: value below zero 
     * the millisecond value is used for oauth_nonce later on 
     */ 
      int millis = (int) System.currentTimeMillis() * -1; 
      int time = (int) millis/1000; 

      /** 
      * Listing of all parameters necessary to retrieve a token 
      * (sorted lexicographically as demanded) 
      */ 
      String[][] data = { 
       {"oauth_callback", "SOME_URL"}, 
       {"oauth_consumer_key", "MY_CONSUMER_KEY"}, 
       {"oauth_nonce", String.valueOf(millis)}, 
       {"oauth_signature", ""}, 
       {"oauth_signature_method", "HMAC-SHA1"}, 
       {"oauth_timestamp", String.valueOf(time)}, 
       {"oauth_version", "1.0"} 
      }; 

      /** 
      * Generation of the signature base string 
      */ 
      String signature_base_string = 
       "POST&"+URLEncoder.encode(url, "UTF-8")+"&"; 
      for(int i = 0; i < data.length; i++) { 
       // ignore the empty oauth_signature field 
       if(i != 3) { 
       signature_base_string += 
        URLEncoder.encode(data[i][0], "UTF-8") + "%3D" + 
        URLEncoder.encode(data[i][1], "UTF-8") + "%26"; 
       } 
      } 
      // cut the last appended %26 
      signature_base_string = signature_base_string.substring(0, 
       signature_base_string.length()-3); 

      /** 
      * Sign the request 
      */ 
      Mac m = Mac.getInstance("HmacSHA1"); 
      m.init(new SecretKeySpec("CONSUMER_SECRET".getBytes(), "HmacSHA1")); 
      m.update(signature_base_string.getBytes()); 
      byte[] res = m.doFinal(); 
      String sig = String.valueOf(Base64Coder.encode(res)); 
      data[3][1] = sig; 

      /** 
      * Create the header for the request 
      */ 
      String header = "OAuth "; 
      for(String[] item : data) { 
       header += item[0]+"=\""+item[1]+"\", "; 
      } 
      // cut off last appended comma 
      header = header.substring(0, header.length()-2); 

      System.out.println("Signature Base String: "+signature_base_string); 
      System.out.println("Authorization Header: "+header); 
      System.out.println("Signature: "+sig); 

      String charset = "UTF-8"; 
      URLConnection connection = new URL(url).openConnection(); 
      connection.setDoInput(true); 
      connection.setDoOutput(true); 
      connection.setRequestProperty("Accept-Charset", charset); 
      connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset); 
      connection.setRequestProperty("Authorization", header); 
      connection.setRequestProperty("User-Agent", "XXXX"); 
      OutputStream output = connection.getOutputStream(); 
      output.write(header.getBytes(charset)); 

      BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); 

      String read; 
      while((read = reader.readLine()) != null) { 
       buffer.append(read); 
      } 
     } 
     catch(Exception e) { 
      e.printStackTrace(); 
     } 

     return buffer.toString(); 
    } 

    public static void main(String[] args) { 
     System.out.println(Request.read("http://api.twitter.com/oauth/request_token")); 
    } 
} 
+1

Mi consejo: no reinventar la rueda, utilizar la solución de otra persona: http://stackoverflow.com/questions/1731966/library -for-oauth-consumer-java – skaffman

+2

He considerado utilizar también una biblioteca inflada, pero quería una solución que se adapte perfectamente. Para mí, la programación significa más que simplemente poner algunas bibliotecas o API predefinidas juntas, yo quería obtener una mirada más allá de las escenas. – phineas

Respuesta

1

Intenta quitar el "oauth_callback" parámetro. Funcionó para mí La aplicación en la que estaba trabajando es una aplicación web.

1

Sé que esta es una vieja pregunta, pero parece que se necesita un poco de investigación para finalmente obtener una respuesta correcta. Este parece ser uno de los principales enlaces en google también. Las páginas en dev.twitter.com conducen a casi ninguna parte también. Entonces aquí va. Mire here para obtener un código que maneje correctamente. Utiliza HttpCore, pero se puede lograr con bibliotecas estándar.

Haciendo la historia corta.

  1. La biblioteca URLEncoder en 1.6 (muy probablemente también en Android) no cumple con el estándar de RFC que Twitter API requiere. El código aquí parece estar contrarrestando el problema parcialmente. Eche un vistazo a la fuente que he vinculado para encontrar el método que lo maneje apropiadamente.
  2. Al crear el parámetro de cadena base, está codificando cada par de valores clave. Se ajusta a la guía en la página de Twitter. Es más fácil agregar la url codificada y la cadena de parámetros creada por completo (pares de clave/valor)
  3. Al crear la firma, la está creando contra un objeto keyspec con CONSUMER_KEY junto con el método de token de solicitud de inicio de sesión "&" del API de Twitter
  4. En cuanto a este código. Para el token de solicitud, no parece ser importante en absoluto.

    connection.setRequestProperty("Accept-Charset", charset); 
    connection.setRequestProperty("Content-Type", "application/x-www-formurlencoded;charset="+ charset); 
    connection.setRequestProperty("User-Agent", "XXXX"); 
    

    Ésta, sin embargo, hace connection.setRequestMethod(method);