2013-02-11 197 views
1

情景:

当授予访问权限时,我为每个应用用户在数据存储中保存令牌。gdata OAuth2如何使用多个用户的令牌

我需要创建多个的GData联系,以便授权客户 访问不同用户的接触中,我得到令牌的用户需要从 数据存储和创建授权接触客户,例如将一个用户的 联系人复制到其他用户的联系人。

问题:

授权客户按预期工作,并得到了 用户,其令牌使用的接触饲料,但令牌,令牌到期日也 保存,并在一个小时或45到期分钟,然后它不再工作, 我读到,如果刷新令牌存在于令牌对象中,则令牌 将自动获得新的访问令牌,如果短期访问令牌为 已过期但不会发生。

问:

我怎么能刷新令牌从数据存储得到它,如果它是 过期,所以我可以,只要用户没有 取消获得访问用户的联系人后?

CODE:

SCOPE = 'https://www.google.com/m8/feeds' 
REDIRECT_URI = 'http://localhost:8888/mainPage' 
USER_AGENT = 'shared-contacts' 

token = gdata.gauth.OAuth2Token(client_id=CLIENT_ID, 
           client_secret=CLIENT_SECRET, 
           scope=SCOPE, 
           user_agent=USER_AGENT) 

class MyEntity(db.Model): 
    userEmail = db.StringProperty() 
    access_token = ObjectProperty() 

class ObjectProperty(db.BlobProperty): 
    def validate(self, value): 
     try: 
      result = pickle.dumps(value) 
      return value 
     except pickle.PicklingError, e: 
      return super(ObjectProperty, self).validate(value) 

    def get_value_for_datastore(self, model_instance): 
     result = super(ObjectProperty, self).get_value_for_datastore(model_instance) 
     result = pickle.dumps(result) 
     return db.Blob(result) 

    def make_value_from_datastore(self, value): 
     try: 
      value = pickle.loads(str(value)) 
     except: 
      pass 
     return super(ObjectProperty, self).make_value_from_datastore(value) 

class MainHandler(webapp2.RequestHandler): 
    def get(self): 
     user = users.get_current_user() 
     if user: 
      self.redirect(token.generate_authorize_url(
                redirect_uri=REDIRECT_URI, 
                access_type='offline') 
               ) 
     else: 
      self.redirect(users.create_login_url("/")) 

class MainPage(webapp2.RequestHandler): 

    def get(self): 
     # Getting the token from datastore, if token exists for this user then 
     # proceed otherwise get the access token and save in datastore. 

     accessToken = Fetch_Access_Token() 

     if accessToken: 
      pass 
     else: 
      url = atom.http_core.Uri.parse_uri(self.request.uri) 
      code = url.query 
      code = code['code'] 

      if 'error' in code: 
       # User Did Not Grant The Access 
       pass 
      else: 
       token_user_email = users.get_current_user().email() 
       token.GetAccessToken(code) 
       entity = MyEntity(userEmail=token_user_email, access_token=token) 
       entity.put() 

     self.response.out.write(template.render('index.html',{})) 

class RPCMethods(): 
    def MoveContacts(self, *args): 

     # All tokens except current user 
     shared_group_users = shared_users(skip_current_user) 

     contact_client = gdata.contacts.client.ContactsClient(source=USER_AGENT) 

     for sg_user in shared_group_users.itervalues(): 

      shared_user_token = sg_user[1] 

      # PROBLEM OCCURS HERE, IT WORKS FOR ONLY 1 HOUR AND HERE I NEED 
      TO REFRESH THIS TOKEN. 

      # For almost an hour i get other user's Data, but after that i 
      get current user's Data. 

      shared_user_authorized_client = shared_user_token.authorize(contact_client) 
      shared_group_contact_feed = shared_user_authorized_client.GetContacts() 

application = webapp2.WSGIApplication([ 
             ('/', MainHandler), 
             ('/mainPage', MainPage), 
             ('/rpc', RPCHandler), 
             ], debug=True) 

UPDATE:

工作代码:

