首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有python gdata_api的OAuth2 : 400错误请求

带有python gdata_api的OAuth2 : 400错误请求
EN

Stack Overflow用户
提问于 2018-01-25 07:25:01
回答 1查看 451关注 0票数 0

不久前,我用python编写了一个使用Google的python gdata api的应用程序。我开始使用gdata_api示例,它工作得很好。在某种程度上,谷歌关闭了uid/pwd身份验证,并强制实施了OAuth2。因此,我修改了应用程序,使其可以与OAuth2一起运行。

它已经正常工作了几年,直到有一天它停止了,并在尝试请求访问令牌(明确地说,是来自https://www.googleapis.com/oauth2/v3/token的令牌)时开始返回错误400 (=错误请求)。这不是第一次发生(意味着在请求新的授权令牌并第一次使用它之后),而是在那之后的每一次。

我看到一些帖子说,他们修复了重定向uri,然后让它工作了,但他们没有写下要使用的内容。我也不知道这是否是正确的解决方案。我的OAuth2实现的精简版本如下所示(我重复一遍,它已经工作多年了):

代码语言:javascript
复制
import sys
import os

# WARNING!! you need also TLSLITE inside gdata/oauth subdir.
# This is how supported google shits are nowadays.
# See: https://github.com/google/gdata-python-client/issues/44

sys.path.append("~/gdatalib/gdata-python-client-master/src") #Quick and dirty way to get the latest version in. It doesnt make much of a difference anyway

import gdata
import gdata.contacts.data
import gdata.contacts.client
import urllib
import urllib2
import json
import subprocess

clientId = ""  # your app's client ID  , get one at https://console.developers.google.com/projectselector/apis/credentials?supportedpurview=project
clientSecret = "" # your app's client secret
oauthPath = ""
userAgent = "fuBar"

class OAuth2Auth(object):
    def __init__(self, sUserName, sAccountPassword):
        #gather all data
        self.username           = sUserName.split("@")[0] # remove @whatever, if any
        self.password           = sAccountPassword
        self.clientid           = clientId
        self.clientsecret       = clientSecret
        self.rediruri           = '''urn:ietf:wg:oauth:2.0:oob'''

        self.authrequesturl     = ("https://accounts.google.com/o/oauth2/auth?scope=https://www.google.com/m8/feeds/"
                                  "&redirect_uri=%s"
                                  "&response_type=code"
                                  "&client_id=%s"
                                  "&login_hint=%s") # % (redir_uri,client_id,sAccountName+"@gmail.com")
        self.oauth2_endpoint    = "https://www.googleapis.com/oauth2/v3/token"



        self.tokensPath         = os.path.join(oauthPath, self.username)
        #print self.tokensPathata should be a b
        self.accessToken        = None
        self.refreshToken       = None

        self._getTokens()
        #create an OAuth2Token
        print "Creating Oauth2Token...",
        self.oauth2token = gdata.gauth.OAuth2Token(client_id = self.clientid,
                                          client_secret = self.clientsecret,
                                          scope = 'https://www.google.com/m8/feeds/',
                                          user_agent = userAgent,
                                          access_token = self.accessToken,
                                          refresh_token = self.refreshToken)
        print " done."
        pass

    def __del__(self):
        #check that the access token in the OAuth2Token is the same as the read one.
        if (self.accessToken != self.oauth2token.access_token):
            #if not, update the file
            print "Access token has been updated by gdata_api. Updating the storage."
            self.accessToken = self.oauth2token.access_token
            self._storeTokens()
        pass

    def _storeTokens(self):
        if self.accessToken and self.refreshToken:
            f= open(self.tokensPath,'w+');
            f.seek(0);
            f.truncate();
            data = [ self.accessToken + '\n', self.refreshToken+'\n' ]
            f.writelines(data)
            f.close()

    def _readTokens(self):
        if not os.path.isfile(self.tokensPath):
            raise Exception('Expecting to find token file, but the file is not present!')

        f= open(self.tokensPath,'r')
        tokenlist = [ l.rstrip('\n') for l in f.readlines() ]
        f.close()

        if ( len(tokenlist) < 2 ):
            raise Exception('Not enough data in token file!')

        self.accessToken        = tokenlist[0]
        self.refreshToken       = tokenlist[1]


    def _getTokens(self):
        if not os.path.isfile(self.tokensPath):
            print "TokenPath doesn't exist. requesting new tokens"
            self._requestNewTokens()
            self._storeTokens()
        else:
            print "TokenPath exists"
        self._readTokens()


    def _requestNewTokens(self):
        #print '\nSTEP 1: Create OAuth2 request token URL.'
        request_url = self.authrequesturl % (self.rediruri,self.clientid,self.username+"@gmail.com")

        #print '\nSTEP 2: Spawn grob with adequate URL.'

        CHROME = os.path.join('C:\\', 'Program Files (x86)', 'Google', 'Chrome', 'Application', 'chrome.exe')
        CHROME = "/usr/bin/google-chrome" # for linux
        #CHROME = "" # or use whatever browser
        #subprocess.call([CHROME, '--incognito', request_url])   #use this the first time, after, you can also hardcode the token below
        request_token = """<your request token here to avoid storing and retrieving it>""" # You can hardcode the token here, if you got, and comment the line above spawning a chrome

        #print 'Request Token fetched: %s' % request_token
        #print '\nSTEP 3: Exchange auth token for access and refresh OAuth2 tokens.'


        request_args = { 'code':request_token, 
                         'client_id': self.clientid , 
                         'client_secret': self.clientsecret,
                         'redirect_uri':self.rediruri,
                         'grant_type':'authorization_code' }

        data = urllib.urlencode(request_args)
        fullUrl = self.oauth2_endpoint + "/" + data
        request = urllib2.Request(self.oauth2_endpoint, data)

        try:
            response = urllib2.urlopen(request)  # ===== FAILS HERE =====
            json_data = response.read()
            parsed_json = json.loads(json_data)
            self.accessToken = parsed_json['access_token']
            self.refreshToken =parsed_json['refresh_token']
            print parsed_json
        except Exception, e:
            print fullUrl
            print request.get_full_url()
            print request.get_selector()
            print e


def main():
    testuser="someuser@gmail.com"
    testpass="somepass"
    manager = OAuth2Auth(testuser,testpass)


if __name__ == '__main__':
    main()

根据https://developers.google.com/identity/protocols/OAuth2WebServer#offline的说法,应该在请求访问令牌时添加access_type = "offline“,以便也获得刷新令牌。然而,我试过了,它不起作用。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-01-27 01:28:26

事实证明,向请求授权码添加access_type=offline和include_granted_scopes=true并创建新的clientId/secret (但也可以切换回来)都有助于解决该问题。

我想在2012/2013年的时候这个参数还没有出现。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48433331

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档