Android:使用OAuth访问Google任务时出现问题

end*_*yha 3 android

由于google任务没有公共API,我想编写解决方法并像浏览器一样请求数据,然后解析结果以进一步显示.

要访问数据,我已经通过Google实施了OAuth身份验证来访问此网址:https://mail.google.com/

对于OAuth,我使用了sign-post库,效果很好.

问题是,当我尝试使用已签名的请求访问https://mail.google.com/tasks/ig时,它会返回登录页面而不是带有任务的所需列表.

更具体的是我的代码:

public class GoogleOAuthActivity extends Activity {
    private static final String TAG = GoogleOAuthActivity.class.getSimpleName();
    private CommonsHttpOAuthProvider provider;
    private CommonsHttpOAuthConsumer consumer;

    @Override
    @SuppressWarnings("unchecked")
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        provider = new CommonsHttpOAuthProvider(OAuthPrefs.GET_REQUEST_TOKEN_URL, OAuthPrefs.GET_ACCESS_TOKEN_URL,
                OAuthPrefs.TOKEN_AUTHORIZATION_URL);
        consumer = new CommonsHttpOAuthConsumer(OAuthPrefs.CONSUMER_KEY, OAuthPrefs.CONSUMER_SECRET);
        consumer.setMessageSigner(new HmacSha1MessageSigner());

        Log.v(TAG, "Starting google authentication activity");
        new RequestGoogleOAuth(this, provider, consumer).execute();
    }

    @Override
    @SuppressWarnings("unchecked")
    public void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        final Uri uri = intent.getData();
        if (uri != null && uri.getScheme().equals(OAuthPrefs.CALLBACK_SCHEME)) {
            Log.v("OAUTH MAIN", "STARTING STAGE TWO");
            new ConfirmGoogleOAuthTask(this, provider, consumer).execute(uri);
            finish();
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

第一个OAuth阶段

public class RequestGoogleOAuth extends OAuthGoogleTask {
    public static final String TAG = RequestGoogleOAuth.class.getSimpleName();

    public RequestGoogleOAuth(Context context, CommonsHttpOAuthProvider provider, CommonsHttpOAuthConsumer consumer) {
        super(context, provider, consumer);
    }

    protected Object doInBackground(Object... params) {
        final String TAG = getClass().getName();
        try {
            final String url = provider.retrieveRequestToken(consumer, OAuthPrefs.CALLBACK_URL);
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)).setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
                    & Intent.FLAG_ACTIVITY_NO_HISTORY & Intent.FLAG_FROM_BACKGROUND);
            context.startActivity(intent);
            Log.v(TAG, "Request google authentication");
        } catch (Exception e) {
            Log.e(TAG, "ERROR during google authentication request", e);
        }
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

第二个OAuth阶段并尝试访问Google任务

public class ConfirmGoogleOAuthTask extends OAuthGoogleTask {
    public ConfirmGoogleOAuthTask(Context context, CommonsHttpOAuthProvider provider, CommonsHttpOAuthConsumer consumer) {
        super(context, provider, consumer);
    }

