2013-02-11 28 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

相關問題