See*_*her 8 python django google-api oauth-2.0 oauth2client
我正在尝试通过验证Google令牌来访问Django应用程序中的用户日历.虽然我已经跟踪了网上发现的几个迹象,但我仍然遇到了对我的回调函数(错误请求)的400错误代码响应.
views.py
# -*- coding: utf-8 -*-
import os
import argparse
import httplib2
import logging
from apiclient.discovery import build
from oauth2client import tools
from oauth2client.django_orm import Storage
from oauth2client import xsrfutil
from oauth2client.client import flow_from_clientsecrets
from django.http import HttpResponse
from django.http import HttpResponseBadRequest
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.core.urlresolvers import reverse
from django.contrib import auth
from django.contrib.auth.decorators import login_required
from django.conf import settings
from apps.tecnico.models import Credentials, Flow
CLIENT_SECRETS = os.path.join(
os.path.dirname(__file__), '../../client_secrets.json')
@login_required
def index(request):
storage = Storage(Credentials, 'id', request.user, 'credential')
FLOW = flow_from_clientsecrets(
CLIENT_SECRETS,
scope='https://www.googleapis.com/auth/calendar.readonly',
redirect_uri='http://MY_URL:8000/oauth2/oauth2callback'
)
credential = storage.get()
if credential is None or credential.invalid is True:
FLOW.params['state'] = xsrfutil.generate_token(
settings.SECRET_KEY, request.user)
authorize_url = FLOW.step1_get_authorize_url()
f = Flow(id=request.user, flow=FLOW)
f.save()
return HttpResponseRedirect(authorize_url)
else:
http = httplib2.Http()
http = credential.authorize(http)
service = build(serviceName='calendar', version='v3', http=http,
developerKey='MY_DEV_KEY_FROM_GOOGLE_CONSOLE')
events = service.events().list(calendarId='primary').execute()
return render_to_response('calendario/welcome.html', {
'events': events['items'],
})
@login_required
def auth_return(request):
if not xsrfutil.validate_token(
settings.SECRET_KEY, request.REQUEST['state'], request.user):
return HttpResponseBadRequest()
storage = Storage(Credentials, 'id', request.user, 'credential')
FLOW = Flow.objects.get(id=request.user).flow
credential = FLOW.step2_exchange(request.REQUEST)
storage.put(credential)
return HttpResponseRedirect("http://MY_URL:8000/caly")
Run Code Online (Sandbox Code Playgroud)
models.py
from oauth2client.django_orm import FlowField, CredentialsField
[...]
class Credentials(models.Model):
id = models.ForeignKey(User, primary_key=True)
credential = CredentialsField()
class Flow(models.Model):
id = models.ForeignKey(User, primary_key=True)
flow = FlowField()
Run Code Online (Sandbox Code Playgroud)
我直接从Google Dev Console 下载了client_secrets.json文件.开发者控制台中指定的客户端ID类型是"Web应用程序",我认为这是正确的.我注意到的是,如果我删除令牌验证代码块:
if not xsrfutil.validate_token(
settings.SECRET_KEY, request.REQUEST['state'], request.user):
return HttpResponseBadRequest()
Run Code Online (Sandbox Code Playgroud)
一切正常,流和凭据得到正确存储在数据库中,我被允许阅读日历.我可能错在哪里?
编辑:我还检查了传出(谷歌)和传入(回调)数据:
外出:
request.user:
admin
settings.SECRET_KEY:
I_AM_NOT_WRITING_IT_HERE
FLOW.params['state']:
SOME_OTHER_RANDOM_STUFF
Run Code Online (Sandbox Code Playgroud)
收到:
request.user:
admin
settings.SECRET_KEY:
I_AM_NOT_WRITING_IT_HERE
FLOW.params['state']:
SOME_OTHER_RANDOM_STUFF
Run Code Online (Sandbox Code Playgroud)
数据是相同的,至少是打印到控制台.此外,通过控制台的生成/验证操作正常工作(xsrfutil.validate_token返回True,包括测试和实际数据,包括用户模型实例).我更加困惑.
wth*_*ain 14
几个小时我一直在努力解决同样的问题,我想出了@Ryan Spaulding和@Hans Z回答的解决方案.有用!
这是因为Django 1.7使用request.REQUEST为上面的状态变量返回一个unicode对象.我之前使用的Django 1.6用于返回一个字符串.
人们可以在这里找到更多细节.https://github.com/google/google-api-python-client/issues/58我写了这篇文章以供将来参考.
if not xsrfutil.validate_token(
settings.SECRET_KEY,
str(request.REQUEST['state']),
request.user):
return HttpResponseBadRequest()
Run Code Online (Sandbox Code Playgroud)