2010-06-03 100 views
5

我嘗試在Java中爲我的編程思想實現OAuth,但是我失敗了。我不知道爲什麼,但我的代碼不起作用。每次運行我的程序時,都會拋出IOException,原因是「java.io.IOException:服務器返回的HTTP響應代碼:401」(401代表未授權)。 我仔細看過文檔,但我真的不明白爲什麼它不起作用。 我想用的我的OAuth提供商是twitter,我也註冊了我的應用程序。
在此先感謝
菲尼亞斯在Java中實現OAuth


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

我的建議是:不要重新發明輪子,用別人的解決方案:http://stackoverflow.com/questions/1731966/library -for-oauth-consumer-java – skaffman 2010-06-03 08:49:18

+2

我也考慮過使用一個臃腫的庫,但我想要一個完全適合的解決方案。 對我來說,編程不僅僅意味着放置一些庫或預定義的API,我想在場景之外觀看。 – phineas 2010-06-03 09:10:38

回答

1

嘗試刪除參數 「oauth_callback」。它爲我工作。我正在研究的應用程序是一個Web應用程序。

1

我知道這是一個古老的問題,但它似乎需要一些挖掘最終得到一個正確的答案。這似乎也是谷歌的頂級鏈接之一。 dev.twitter.com上的頁面也幾乎無處可用。所以在這裏。 查看here以獲取正確處理它的代碼。它使用HttpCore,但可以使用標準庫實現。

簡化故事。

  1. 1.6中的URLEncoder庫(最有可能在Android中)也不符合Twitter API所要求的RFC標準。這裏的代碼似乎是部分地解決了這個問題。看看我鏈接的來源,找到適當處理它的方法。
  2. 創建基本字符串參數時,您正在編碼每個鍵值對。它符合Twitter頁面上的指南。附加編碼url和整個創建的參數字符串(鍵/值對)更容易
  3. 在創建簽名時,您正在使用CONSUMER_KEY附加了「&」簽名的keyspec對象Twitter API。
  4. 就此代碼而言。對於請求令牌,它似乎並不重要。

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

    這其中雖然不 connection.setRequestMethod(method);