如何在GAE任务队列中执行OAuth需求操作? [英] How to do OAuth-requiring operations in a GAE Task Queue?

查看:127
本文介绍了如何在GAE任务队列中执行OAuth需求操作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的Google App Engine应用,其中包含一个更新YouTube播放列表的 / update 页面。它看起来像这样:

 类UpdatePage(webapp2.RequestHandler):

@ decorator.oauth_required
def get(self):
update_result = self.update_playlist()
...

routes = [('/ update',UpdatePage),
(decorator.callback_path,decorator.callback_handler())]
app = webapp2.WSGIApplication(routes,debug = True)

它按预期工作,并且 update_playlist()方法完成它的工作,但事实证明在某些情况下它可以运行很长时间时间,导致 DeadlineExceededError 。所以在阅读了可用的选项后,我想到了 Task Queue API是要走的路(正确?),我试图使用它,遵循在Python中使用推送队列指南。



→总之,我将 UpdatePage 分成 UpdatePageHandler + UpdatePageWorker

 类UpdateHandlerPage(webapp2.RequestHandler):

@ decorator.oauth_required
def get (self):
taskqueue.add(url ='/ updateworker')

类UpdateWorkerPage(webapp2.RequestHandler):

def post(self):
update_result = self.update_playlist()
...

routes = [('/ update',UpdateHandlerPage),
('/ updateworker',UpdateWorkerPage),
(decorator.callback_path,decorator.callback_handler())]
app = webapp2.WSGIApplication(routes,debug = True)

不幸的是,在完成拆分之后,似乎我的OAuth2装饰器不再执行其任务:

  INFO 2013-05-30 17:08:53,971 discovery.py:709]请求的网址:https://www.googleapis.com/youtube/v3/playlists?alt=json&part=snippet% 2Cstatus 
警告2013-05-30 17:08:53,975 urlfetch_stub.py:480]从URLFetch请求中剥离禁止标头:['content-length']
INFO 2013-05-30 17:08: 54,351 client.py:493]刷新401
INFO 2013-05-30 17:08:54,361 appengine.py:276] make:Got type< class'google.appengine.api.datastore_types.Blob >
INFO 2013-05-30 17:08:54,363 appengine.py:289] validate:Got type< class'oauth2client.client.OAuth2Credentials'>
INFO 2013-05-30 17:08:54,364 client.py:680]刷新access_token
INFO 2013-05-30 17:08:54,746 client.py:699]无法检索访问令牌: {
error:invalid_grant
}
INFO 2013-05-30 17:08:54,757 appengine.py:276] make:Got type< class'google.appengine。 api.datastore_types.Blob'>
INFO 2013-05-30 17:08:54,759 appengine.py:289] validate:Got type< class'oauth2client.client.OAuth2Credentials'>
INFO 2013-05-30 17:08:54,761 appengine.py:289] validate:Got type< class'oauth2client.client.OAuth2Credentials'>
INFO 2013-05-30 17:08:54,762 appengine.py:265] get:Got type< class'oauth2client.appengine.CredentialsModel'>

如果不是装饰 UpdateHandlerPage:get 我装饰了 UpdateWorkerPage:post ,我得到了一个无限的失败循环:

  INFO 2013-05-30 17:24:31,307 discovery.py:190]请求的网址:https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest?userIp = 127.0.0.1 
INFO 2013-05-30 17:24:34,960 dev_appserver.py:3105]GET / update HTTP / 1.1200 -
INFO 2013-05-30 17:24:35,060 dev_appserver.py:3105 ]POST / updateworker HTTP / 1.1302 -
警告2013-05-30 17:24:35,065 taskqueue_stub.py:1980]任务task1执行失败。此任务将在0.100秒后重试
INFO 2013-05-30 17:24:35,240 dev_appserver.py:3105]POST / updateworker HTTP / 1.1302 -
警告2013-05-30 17: 24:35,245 taskqueue_stub.py:1980]任务task1未能执行。此任务将在0.200秒内重试
...

我该怎么办?感谢您的帮助!

解决方案

由于任务队列任务将由您的应用程序产生,因此原始请求将通过发送。特别是,通过 SACSID cookie为您的应用程序标识用户的 Cookies 标题(由App Engine Users API )。

