在Java中实现OAuth

我尝试用Java编写实现OAuth的编程思想,但我失败了。 我不知道为什么,但我的代码不起作用。 每次运行程序时,都会抛出IOException,原因是“java.io.IOException:服务器返回HTTP响应代码:401”(401表示未授权)。 我仔细看了一下这些文档,但我真的不明白它为什么不起作用。 我想使用的OAuth提供程序是twitter,我也注册了我的应用程序。
提前致谢
菲尼亚斯

OAuth文档
Twitter API维基
类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")); } } 

尝试删除参数“oauth_callback”。 它对我有用。 我正在处理的应用程序是一个Web应用程序。

我知道这是一个老问题,但似乎需要一些挖掘才能最终得到一个正确的答案。 这似乎也是谷歌的顶级链接之一。 dev.twitter.com上的页面几乎无处可寻。 所以这就是它。 在这里查找正确处理它的代码。 它使用HttpCore ,但可以使用标准库实现。

让故事简短。

  1. 1.6中的URLEncoder库(最有可能在Android中也是如此)不符合Twitter API所要求的RFC标准。 这里的代码似乎部分地解决了这个问题。 看看我链接的源代码,找到适当处理它的方法。
  2. 在创建基本字符串参数时,您将对每个键值对进行编码。 它符合twitter页面上的指南。 附加编码的url和整个创建的参数字符串(键/值对)更容易
  3. 在创建签名时,您将针对keyspec对象创建它,其中CONSUMER_KEY在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);