shared_user_credentials = StorageByKeyName(CredentialsModel, shared_user_credentials_key, 'credentials').get() 

    if shared_user_credentials.access_token_expired == True: 
     http = httplib2.Http() 
     http = shared_user_credentials.authorize(http) 
     shared_user_credentials.refresh(http) 
+0

如何将其存储在数据存储中?你在执行什么来获取'atom.http_core.Uri.parse_uri(self.request.uri)'? – bossylobster 2013-02-11 17:58:33

+0

@bossylobster 我使用gdata.gauth.OAuth2Token得到的令牌对象,我无法使用应用程序引擎中提供的方法将它保存在数据存储中 例如, ae_save或 datastore CredentialsProperty(),所以我搜索n找到了一个解决方案。 回答你的问题太长了评论,所以我编辑了 的问题,并添加了所有的代码,请看看,谢谢 – 2013-02-12 13:45:38

回答

2

所以的OAuth 2.0代码为 “完全没问题”,但你现在的样子获得随后你需要的令牌就是问题。

在另一个post,我提到了offline access部分OAuth2.0的文档状态:

当你的应用程序收到刷新令牌,重要的是要 商店刷新标记以供将来使用。如果您的应用程序丢失了刷新令牌,则必须在 获得另一个刷新令牌之前重新提示用户同意。如果需要重新提示用户同意 ,请在授权 代码请求中包含approval_prompt参数,并将该值设置为force

简单的解决方法:

所以,当你调用generate_authorize_url,发送approval_prompt='force'

self.redirect(token.generate_authorize_url(redirect_uri=REDIRECT_URI, 
              access_type='offline', 
              approval_prompt='force') 

你会发现,approval_prompt已经在signaturegenerate_authorize_url方法。

实际FIX:

当你存储您的令牌:

token_user_email = users.get_current_user().email() 
token.GetAccessToken(code) 
entity = MyEntity(userEmail=token_user_email, access_token=token) 

你知道你必须为当前用户的实体集。我建议你用

entity = MyEntity(id=token_user_email, access_token=token). 

而不是存储它时,你让你的用户完成OAuth 2.0流,

user = users.get_current_user() 
if user: 
    self.redirect(token.generate_authorize_url(
    ... 

你应该先检查是否已经有一个给定用户令牌:

token = MyEntity.get_by_id(user.email()) 
if token is not None: 
    # do something 

,你真的应该,真的真的,不要使用token作为全局对象!

老实说,有这么多的方法来解决这个错误,你可能会更好使用从google-api-python-clientOAuth2Decorator

有关如何将此装饰器与gdata-python-client结合使用的一些参考,请查看我在其他问题上发布的​​。

离别注:

您应该使用ndbdatastore library。不必编写可怕的ObjectProperty,您可以简单地使用ndb.PickleProperty,而无需付出任何努力。

+0

非常感谢,点击'有用的答案',但没有足够的声誉我说: S 我现在正在尝试使用您的文章“在GData和Discovery之间桥接OAuth 2.0对象”的装饰器的oauth流。 从bd切换到ndb以及n现在我甚至不需要保存令牌,因为“OAuth2TokenFromCredentials”将有一个。 希望这个时候令牌得到刷新,因为我不能提示用户使用“approval_prompt”授予每次刷新的访问权限,因为生病需要创建多个联系人客户端与他们的联系人一起工作 – 2013-02-13 10:56:31

+0

now ill保存凭证对象使用, storage = StorageByKeyName (CredentialsModel,user.user_id(),'credentials'), storage.put(decorator.credentials) – 2013-02-13 11:00:12

+0

从数据存储获得它后,使用装饰器的对象“Credentials”,现在我可以刷新它,如果访问令牌已过期。 接下来的问题是当刷新令牌过期时,我已经读了它的有效期为14天。 更新包括新代码在内的问题,非常感谢您的帮助以及最好和最有用的文章之一,桥接发现n gdata。当我再次遇到麻烦时, 会再次打扰你:) – 2013-02-14 14:50:41

相关问题