0

我尝试了一个简单的带有 gdata、appengine 和 OAuth2 的 HelloWorld。我读了这篇文章谷歌的官方帖子

问题 1

根据第一篇文章,我的应用程序在第 7 部分“使用代码获取访问令牌”失败:

Traceback (most recent call last):
  File "[$PATH]/dev/outils/google_appengine/google/appengine/ext/webapp/_webapp25.py", line 701, in __call__
    handler.get(*groups)
  File "[$PATH]/dev/outils/google_appengine/google/appengine/ext/webapp/util.py", line 68, in check_login
    handler_method(self, *args)
  File "[$PATH]/dev/projets/xxx/main.py", line 76, in get
    token.get_access_token(url.query)
  File "[$PATH]/dev/projets/xxx/gdata/gauth.py", line 1296, in get_access_token
    'redirect_uri': self.redirect_uri,
AttributeError: 'OAuth2Token' object has no attribute 'redirect_uri'

我在方法 generate_authorize_url() 中提供了 redirect_uri,并在Google API 控制台上填写了 2 个“重定向 URI” :

为什么redirect_uri 是松散的?

解决方案:参见@bossylobster 答案。


问题 2 现在,我想像这样保存这个新的访问令牌:

access_token_key = 'access_token_%s' % current_user.user_id()
gdata.gauth.ae_save(token, access_token_key)

这些行抛出此异常:

Traceback (most recent call last):
  File "[$PATH]/dev/outils/google_appengine/google/appengine/ext/webapp/_webapp25.py", line 701, in __call__
    handler.get(*groups)
  File "[$PATH]/dev/outils/google_appengine/google/appengine/ext/webapp/util.py", line 68, in check_login
    handler_method(self, *args)
  File "[$PATH]/dev/projets/xxx/main.py", line 89, in get
    gdata.gauth.ae_save(token, access_token_key)
  File "[$PATH]/dev/projets/xxx/gdata/gauth.py", line 1593, in ae_save
    return gdata.alt.app_engine.set_token(key_name, token_to_blob(token))
  File "[$PATH]/dev/projets/xxx/gdata/alt/app_engine.py", line 92, in set_token
    if Token(key_name=unique_key, t=token_str).put():
  File "[$PATH]/dev/outils/google_appengine/google/appengine/ext/db/__init__.py", line 973, in __init__
    prop.__set__(self, value)
  File "[$PATH]/dev/outils/google_appengine/google/appengine/ext/db/__init__.py", line 613, in __set__
    value = self.validate(value)
  File "[$PATH]/dev/outils/google_appengine/google/appengine/ext/db/__init__.py", line 2779, in validate
    (self.name, self.data_type.__name__, err))
BadValueError: Property t must be convertible to a Blob instance (Blob() argument should be str instance, not unicode) 

但是gdata.gauth.access_token调用gdata.gauth.upgrade_to_access_token会返回带有一些修改的令牌。

如果我尝试token_to_blob,我有这个例外UnsupportedTokenType: Unable to serialize token of type <type 'unicode'>

** 如何保存新的 access Token ?**

主.py:

from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app, login_required
from google.appengine.api import users

import gdata.gauth
import atom.http_core


SETTINGS = {
    'APP_NAME': 'xxx',
    'CLIENT_ID':'xxx.apps.googleusercontent.com',
    'CLIENT_SECRET':'xxx',
    'SCOPES': ['https://www.google.com/m8/feeds/', 'https://docs.google.com/feeds/', 'https://www.google.com/calendar/feeds/'],
    'USER_AGENT' : 'xxxs',
    'OAUTH2CALLBACK':'http://localhost:8080/oauth2callback'
    #'OAUTH2CALLBACK':'http://example.com/oauth2callback'
    }

class Home(webapp.RequestHandler):

    def get(self):
        """Home"""
        if users.get_current_user():
            self.redirect("/step1")
        else:
            self.response.out.write("<a href='/step1'>Sign in google</a><br />")

class Fetcher(webapp.RequestHandler):

    @login_required
    def get(self):
        """This handler is responsible for fetching an initial OAuth
        request token and redirecting the user to the approval page."""

        current_user = users.get_current_user()

        #create token
        token = gdata.gauth.OAuth2Token(client_id = SETTINGS['CLIENT_ID'],
                                        client_secret = SETTINGS['CLIENT_SECRET'],
                                        scope = ' '.join(SETTINGS['SCOPES']),
                                        user_agent = SETTINGS['USER_AGENT'])



        url = token.generate_authorize_url(redirect_uri = SETTINGS['OAUTH2CALLBACK'])
        #save token to datastore
        gdata.gauth.ae_save(token, current_user.user_id())

        message = """<a href="%s">
        Request token for the Google Documents Scope</a>"""

        self.response.out.write(message % url)
        self.response.out.write(" ; redirect uri : %s" % token.redirect_uri)

class RequestTokenCallback(webapp.RequestHandler):


    @login_required
    def get(self):
        """When the user grants access, they are redirected back to this
        handler where their authorized request token is exchanged for a
        long-lived access token."""

        current_user = users.get_current_user()

        #get token from callback uri
        url = atom.http_core.Uri.parse_uri(self.request.uri)

        # get token from datastore
        token = gdata.gauth.ae_load(current_user.user_id())
        # SOLUTION 1
        token.redirect_uri = SETTINGS['OAUTH2CALLBACK']

        if isinstance(token, gdata.gauth.OAuth2Token):
            if 'error' in url.query:
                pass
            else:
                token.get_access_token(url.query)

         gdata.gauth.ae_save(gdata.gauth.token_to_blob(token), "access_token_" + current_user.user_id())

def main():
    application = webapp.WSGIApplication([('/', Home),
                                          ('/step1', Fetcher),
                                          ('/oauth2callback', RequestTokenCallback)],
                                         debug = True)
    run_wsgi_app(application)

if __name__ == '__main__':
    main()

应用程序.yaml:

application: xxx
version: 2
runtime: python
api_version: 1

handlers:

- url: .*
  script: main.py
4

1 回答 1

0

当你打电话时AeLoad,你需要看看AeSave。您会在调用的源代码中注意到。token_to_blob

但是,在 for 的源代码token_to_blobredirect_uri没有保存到 blob,因此您需要保留它并调用:

token = gdata.gauth.ae_load(current_user.user_id())
token.redirect_uri = SETTINGS['OAUTH2CALLBACK']

如需参考,请参阅另一篇相关帖子

对问题 2 的回答:阅读回溯:Blob()参数应该是str实例,而不是unicode。您在本地使用的是哪个版本Python

于 2012-05-08T18:19:36.490 回答