【问题标题】:Google oauth java client to get an access token fails with "400 Bad Request { "error" : "invalid_request" }"Google oauth java 客户端获取访问令牌失败,出现“400 Bad Request {“error”:“invalid_request”}”
【发布时间】:2012-11-18 07:01:14
【问题描述】:

我正在使用此处显示的“Web 服务器应用程序”示例。在我的回调 servlet 中,我想检索一个访问令牌,但我无法成功地做到这一点。 以下是我的代码

  @Override
  protected String getUserId(HttpServletRequest req) throws ServletException, IOException {
    // return user ID
      Iterator<String> iterator = req.getParameterMap().keySet().iterator();
        while (iterator.hasNext()) {
            String string = iterator.next();

            System.out.println(string+"---++--"+req.getParameter(string));
        }
        GoogleAuthorizationCodeTokenRequest newTokenRequest = new GoogleAuthorizationCodeFlow.Builder(new NetHttpTransport(), new JacksonFactory(),
                                                             "2XXXXXX7218.apps.googleusercontent.com", "KugD_XXX_7vqnGZVXXXXX1M",
                                                              Collections.singleton("https://gdata.youtube.com"))
                                                              .build().newTokenRequest(req.getParameter("code"));
        //GoogleAuth
        GoogleTokenResponse token = newTokenRequest.setRedirectUri("/").execute();
        String accessToken = token.getAccessToken();
        System.out.println("accesstoken:"+accessToken);
        return "";
  }

运行此代码后出现以下错误

com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
  "error" : "invalid_request"
}

简而言之,我得到了“代码”参数(请求代码),我不确定如何将其转换为访问令牌。 我已经看过了 Google API - request for token from Oauth2 returns "invalid_request" Google OAuth 2: response_type error on token request 但我的代码中没有什么可以使用的

编辑

谷歌 API 对我不起作用,所以我在不使用任何库的情况下编写了以下代码

 URL url = new URL("https://accounts.google.com/o/oauth2/token");
    connection = (HttpURLConnection) url.openConnection();
    String urlParameters = "code=" + req.getParameter("code") + "&client_id=29852.apps.googleusercontent.com&client_secret=KugD_LVi_7vqnssssxxxNRBz1M"+
            "&redirect_uri=https://flixomnia.com/oauth2callback&grant_type=authorization_code&scope=https://gdata.youtube.com&response_type=token";
    connection.setDoOutput(true);
    connection.setDoInput(true);
    connection.setInstanceFollowRedirects(true);
    connection.setRequestMethod("POST");
    connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    connection.setRequestProperty("Authorization", "Bearer 4/q3Xh_pJI458XXXXXXXkh-lxe3-8.cmaD6o7V5BkQXE-XXXXX-edgI");
    connection.setRequestProperty("Content-Length", "" + Integer.toString(urlParameters.getBytes().length));
    connection.setRequestProperty("X-GData-Key", "key=AI39siXXXXXXM7tyHBvXEM1lLcORetit6QSArQ3sjelBxXXXXXXtgLSPdZPxvsF_vkntOQMnAEYAuVFqhN7oUw");
    connection.setRequestProperty("GData-Version", "2");

    connection.setUseCaches(false);
    //com.google.gdata.client.youtube.YouTubeService service = new com.google.gdata.client.youtube.YouTubeService("","");
    //YouTubeMediaGroup g = new YouTubeMediaGroup();


    DataOutputStream wr = new DataOutputStream(connection.getOutputStream());

    wr.writeBytes(urlParameters);
    wr.flush();
    InputStream inputStream = connection.getInputStream();
    byte[] b = new byte[1024];
    while (inputStream.read(b) != -1) {
        System.out.print(new String(b));

    }
    System.out.println("");
    wr.close();
    connection.disconnect();

但我仍然收到以下错误

    {  "error" : "invalid_request"}
java.io.IOException: Server returned HTTP response code: 400 for URL: https://accounts.google.com/o/oauth2/token
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1615)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
    at com.broadcastr.servlets.YouTubeCallbackService.getUserId(YouTubeCallbackService.java:168)
    at com.google.api.client.extensions.servlet.auth.oauth2.AbstractAuthorizationCodeCallbackServlet.doGet(AbstractAuthorizationCodeCallbackServlet.java:130)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1001)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)

【问题讨论】:

  • 我今晚才开始使用 google-oauth-java-client,但您似乎没有正确设置回调 URI(“/”),我觉得不合适。也许遵循code.google.com/p/google-oauth-java-client/wiki/OAuth2 的Servlet 授权代码流会有所帮助。我发现示例代码非常有用,但它是针对 Java 客户端的,而不是针对 servlet 的。祝你好运。
  • 不行,还是不行,我试过localhost:8080...!!
  • @RichardBerger 查看我的新编辑,它仍然无法正常工作:(

标签: java oauth-2.0 google-oauth


【解决方案1】:

我也浪费了我 2 天的时间来解决这个问题。我无法使用HttpUrlConnection 发布令牌请求。 HttpClient 为我工作。

以下是工作代码:

1) 传递的值:

