繁体   English   中英

访问令牌过期时Gmail API错误(Python,Django):HttpAccessTokenRefreshError invalid_client:未找到OAuth客户端

[英]Gmail API error when access token expires (Python, Django): HttpAccessTokenRefreshError invalid_client: The OAuth client was not found

我正在建立Django专案。 我需要通过Gmail的API发送电子邮件,因此我创建了一个项目,获得了API密钥,oauth凭据等。

我设法完成了“授权”部分,即用户登录所在的位置,授予您阅读+发送电子邮件的权限(据我所知,access_type = offline),并且您获得了access_token。 我将用户的“ access_token”,“ expires_in”和“ refresh_token”字段保存在数据库中。

然后,我可以阅读用户电子邮件的标签,以他的名字发送电子邮件,等等。没问题。

一旦access_token过期(因此,在用户授予权限的一个小时之后),就会出现问题。

尝试发送电子邮件时,我得到的错误是:

/ test_gmail_api3 /上的HttpAccessTokenRefreshError

invalid_client:找不到OAuth客户端。

我浏览了很多相关的stackoverflow问题,并尝试更改了许多不同的东西,但是没有任何效果。 唯一有效的方法是从我的测试gmail帐户手动撤消访问权限,再次授予访问权限,然后它可以正常运行...直到access_token再次到期。

这是错误:

HttpAccessTokenRefreshError的屏幕截图

这些是代码(t)的相关部分:

这是代码的相关部分:

用于向用户征求同意/许可的视图(效果很好,使用以下代码重定向到test_gmail_api2:

def test_gmail_api(request):
flow = OAuth2WebServerFlow(client_id='<< edited to keep secret >>.apps.googleusercontent.com',
                       client_secret='<< edited to keep secret >>MpNLDa',
                       scope=('https://www.googleapis.com/auth/gmail.readonly ' + 'https://www.googleapis.com/auth/gmail.send'),
                       redirect_uri='http://localhost:8000/test_gmail_api2/')
auth_uri = flow.step1_get_authorize_url()
return redirect(auth_uri)

用于使用Google代码获取access_token和refresh_token的视图(效果很好,我获取了令牌并将其另存为字符串):

def test_gmail_api2(request):
flow = OAuth2WebServerFlow(client_id='<< edited to keep secret >>.apps.googleusercontent.com',
                       client_secret='<< edited to keep secret >>MpNLDa',
                       scope=('https://www.googleapis.com/auth/gmail.readonly ' + 'https://www.googleapis.com/auth/gmail.send'),
                       redirect_uri='http://localhost:8000/test_gmail_api2/')
credentials = flow.step2_exchange(request.GET.get('code', ''))
current_profile = Profile.objects.get(email_address='none@test.com')
current_profile.access_token = credentials.get_access_token(http=None).access_token
current_profile.access_token_expiration = credentials.get_access_token(http=None).expires_in

string_credentials = credentials.to_json()
json_credentials = json.loads(string_credentials)

current_profile.refresh_token = json_credentials['refresh_token']
current_profile.save()

service = build('gmail', 'v1', http=credentials.authorize(Http()))

# Call the Gmail API
test_response = ""
results = service.users().labels().list(userId='me').execute()
labels = results.get('labels', [])
if not labels:
    test_response += 'No labels found.'
else:
    test_response += 'Labels:'
    for label in labels:
        test_response += label['name'] + "<br>"

response = service.users().messages().list(userId='me',
                                           q='has:attachment').execute()
messages = []
if 'messages' in response:
  messages.extend(response['messages'])
test_response += string_credentials
return HttpResponse(test_response)

最后,该视图将读取所有标签并发送电子邮件:

def test_gmail_api3(request):
client_id='<< edited to keep secret >>.apps.googleusercontent.com',
client_secret='<< edited to keep secret >>MpNLDa'
current_profile = Profile.objects.get(email_address='none@test.com')
refresh_token = current_profile.refresh_token
access_token = current_profile.access_token
expires_at = current_profile.access_token_expiration
some_user_agent = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.517 Safari/537.36'
cred = oauth2client.client.GoogleCredentials(access_token,client_id,client_secret,
                                      refresh_token,expires_at,"https://accounts.google.com/o/oauth2/token",some_user_agent) # tried access_token=None and token_expiry=None but it doesn't work
http = cred.authorize(httplib2.Http())
service = build('gmail', 'v1', http=cred.authorize(Http()))

# Call the Gmail API
test_response = ""

string_credentials = cred.to_json()
json_credentials = json.loads(string_credentials)
test_response += string_credentials + '<br>'

results = service.users().labels().list(userId='me').execute()
labels = results.get('labels', [])
if not labels:
    test_response += 'No labels found.'
else:
    test_response += 'Labels:'
    for label in labels:
        test_response += label['name'] + "<br>"

response = service.users().messages().list(userId='me',
                                           q='has:attachment').execute()
messages = []
if 'messages' in response:
  messages.extend(response['messages'])
test_response += cred.to_json() + '<br>'

user_id='me'
threads = service.users().threads().list(userId=user_id).execute().get('threads', [])
for thread in threads:
    tdata = service.users().threads().get(userId=user_id, id=thread['id']).execute()
    nmsgs = len(tdata['messages'])

    if nmsgs > 2:    # skip if <3 msgs in thread
        msg = tdata['messages'][0]['payload']
        subject = ''
        for header in msg['headers']:
            if header['name'] == 'Subject':
                subject = header['value']
                break
        if subject:  # skip if no Subject line
            test_response += subject + ' has num of mssgs: ' + str(nmsgs) + '<br>'

message = MIMEText('blah blah blah')
message['to'] = 'my_personal_email@gmail.com'
message['from'] = 'me'
message['subject'] = 'it seems to be working'
final_mssg =  {'raw': base64.urlsafe_b64encode(message.as_string().encode()).decode()}
try:
    message = (service.users().messages().send(userId='me', body=final_mssg).execute())
    test_response += 'WE JUST SENT A MESSAGE WITH ID ' + message['id']
except Exception as e:
    test_response += "we couldn't send the message. Error: " + str(e)
return HttpResponse(test_response)

我不知道出什么问题了。 我尝试更改代码中的许多内容,但无法摆脱此错误。 我已经为此奋斗了2天了,我快要疯了。 有人可以帮我吗?

谢谢!

PS:这是正确保存令牌的数据库条目:

带有令牌字符串的Django数据库条目

天哪,我才找到解决方案。

我再次浏览了错误日志,发现变量“ client_id”是列表而不是字符串:

错误日志中的本地变量

回到代码中,看到不应该有一个多余的逗号(因此,将“ client_id”作为列表而不是应有的字符串):

代码中的多余逗号引起错误

这就是引发错误的原因。 我猜它只是在需要刷新令牌时才触发它。

删除了逗号,现在可以正常使用了。 傻我 🤦

抱歉,这个问题对我来说非常具体,我想它永远也不会帮助任何人。

我知道代码需要大量重做和整理(例如,我做cred.authorize()2次!),这只是出于测试目的,我被困在其中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM