【问题标题】:Implement OAuth in Java在 Java 中实现 OAuth
【发布时间】:2011-02-27 05:00:07
【问题描述】:

我尝试在 Java 中为我的编程理念实现 OAuth,但我惨遭失败。我不知道为什么,但我的代码不起作用。每次我运行我的程序时,都会抛出一个 IOException,原因是“java.io.IOException:服务器返回 HTTP 响应代码:401”(401 表示未经授权)。 我仔细查看了文档,但我真的不明白为什么它不起作用。 我想使用的 OAuth 提供程序是 twitter,我也在其中注册了我的应用程序。
提前感谢
飞哥


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"));
   }
}

【问题讨论】:

  • 我的建议:不要重新发明轮子,使用别人的解决方案:stackoverflow.com/questions/1731966/…
  • 我也考虑过使用臃肿的库,但我想要一个完全适合的解决方案。对我来说,编程不仅仅是将一些库或预定义的 API 放在一起,我想获得一个超越场景。

标签: java twitter oauth


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    我知道这是一个老问题,但似乎需要花点时间才能最终得到正确的答案。这似乎也是谷歌的热门链接之一。 dev.twitter.com 上的页面也几乎无处可去。就这样吧。 查看here 以获取正确处理它的代码。它使用HttpCore,但可以通过标准库来实现。

    让故事简短。

    1. 1.6 中的 URLEncoder 库(很可能在 Android 中也是如此)不符合 RFC 标准 Twitter API 要求。这里的代码似乎部分地解决了这个问题。查看我链接的源代码以找到适当处理它的方法。
    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);

    【讨论】:

      猜你喜欢
      • 2011-02-17
      • 2011-01-10
      • 2011-06-30
      • 2011-04-08
      • 2014-05-07
      • 1970-01-01
      • 2016-02-20
      • 2013-01-24
      • 1970-01-01
      相关资源
      最近更新 更多