String url = "https://accounts.google.com/o/oauth2/token";
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("grant_type", "authorization_code"));

nameValuePairs.add(new BasicNameValuePair("client_id",client_id));
nameValuePairs.add(new BasicNameValuePair("client_secret", client_secret));
nameValuePairs.add(new BasicNameValuePair("redirect_uri", "http://example.com/bin/showcase/servlet/googlecallback"));
nameValuePairs.add(new BasicNameValuePair("code", code));

StringBuffer postResult =  sendPost(url, nameValuePairs);

2) 方法

private StringBuffer sendPost(String url, List<NameValuePair> postParams) 
        throws Exception {

    HttpPost post = new HttpPost(url);
    HttpClient client = new DefaultHttpClient();

    // add header
    post.setHeader("Host", "accounts.google.com");
    post.setHeader("Accept", 
            "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
    post.setHeader("Accept-Language", "en-US,en;q=0.5");
    post.setHeader("Connection", "keep-alive");
    post.setHeader("Referer", "https://accounts.google.com/o/oauth2/token");
    post.setHeader("Content-Type", "application/x-www-form-urlencoded");

    post.setEntity(new UrlEncodedFormEntity(postParams));

    HttpResponse response = client.execute(post);

    int responseCode = response.getStatusLine().getStatusCode();

    BufferedReader rd = new BufferedReader(
            new InputStreamReader(response.getEntity().getContent()));

    StringBuffer result = new StringBuffer();
    String line = "";`enter code here`
    while ((line = rd.readLine()) != null) {
        result.append(line);
    }
    return result;
}

【讨论】:

  • 谢谢,我想补充一点,标题对我来说非常重要。
【解决方案2】:

请从请求 URL 中删除 EDIT 代码中存在问题的“&response_type=token”参数,您的问题将得到解决。

【讨论】:

    【解决方案3】:
    1. 在上面初始代码中的setRedirectUri方法中获取访问令牌,redirect_uri设置不正确。应使用在客户端注册时指定的redirect_uri

    2. 在 EDIT 代码中,在向访问令牌端点发送所需参数的同时,还会随请求一起发送不受支持的参数 response_type。删除response_type 参数应该可以解决问题。

      此外,根据OAuth2 RFC draft,如果请求使用多种机制来验证客户端身份,访问令牌端点也可能会出错invalid_request。因此,将Authorization 标头删除到URLConnection 也应该可以解决问题。

    【讨论】:

      【解决方案4】:

      在让 Java 应用和 Android 应用访问我的 Oauth 服务器时,我发现以下两个库很有用 - 但它们的用途不同 - 也许一个比另一个更适合您的需求。

      1. google-oauth-java-client 在 DailyMotion 中使用。 https://code.google.com/p/google-oauth-java-client/, http://samples.google-oauth-java-client.googlecode.com/hg/dailymotion-cmdline-sample/instructions.html 此库/示例代码允许您从 Java 访问您自己的 OAuth2 服务器。

      2. google-api-java-client 用于:Android中的Auth2流(Latitude)http://blog.doityourselfandroid.com/2011/08/06/oauth-2-0-flow-android/ 此库/示例代码专门用于通过 OAuth2 访问 Google API。

      我不确定您要解决哪个问题,但是这两个问题中的一个应该会有所帮助。两者都经历了将“代码”交换为“authToken”的过程,但方式略有不同。 RB

      【讨论】:

      • 嘿,Richard,使用客户端库的建议很好,但是,在 Android 上使用 OAuth2 的首选方法是 Google Play Services 库。原来的帖子是针对网络服务器的,所以这不适用,但对于你的情况,你应该考虑转移到它,因为它是为了安全性和可用性。 developer.android.com/google/play-services/auth.html
      • 大卫:感谢您的更新。一个问题 - 从我对您提供的参考资料的快速浏览来看,似乎 Google Play 服务是访问任何 Google API 时要走的路,而不是访问一些随机的第 3 方 API。这通常是正确的吗?
      • 理查德,你是对的。我们已经听到了关于使用 Google 以外的其他 API 的请求,但我们目前没有要宣布的内容。
      【解决方案5】:

      上面的 Richard 是对的,在 setRedirectUri 中,您需要使用您在注册应用程序时指定的完整重定向 URI。这不应该是相对的,而是绝对的。 (希望是 https)

      戴维普

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-12
        • 2015-05-10
        • 2019-04-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-26
        相关资源
        最近更新 更多