Python Django | Google 身份验证和从头开始获取邮件
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
所以整个终端看起来像:
因为我们创建了一个应用程序。将该应用名称添加到INSTALLED_APP
列表中的settings.py
中。现在我们已经运行了 Django 项目,所以让我们先迁移它,然后检查是否有任何错误。
python manage.py makemigrations
python manage.py migrate
python manage.py runserver
因此,迁移后,应该能够运行服务器并在该特定 url 上看到 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 获得的凭证,因此只有 2 个主要字段需要处理。第一个是id
,它将是 ForeignKey ,第二个是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,
目前task
和updated_time
只是添加的额外字段,因此可以删除。所以这个凭证将保存数据库中的凭证数据。
重要准则:
当我们导入CredentialsField
时,会自动在后面执行__init__
方法,如果您会注意到路径中的代码/google-login/myvenv/lib/python3.5/site-packages/oauth2client/contrib/django_util/__init__.py
第233行
他们正在导入 urlresolvers,以便他们可以从中使用 reverse 方法。现在的问题是这个 urlresolvers 在 Django 1.10 或 Django 1.11 之后已经被删除,如果你在 Django 2.0 上工作,那么它会给出一个错误,即找不到或不存在 urlresolvers。
现在要克服这个问题,我们需要更改 2 行,首先将 import from django.core import urlresolvers
为from django.urls import reverse
然后将第 411 行urlresolvers.reverse(...)
替换为reverse(...)
现在您应该能够成功运行它。
创建这些模型后:
python manage.py makemigrations
python manage.py migrate
第 4 步:创建视图
现在我们只有 3 个主要视图来处理请求。首先是显示主页、状态、Google 按钮,以便我们可以发送身份验证请求。单击 google 按钮时将触发第二个视图,这意味着 AJAX 请求。第三是处理来自 google 的返回请求,以便我们可以从中接受 access_token 并将其保存在我们的数据库中。
首先,让我们进行 Google 身份验证:
所以现在我们需要指定 API 的流程,我们需要询问什么权限,我的密钥是什么和重定向 url。所以要做到这一点,请输入:
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 url 发出请求,然后获取凭据。
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个参数。首先是其中包含 CredentialsField 的模型类。第二个是具有凭据的唯一 id 表示键名,第三个是具有凭据的键值,最后是我们在models.py
中指定的 CredentialsField 的名称。
然后我们从存储中获取值,看看它是否有效。如果它无效,那么我们创建一个用户令牌并获取一个授权 url,我们将用户重定向到 Google 登录页面。重定向后用户将填写表格,一旦用户被谷歌授权,谷歌将使用access_token
将数据发送到回调 url ,我们稍后会这样做。现在以防万一,如果用户凭据已经存在,那么它将重新验证凭据并返回 access_token 或有时会返回刷新的 access_token,以防前一个已过期。
现在我们需要处理回调 url,这样做:
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("/")
现在在回调 url 中,当我们从 google 获得一个响应时,我们会捕获数据并从中获取状态,状态只不过是我们通过 generateToken 生成的令牌。因此,我们所做的是使用 secret_key、我们生成的令牌以及生成它的用户来验证令牌。这些事情通过xsrfutil.validate_token
方法进行验证,该方法确保令牌随着时间的推移不会太旧,并且仅在给定的特定时间生成。如果这些事情不能很好地解决,那么它会给你错误,否则你将进入下一步并与谷歌共享回调响应中的代码,以便你可以获得 access_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 中已经过身份验证,这意味着用户不再是匿名用户并且信息保存在数据库中。现在为了支持匿名用户,我们可以删除数据库中的凭据检查或创建一个临时用户。
回到主视图,首先我们将检查用户是否经过身份验证,这意味着用户不是匿名的,如果是,则让他登录,否则首先检查凭据。如果用户已经从谷歌登录,那么它将显示状态为真,否则它将显示假。
现在来到模板,让我们创建一个。首先转到根文件夹并创建一个名为“模板”的文件夹,然后在其中创建index.html
:
{% load static %}
Google Login
{% if not status %}
Google
{% else %}
Your are verified
{% endif %}
现在这个页面非常简化,所以没有 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 表示gfglogin/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 用于回调 url,最后一个是主页 url。现在在运行之前,我们还没有谈到一些设置:
在settings.py
你需要编辑:
- 在 TEMPLATES 列表中,在 DIRS 列表中添加“模板”。
- 最后在 settings.py 文件中添加:
STATIC_URL = '/static/' STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'), ) GOOGLE_OAUTH2_CLIENT_SECRETS_JSON = 'client_secrets.json'
所以我们只是指定了模板和静态文件的位置,最重要的是 google oauth2 客户端机密 json 文件在哪里。现在我们将下载这个文件。第 6 步:生成 Oauth2 客户端机密文件
前往 Google Developer Console 页面并创建一个项目并将其命名为您喜欢的任何名称。创建后,转到项目仪表板并单击左上角的导航菜单。然后单击 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
现在您应该能够看到 Google 链接,现在单击它,您将看到:
现在你可以看到它说登录以继续 GFG,这里 GFG 是我的项目名称。所以它工作正常。现在输入您的凭据,提交后您将看到:
由于我们正在请求邮件权限,这就是为什么它要求用户允许它。如果它显示错误,那么在 Google 控制台中,您可能需要将 Gmail API 激活到您的项目中。现在,一旦您允许它,您将获得凭据并保存在数据库中。如果用户单击取消,那么您将需要编写更多代码来处理此类流程。
现在,如果您允许它,那么您将能够在您的控制台/数据库上看到 access_token。获得 access_token 后,您可以使用它来获取用户电子邮件和所有其他内容。
在此处查看此存储库中的完整代码。