更新:(这是在原文后添加的。)由于没有cookie,标识用户的SACSID cookie不会在那里,因此 decorator.oauth_required 指定将强制重定向(即HTTP 302 EVERY 运行cron作业。



不是试图从装饰器中获取当前用户,您最好将App Engine用户ID传递给您的任务。首先获取当前用户(在您装饰的方法中):

  from google.appengine.api导入用户
#保证不要被装饰者设为无
current_user = users.get_current_user()

然后通过沿着任务中的App Engine用户标识

  import urllib 
query_string = urllib.urlencode({'user_id': current_user.user_id()})
taskqueue.add(url ='/ updateworker?'+ query_string)

然后在你的任务中,你可以检索那个 user_id

 #这是在查询字符串
中添加的'user_id'user_id = self.request.get('user_id')

并使用它获取该用户的凭据就像在装饰器中完成

  from oauth2client.appengine import CredentialsModel $ b $ from oauth2client.appengine import StorageByKeyName 
#您正在使用OAuth2Decorator的默认值
#您的上面的代码是
credentials = StorageByKeyName(
CredentialsModel,user_id,'credentials').get()


I have a simple Google App Engine app that includes a /update page which updates a YouTube playlist. It looks like this:

class UpdatePage(webapp2.RequestHandler):

    @decorator.oauth_required
    def get(self):
        update_result = self.update_playlist()
        ...

routes = [('/update', UpdatePage),
          (decorator.callback_path, decorator.callback_handler())]
app = webapp2.WSGIApplication(routes, debug=True)

It works as expected and the update_playlist() method does its job, but it turns out that under some circumstances it can run for a pretty long time, resulting in a DeadlineExceededError. So after reading about the available options, I figured the Task Queue API is the way to go (right?) and I'm trying to use it, following the Using Push Queues in Python guide.

→ In short, I split UpdatePage into UpdatePageHandler + UpdatePageWorker:

class UpdateHandlerPage(webapp2.RequestHandler):

    @decorator.oauth_required
    def get(self):
        taskqueue.add(url='/updateworker')

class UpdateWorkerPage(webapp2.RequestHandler):

    def post(self):
        update_result = self.update_playlist()
        ...

routes = [('/update', UpdateHandlerPage),
          ('/updateworker', UpdateWorkerPage),
          (decorator.callback_path, decorator.callback_handler())]
app = webapp2.WSGIApplication(routes, debug=True)

Unfortunately, after doing the split it seems my OAuth2 decorator no longer does its job:

INFO     2013-05-30 17:08:53,971 discovery.py:709] URL being requested: https://www.googleapis.com/youtube/v3/playlists?alt=json&part=snippet%2Cstatus
WARNING  2013-05-30 17:08:53,975 urlfetch_stub.py:480] Stripped prohibited headers from URLFetch request: ['content-length']
INFO     2013-05-30 17:08:54,351 client.py:493] Refreshing due to a 401
INFO     2013-05-30 17:08:54,361 appengine.py:276] make: Got type <class 'google.appengine.api.datastore_types.Blob'>
INFO     2013-05-30 17:08:54,363 appengine.py:289] validate: Got type <class 'oauth2client.client.OAuth2Credentials'>
INFO     2013-05-30 17:08:54,364 client.py:680] Refreshing access_token
INFO     2013-05-30 17:08:54,746 client.py:699] Failed to retrieve access token: {
  "error" : "invalid_grant"
}
INFO     2013-05-30 17:08:54,757 appengine.py:276] make: Got type <class 'google.appengine.api.datastore_types.Blob'>
INFO     2013-05-30 17:08:54,759 appengine.py:289] validate: Got type <class 'oauth2client.client.OAuth2Credentials'>
INFO     2013-05-30 17:08:54,761 appengine.py:289] validate: Got type <class 'oauth2client.client.OAuth2Credentials'>
INFO     2013-05-30 17:08:54,762 appengine.py:265] get: Got type <class 'oauth2client.appengine.CredentialsModel'>

And if instead of decorating UpdateHandlerPage:get I decorate UpdateWorkerPage:post, I get an infinite failure loop instead:

INFO     2013-05-30 17:24:31,307 discovery.py:190] URL being requested: https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest?userIp=127.0.0.1
INFO     2013-05-30 17:24:34,960 dev_appserver.py:3105] "GET /update HTTP/1.1" 200 -
INFO     2013-05-30 17:24:35,060 dev_appserver.py:3105] "POST /updateworker HTTP/1.1" 302 -
WARNING  2013-05-30 17:24:35,065 taskqueue_stub.py:1980] Task task1 failed to execute. This task will retry in 0.100 seconds
INFO     2013-05-30 17:24:35,240 dev_appserver.py:3105] "POST /updateworker HTTP/1.1" 302 -
WARNING  2013-05-30 17:24:35,245 taskqueue_stub.py:1980] Task task1 failed to execute. This task will retry in 0.200 seconds
...

What can I do? Thanks for your help!

解决方案

Since the Task Queue task will be spawned by your application, none of the headers from your original request will be sent through. In particular, the Cookies header identifying your user via the SACSID cookie for your application (provided by the App Engine Users API).

UPDATE: (This was added after the original post.) As a result of no cookies, the SACSID cookie identifying the user won't be there, hence the decorator.oauth_required designation will force a redirect (which is HTTP 302) EVERY time the cron job runs.

Instead of trying to get the current user from the decorator, you are better off passing along the App Engine User ID to your task. First get the current user (within your decorated method):

from google.appengine.api import users
# Guaranteed not to be None by the decorator
current_user = users.get_current_user()

and then pass along the App Engine User ID in the task

import urllib
query_string = urllib.urlencode({'user_id': current_user.user_id()})
taskqueue.add(url='/updateworker?' + query_string)

Then within your task, you can retrieve grab that user_id

# This is the 'user_id' you appended in the query string
user_id = self.request.get('user_id')

and use it to get that user's credentials as is done in the decorator:

from oauth2client.appengine import CredentialsModel
from oauth2client.appengine import StorageByKeyName
# This assumes you are using the defaults for OAuth2Decorator,
# which your above code is
credentials = StorageByKeyName(
    CredentialsModel, user_id, 'credentials').get()

这篇关于如何在GAE任务队列中执行OAuth需求操作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