【问题标题】:'OAuth2Token' object has no attribute 'redirect_uri' and save access token with Appengine and gdata'OAuth2Token' 对象没有属性 'redirect_uri' 并使用 Appengine 和 gdata 保存访问令牌
【发布时间】:2012-05-17 00:57:29
【问题描述】:

我尝试了一个简单的带有 gdata、appengine 和 OAuth2 的 HelloWorld。我读过this postthe official post from Google

问题 1

根据first post 帖子,我的应用程序在第 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 APIs console 上填写了 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'>

**如何保存新的访问Token?**

main.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()

app.yaml:

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

handlers:

- url: .*
  script: main.py

【问题讨论】:

    标签: google-app-engine python-2.7 oauth-2.0 gdata


    【解决方案1】:

    调用AeLoad时,需要查看AeSave。您会注意到在 source code 中调用了 token_to_blob

    但是,在 token_to_blobsource 中,redirect_uri 不会保存到 blob,因此您需要保留它并调用:

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

    有关参考,请参阅另一个related post

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

    【讨论】:

    • 谢谢!但是现在,我无法保存新的访问令牌。见编辑。
    • 答案 2:我从 2.7 切换到 2.5,效果更好 :-) 谢谢。
    猜你喜欢
    • 2016-05-17
    • 2013-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-23
    • 2013-10-25
    • 2021-03-17
    • 1970-01-01
    相关资源
    最近更新 更多