如何通过 Jersey+Oltu 从 Java 桌面应用程序访问 Bitbucket API?

How to access Bitbucket API from a Java Desktop App via Jersey+Oltu?

如标题所述,我想访问 bitbucket API from a native Java Desktop Application. Bitbucket requires Applications to use OAuth2, and for that I found that Oltu 应该完成的工作。

然而,我对OAuth的了解非常有限,所以我还停留在很早的阶段。这是我到目前为止所做的:

第 1 步: 我使用我的 Bitbucket 帐户注册了一个 OAuth 消费者,详细信息如下:

Name: jerseytestapp
Description:
CallbackURL: http://localhost:8080/
URL: 

问题 1:我可以自动执行此步骤吗?

第2步:我运行以下Java代码:

package jerseytest;

import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;

public class BitbucketJersey {

    public static void main(String[] args) {
    OAuthClientRequest request;
    try {
        request = OAuthClientRequest
                .authorizationLocation("https://bitbucket.org/site/oauth2/authorize")
                .setClientId("jerseytestapp")
                .setRedirectURI("http://localhost:8080")
                .buildQueryMessage();

            System.out.println(request.getLocationUri());

        } catch (OAuthSystemException e) {
            e.printStackTrace();
        }
    }

}

第 3 步: 我收到以下 locationURI 并在 Firefox 中打开

https://bitbucket.org/site/oauth2/authorize?redirect_uri=http%3A%2F%2Flocalhost%3A8080&client_id=jerseytestapp

问题 2:我需要使用浏览器还是可以从 java 应用程序执行此操作?

我在 Firefox 中收到以下回复消息:

Invalid client_id
This integration is misconfigured. Contact the vendor for assistance.

问题 3:接下来正确的步骤是什么,我的方法有什么问题?

答案 1:您可以自动创建 OAuth 消费者,但您可能不想这样做。

Bitbucket 提供 documentation on how to create a consumer through their APIs,尽管文档缺少许多相关字段。即便如此,您仍然可以通过编程方式制作一个 HTTP 请求,它模仿 Bitbucket 的 Web 界面为创建消费者所做的任何事情。所以是的,它可以自动化。

这就是您可能不想这样做的原因。在您的情况下,您有三样东西需要协同工作:您的应用程序、最终用户和 Bitbucket。 (或者就此流程的 OAuth 术语而言,它们分别是 client, resource owner, and authorization server。)正常的处理方式是您的应用程序由您在帐户中创建的 OAuth 消费者唯一标识,您的应用程序对 Bitbucket 的所有使用都将使用该单一 OAuth 消费者来识别您的应用程序。因此,除非您正在做类似开发生成其他 Bitbucket 应用程序的 Bitbucket 应用程序之类的事情,否则您不需要自动创建其他 OAuth 消费者。

答案 2:您可以直接从您的 Java 应用程序授权。

Bitbucket 声明 it supports all four grant flows/types defined in RFC-6749. Your code is currently trying to use the Authorization Code Grant type. Using this grant type WILL force you to use a browser. But that’s not the only problem with this grant type for a desktop application. Without a public webserver to point at, you will have to use localhost in your callback URL, as you are already doing. That is a big security hole because malicious software could intercept traffic to your callback URL to gain access to tokens that the end user is granting to your application only. (See the comments on this Whosebug question for more discussion on that topic.) Instead, you should be using the Resource Owner Password Credentials Grant type which will allow you to authenticate a Bitbucket’s username and password directly in your application, without the need of an external browser or a callback URL. Bitbucket provides a sample curl command on how to use that grant type here

答案 3:正确的后续步骤是根据以下示例对您的代码进行建模。您的方法有什么问题是您正在尝试使用不适合您需要的授权类型,并且您正在尝试使用您的 OAuth 消费者的名称来识别您的应用程序而不是您的消费者的密钥和秘密。

以下代码示例使用我自己的 username/password/key/secret 组合成功检索了访问令牌,其值已被替换掉。使用 JDK 1.8.0_45 和 org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:1.0.0.

测试代码
OAuthClientRequest request = OAuthClientRequest
    .tokenLocation("https://bitbucket.org/site/oauth2/access_token")
    .setGrantType(GrantType.PASSWORD)
    .setUsername("someUsernameEnteredByEndUser")
    .setPassword("somePasswordEnteredByEndUser")
    .buildBodyMessage();
String key = "yourConsumerKey";
String secret = "yourConsumerSecret";
byte[] unencodedConsumerAuth = (key + ":" + secret).getBytes(StandardCharsets.UTF_8);
byte[] encodedConsumerAuth = Base64.getEncoder().encode(unencodedConsumerAuth);
request.setHeader("Authorization", "Basic " + new String(encodedConsumerAuth, StandardCharsets.UTF_8));
OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
OAuthResourceResponse response = oAuthClient.resource(request, OAuth.HttpMethod.POST, OAuthResourceResponse.class);
System.out.println("response body: " + response.getBody());

您的主要问题是您提供的是客户名称而不是客户 ID:

.setClientId("jerseytestapp")

获取我所知道的客户端 ID 的唯一方法是查询: https://bitbucket.org/api/1.0/users/your_account_name/consumers

然而,即使那样它仍然无法正常工作,所以我联系了 bitbucket 支持。结果证明文档具有误导性。您实际上需要改用客户端密钥。

.setClientId("ydrqABCD123QWER4567") // or whatever your case might be

https://bitbucket.org/site/oauth2/authorize?client_id=client_key&response_type=token