    @Override
    public Object doInBackground(Object... params) {
        final Uri uri = (Uri) params[0];
        final String TAG = getClass().getName();

        final SharedPreferences prefs = context.getSharedPreferences(OAuthPrefs.PREF_NAME, Context.MODE_PRIVATE);
        final String oauthVerifier = uri.getQueryParameter(OAuth.OAUTH_VERIFIER);

        try {
            provider.retrieveAccessToken(consumer, oauthVerifier);
            final Editor edit = prefs.edit();
            edit.putString(OAuth.OAUTH_TOKEN, consumer.getToken());
            edit.putString(OAuth.OAUTH_TOKEN_SECRET, consumer.getTokenSecret());
            edit.commit();

            CommonsHttpOAuthConsumer consumer = new CommonsHttpOAuthConsumer(OAuthPrefs.CONSUMER_KEY, OAuthPrefs.CONSUMER_SECRET);
            consumer.setMessageSigner(new HmacSha1MessageSigner());
            consumer.setTokenWithSecret(consumer.getToken(), consumer.getTokenSecret());

            HttpClient httpClient = HttpUtils.createHttpClient();
            HttpGet httpGet = new HttpGet(consumer.sign("https://mail.google.com/tasks/ig"));
            HttpResponse response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            Log.d(TAG, "Status code = " + statusCode);
            if (statusCode == HttpStatus.SC_OK) {
                String xml = ConvertUtils.convertStreamToString(response.getEntity().getContent(), true);
                Log.d(TAG, "XML = " + xml);
            }

            Log.v(TAG, "Successfully receive access token");
        } catch (Exception e) {
            Log.e(TAG, "ERROR during request for access token", e);
        }
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

在这一行:

String xml = ConvertUtils.convertStreamToString(response.getEntity().getContent(), true);
                    Log.d(TAG, "XML = " + xml);
Run Code Online (Sandbox Code Playgroud)

我可以看到我收到"登录页面"

我认为原因是google不提供对此服务的访问权限,即使我已经使用OAuth进行身份验证,也限制了我对此资源的访问权限(即使我已将范围定义为https://mail.google.com/) .我不知道如何立即实现它,但看起来我需要模拟浏览器与谷歌的交互方式(检索和发送适当的coockies).但我问,因为我不确定如何处理这种情况,因为我已经提到google tasks API没有公共API(肥皂,休息或任何其他)所以对我来说如何为此实现客户端并不明显特征...

如果某人有应用程序访问谷歌资源而没有公共API的示例,我将非常高兴看到这一点.

谢谢,有人知道答案!

rya*_*yan 5

[在5/11更新推荐API,4/6使用普通ClientLogin而不是cookie]

现在有一个Google Tasks API!使用它,它更容易,你的代码将更易于维护.只考虑后代的其余部分.

不幸的是,你走在正确的轨道上.谷歌任务还没有API,OAuth或其他,所以你必须做一些HTML抓取.:/ afaik,这就是客户现在所做的所有其他第三方任务.ClientLogin确实适用于auth,所以这至少是这样的.

这里有一些执行此操作的shell脚本代码:http://privacylog.blogspot.com/2010/09/updated-google-tasks-api.html.详情如下.

首先,POSTwww.google.com/accounts/ClientLogin在描述http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html#Request得到一个身份验证令牌.使用goanna_mobile的服务名称.(这个很重要!)

然后,使用您在上面收到的身份验证令牌传递标头.你会得到HTML回来.提取各个任务列表的ID.它们的形式为04291568652951293844:0:0.GET https://mail.google.com/tasks/mAuthorization:GoogleLogin

然后,您将发送带有JSON编码主体的POST https://mail.google.com/tasks/r/d以获取每个列表的内容.这是一个示例体:

r={action_list:
   [{action_type: get_all,
     action_id: 5,
     list_id: 0429158965...:0:0,
     get_deleted: false,
     date_start: 1969-12-31,
     get_archived: true
    }],
   client_version: 1256686
  }
Run Code Online (Sandbox Code Playgroud)

重要笔记:

  • latest_sync_point:0表示获取所有任务
  • r =中的= 不是 url编码为r%3D
  • 包括标题'AT:1'.没有它任务返回401 Unauthorized.

输出更多是JSON,例如:

{latest_sync_point: 1263000002293000, response_time:1263077227, results:[], tasks:
  [{id: 04291589652955....:0:38,
    last_modified: 1263000002281,
    name: foo bar
    notes: ,
    type: TASK,
    deleted: false,
    list_id: [0429158965...:0:0],
    completed: false
   },
   {id: 0429158965295...:0:37,
    last_modified: 1262929947949,
    name: baz
    notes: ,
    type: TASK,
    deleted:false,
    list_id: [0429158965295...:0:0],
    completed: false
   },
   ...
Run Code Online (Sandbox Code Playgroud)