代码之家  ›  专栏  ›  技术社区  ›  endryha

Android:使用OAuth访问google任务的问题

  •  3
  • endryha  · 技术社区  · 15 年前

    由于google tasks没有公共api,我想编写解决方案,像浏览器一样请求数据,然后解析结果以进一步显示。

    为了访问数据,我使用google实现了OAuth身份验证来访问此url: 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();
            }
        }
    
    }
    

    第一阶段

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

    第二个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;
        }
    }
    

    在这一行:

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

    我可以看到我收到“登录页”

    我认为原因是google不提供对这个服务的访问,甚至我已经用OAuth进行了身份验证,它限制了我对这个资源的访问(甚至我定义了 https://mail.google.com/ ). 我现在不知道如何实现它,但看起来我需要模拟浏览器与google的交互方式(检索并发送适当的coockies)。但是我在问,因为我不确定如何处理这种情况,因为正如我所提到的,googletaskapi没有公共API(soap、rest或任何其他API),所以对于我来说,如何实现这个特性的客户端并不明显。。。

    如果有人有应用程序访问谷歌资源没有公共API的例子,我将非常高兴看到。

    谢谢,希望有人知道答案!

    2 回复  |  直到 15 年前
        1
  •  5
  •   ryan    15 年前

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

    现在有一个 Google Tasks API ! 相反,使用它会容易得多,代码也会更易于维护。剩下的答案只为后人考虑。

    不幸的是,你走上了正确的轨道。现在还没有google任务的API,OAuth或者其他的,所以您需要做一些HTML抓取。:afaik,这是客户机现在执行的所有其他第三方任务。不过,ClientLogin确实适用于auth,所以至少是这样。

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

    第一, POST 到 www.google.com/accounts/ClientLogin 如中所述 http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html#Request 以获取身份验证令牌。使用 goanna_mobile 作为服务名称。(这很重要!)

    那么, GET https://mail.google.com/tasks/m 并通过 Authorization:GoogleLogin 上面收到的带有身份验证令牌的头。你会得到HTML的。提取单个任务列表的ID。表格是04291568652951293844:0:0。

    然后用JSON编码的正文将帖子发送到 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
      }
    

    重要提示:

    • 最新同步点:0以获取所有任务
    • r=中的=是 不 url编码为r%3D
    • 包括标题“AT:1”。如果没有it任务,则返回401个未经授权的任务。

    输出更多的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
       },
       ...
    
        2
  •  1
  •   Awais Qarni Leonardo Conde    15 年前

    从几周前开始他们就有了API here