Python Django 谷歌认证和从头开始获取邮件
谷歌认证和从头开始获取邮件意味着不使用任何已经设置了这种认证过程的模块。我们将使用Google API python客户端和Oauth2client,这是Google提供的。有时候,用这些库实现谷歌认证真的很难,因为没有合适的文档可用。但在完成这个阅读后,事情就会完全清楚了。
现在让我们创建Django 2.0项目,然后实现Google认证服务,然后提取邮件。我们做提取邮件只是为了展示如何在认证后要求许可。
第1步:创建Django项目
第一步是创建虚拟环境,然后安装依赖项。所以我们将使用venv :
mkdir google-login && cd google-login
python3.5 -m venv myvenv
source myvenv/bin/activate
这个命令将创建一个文件夹myvenv,通过它我们刚刚激活了虚拟环境。现在输入
pip freeze
然后你必须看到里面没有安装任何依赖项。现在,首先让我们来安装Django。
pip install Django==2.0.7
这是我们使用的Django版本,但也可以随意使用其他版本。现在,下一步是创建一个项目,让我们把它命名为gfglogin。
django-admin startproject gfglogin .
由于我们是在google-login目录下,所以我们希望django项目只在这个目录下,所以你需要用’ .’来表示当前目录。然后创建一个应用程序,将逻辑与主项目分开,所以创建一个名为gfgauth的应用程序。
django-admin startapp gfgauth
因此,整体的终端将看起来像。
由于我们创建了一个应用程序。在settings.py的INSTALLED_APP列表中添加该应用的名字。现在我们的Django项目已经开始运行了,所以让我们先迁移它,然后检查是否有任何错误。
python manage.py makemigrations
python manage.py migrate
python manage.py runserver
因此,在迁移之后,人们应该能够运行服务器,并在那个特定的网址上看到Django的起始页面。
第2步:安装依赖性
既然我们已经成功运行了项目,让我们来安装基本需求。首先,我们需要googleapiclient,这是因为我们必须创建一个资源对象,以帮助与API进行交互。所以准确地说,我们将使用它的build
方法。
安装:
pip install google-api-python-client==1.6.4
现在,第二个模块是oauth2client,这将确保所有的认证,证书,流量和更多的复杂的事情,所以使用它是很重要的。
pip install oauth2client==4.1.2
最后,安装jsonpickle,(以防万一,如果它没有安装),因为它将被oauth2client在制作CredentalsField时使用。
pip install jsonpickle==0.9.6
所以这些是我们唯一需要的依赖。现在让我们进入编码部分,看看它是如何工作的。
步骤#3:创建模型
使用模型来存储我们从API获得的证书,所以只有两个主要字段需要处理。首先是id,它将是外键,其次是credential,它将等同于CredentialsField。这个字段需要从oauth2client导入。所以我们的models.py将看起来像。
from django.contrib import admin
from django.contrib.auth.models import User
from django.db import models
from oauth2client.contrib.django_util.models import CredentialsField
class CredentialsModel(models.Model):
id = models.ForeignKey(User, primary_key = True, on_delete = models.CASCADE)
credential = CredentialsField()
task = models.CharField(max_length = 80, null = True)
updated_time = models.CharField(max_length = 80, null = True)
class CredentialsAdmin(admin.ModelAdmin):
pass,
目前任务和更新时间只是添加了额外的字段,因此可以被删除。所以这个凭证将在数据库中保存凭证数据。
Important guideline:
当我们导入CredentialsField时,自动在后面执行init方法,如果你注意到路径中的代码
/google-login/myvenv/lib/python3.5/site-packages/oauth2client/contrib/django_util/__init__.py
行 233
他们正在导入urlresolvers,这样他们就可以利用它的反向方法了。现在的问题是,这个urlresolvers在Django 1.10或Django 1.11之后被删除了,如果你在Django 2.0上工作,那么它将给出一个错误,urlresolvers找不到或者不存在。
现在为了解决这个问题,我们需要修改两行,首先把从django.core导入urlresolvers改为从django.urls导入reverse。
然后将411行urlresolvers.reverse(…)改为reverse(…)
现在你应该能够成功运行它。
创建这些模型后。
python manage.py makemigrations
python manage.py migrate
第4步:创建视图
现在,我们只有3个主要的视图来处理请求。第一个是显示主页、状态、谷歌按钮,这样我们就可以发送认证请求。第二个视图将在谷歌按钮被点击时被触发,意味着一个AJAX请求。第三是处理来自google的返回请求,这样我们就可以接受它的access_token并将其保存在我们的数据库中。
首先,让我们做一下谷歌认证的事情。
因此,现在我们需要指定到API的流程,即我们需要询问哪些权限,什么是我的秘密密钥和重定向网址。所以要做到这一点,请输入。
FLOW = flow_from_clientsecrets(
settings.GOOGLE_OAUTH2_CLIENT_SECRETS_JSON,
scope='https://www.googleapis.com/auth/gmail.readonly',
redirect_uri='http://127.0.0.1:8000/oauth2callback',
prompt='consent')
你可以注意到settings.GOOGLE_OAUTH2_CLIENT_SECRETS_JSON ,所以到settings.py文件中输入。
GOOGLE_OAUTH2_CLIENT_SECRETS_JSON = 'client_secrets.json'
这告诉Django哪里有json文件。我们稍后将下载这个文件。在指定了流程之后,让我们开始逻辑。
每当我们需要查看某人是否被授权时,我们首先检查我们的数据库是否已经存在该用户的凭证。如果没有,我们就向API网址发出请求,然后获得证书。
def gmail_authenticate(request):
storage = DjangoORMStorage(CredentialsModel, 'id', request.user, 'credential')
credential = storage.get()
if credential is None or credential.invalid:
FLOW.params['state'] = xsrfutil.generate_token(settings.SECRET_KEY,
request.user)
authorize_url = FLOW.step1_get_authorize_url()
return HttpResponseRedirect(authorize_url)
else:
http = httplib2.Http()
http = credential.authorize(http)
service = build('gmail', 'v1', http = http)
print('access_token = ', credential.access_token)
status = True
return render(request, 'index.html', {'status': status})
我们使用DjangoORMStorage(由oauth2client提供),这样我们就可以从Django数据存储中存储和检索凭证。所以我们需要为它传递4个参数。首先是模型类,里面有CredientialsField。第二是有证书的唯一ID,即键名,第三是有证书的键值,最后是我们在models.py中指定的CredentialsField的名字。
然后我们从存储器中获取值,看看它是否有效。如果它是无效的,那么我们创建一个用户令牌,并获得一个授权的网址,在那里我们将用户重定向到谷歌的登录页面。在重定向后,用户将填写表格,一旦用户被谷歌授权,谷歌将发送数据到回调网址,并附上访问令牌,我们将在后面做。现在,如果用户凭证已经存在,那么它将重新验证凭证,并给你的访问令牌,或者有时刷新的访问令牌,如果以前的访问令牌已经过期。
现在我们需要处理回调的网址,以做到这一点。
def auth_return(request):
get_state = bytes(request.GET.get('state'), 'utf8')
if not xsrfutil.validate_token(settings.SECRET_KEY, get_state,
request.user):
return HttpResponseBadRequest()
credential = FLOW.step2_exchange(request.GET.get('code'))
storage = DjangoORMStorage(CredentialsModel, 'id', request.user, 'credential')
storage.put(credential)
print("access_token: % s" % credential.access_token)
return HttpResponseRedirect("/")
现在,在回调网址中,当我们从google得到一个响应时,我们捕捉数据并从中得到状态,状态只不过是我们通过generateToken生成的令牌。所以我们要做的是,用secret_key、我们生成的token和生成token的用户来验证token。这些东西通过xsrfutil.validate_token方法进行验证,确保令牌的时间不会太长,而且是在特定的时间内生成的。如果这些事情不能很好地解决,那么它将给你带来错误,否则你将进入下一步,与谷歌分享回调响应中的代码,这样你就可以得到访问令牌。
所以这是两步验证,在成功获得证书后,我们使用DjangoORMStorage将其保存在Django数据存储中,因为只有通过它我们才能获取和存储证书到CredentialsField。一旦我们将它存储起来,我们就可以将用户重定向到任何一个特定的页面,这就是你如何获得access_token。
现在让我们创建一个主页,它将告诉用户是否已经登录。
def home(request):
status = True
if not request.user.is_authenticated:
return HttpResponseRedirect('admin')
storage = DjangoORMStorage(CredentialsModel, 'id', request.user, 'credential')
credential = storage.get()
try:
access_token = credential.access_token
resp, cont = Http().request("https://www.googleapis.com/auth/gmail.readonly",
headers ={'Host': 'www.googleapis.com',
'Authorization': access_token})
except:
status = False
print('Not Found')
return render(request, 'index.html', {'status': status})
现在我们假设用户在Django中是被认证的,这意味着用户不再是匿名的,并且有信息保存在数据库中。现在,为了支持匿名用户,我们可以取消对数据库中凭证的检查,或者创建一个临时用户。
回到主视图,首先我们要检查用户是否经过认证,这意味着用户不是匿名的,如果是,那么让他进行登录,否则先检查证书。如果用户已经从Google登录,那么将显示状态为True,否则将显示False。
现在,我们来创建一个模板。首先进入根文件夹,创建一个名为 “templates “的文件夹,然后在里面创建index.html。
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="{% static 'js/main.js' %}"></script>
<title>Google Login</title>
</head>
<body>
<div>
<div>
{% if not status %}
<a href="/gmailAuthenticate" onclick="gmailAuthenticate()" title="Google">Google</a>
{% else %}
<p>Your are verified</p>
{% endif %}
</div>
</div>
</body>
</html>
现在这个页面非常简化,所以没有css或样式,只有一个简单的链接来检查。现在你会注意到js文件。所以再次进入根文件夹并创建一个目录为static/js/。
并在js里面创建一个javascript文件main.js。
function gmailAuthenticate(){
$.ajax({
type: "GET",
url: "ajax/gmailAuthenticate",
// data: '',
success: function (data) {
console.log('Done')
}
});
};
这个js文件被用来将逻辑与HTML文件分开,也用来对Django进行一次AJAX调用。现在我们已经完成了视图的所有部分。
第5步:创建Url和基本设置
在主项目中,urls指的是fglogin/urls.py,编辑并放入。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('gfgauth.urls')),
]
因为我们需要测试gfgauth应用程序的工作。现在在gfgauth/urls.py中输入。
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^gmailAuthenticate', views.gmail_authenticate, name ='gmail_authenticate'),
url(r'^oauth2callback', views.auth_return),
url(r'^$', views.home, name ='home'),
]
正如你所看到的,gmailAuthenticate是用于AJAX调用,oauth2callback是用于回调网址,最后一个是主页网址。现在,在运行之前,有一些设置我们还没有谈及。
在settings.py中,你需要编辑。
1.在TEMPLATES列表中,在DIRS列表中加入’templates’。
2.在settings.py文件的最后添加。
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
GOOGLE_OAUTH2_CLIENT_SECRETS_JSON = 'client_secrets.json'
所以我们只是指定了模板和静态文件的位置,最重要的是谷歌oauth2客户端秘密json文件的位置。现在我们将下载这个文件。
第6步:生成Oauth2客户端秘密文件
前往谷歌开发者控制台页面,并创建一个项目,并为其命名为任何你喜欢的东西。创建后,前往项目仪表板,点击左上角的导航菜单。然后点击API服务,再点击凭证页。点击创建凭证(你可能需要在前进之前设置产品名称,所以先做这个)。现在选择Web应用程序,因为我们使用的是Django。在这之后指定名称,然后简单地进入重定向URI,在那里输入。
http://127.0.0.1:8000/oauth2callback
然后保存它。你不需要指定授权的Javascript起源,所以暂时留空。保存之后,你就可以看到你所有的证书了,只要下载证书就可以了,它会以一些随机的名字被保存,所以只需重新格式化文件名,输入’client_secrets’,并确保它是json格式的。然后保存它并粘贴到Django项目根目录下(即manage.py所在的位置)。
步骤#7:运行它
现在重新检查一切是否正确。确保你已经迁移了它。在继续前进之前,还要创建一个超级用户,这样你就不再是匿名的了。
python3.5 manage.py createsuperuser
输入所有必要的细节,然后做。
python3.5 manage.py runserver
并前往http://127.0.0.1:8000
你会看到这一点。
这是很好的,现在在这里输入你的超级用户证书,然后你就可以看到管理仪表板了。只要避开这一点,再次进入http://127.0.0.1:8000
现在你应该能够看到谷歌的链接,现在点击它,你会看到。
现在,正如你所看到的,它在说登录到GFG,这里GFG是我的项目名称。所以它工作得很好。现在输入你的凭证,提交后你会看到。
由于我们要求的是邮件权限,这就是为什么它要求用户允许它。如果它显示错误,那么在Google控制台,你可能需要在你的项目中激活Gmail API。现在,一旦你允许它,你将获得证书并保存在你的数据库中。如果用户点击了 “取消”,那么你将需要再写一些代码来处理这种流程。
现在,如果你允许的话,你将能够在你的控制台/数据库中看到access_token。获得access_token后,你可以利用它来获取用户的电子邮件和所有其他东西。