如何使用django-allauth对接Google API(Gmail API)实现独立OAuth2授权
如何使用django-allauth对接Google API(Gmail API)实现独立OAuth2授权
嘿,我正好折腾过这个需求,完全明白你想要独立于Google登录之外,单独获取Gmail API授权的诉求,下面一步步给你拆解怎么做:
1. 先搞定Google云平台的基础配置
首先你得去Google云控制台做些准备工作:
- 创建一个新项目,在API库中找到并启用Gmail API
- 进入「API和服务」→「凭据」页面,创建OAuth 2.0客户端ID,应用类型选择「Web应用」
- 填写授权回调URL(本地测试可以填
http://localhost:8000/accounts/google/gmail/callback/,线上环境要换成你的正式域名) - 创建完成后,把生成的客户端ID和客户端密钥存好,后面配置Django会用到
2. 配置Django项目与django-allauth
首先安装依赖包:
pip install django-allauth
接下来修改settings.py,把allauth相关的应用添加到INSTALLED_APPS里:
INSTALLED_APPS = [ # 保留你原有的Django应用 'django.contrib.sites', 'allauth', 'allauth.account', 'allauth.socialaccount', 'allauth.socialaccount.providers.google', ] # 必须设置SITE_ID SITE_ID = 1 # 配置认证后端 AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', 'allauth.account.auth_backends.AuthenticationBackend', ] # 重点配置Google OAuth2参数,指定Gmail所需权限 SOCIALACCOUNT_PROVIDERS = { 'google': { 'SCOPE': [ 'https://www.googleapis.com/auth/gmail.readonly', # 可根据需求调整权限,比如改成发送权限 'openid', ], 'AUTH_PARAMS': { 'access_type': 'offline', # 必须加这个才能获取刷新令牌,避免token过期后失效 'prompt': 'consent', # 每次授权都弹出同意页,确保能拿到刷新令牌 } } }
3. 自定义凭证存储模型
因为要和用户登录的社交账号分开存储,我们自己创建一个模型来保存Gmail的授权凭证:
# models.py from django.db import models from django.contrib.auth.models import User class GmailCredential(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) access_token = models.CharField(max_length=500) refresh_token = models.CharField(max_length=500) expires_at = models.DateTimeField() def __str__(self): return f"{self.user.username}'s Gmail Credentials"
写完模型后别忘了执行数据库迁移:
python manage.py makemigrations python manage.py migrate
4. 写触发授权的视图
这个视图用来生成Google的授权URL,然后重定向到授权页面:
# views.py from django.shortcuts import redirect from allauth.socialaccount.providers.google.provider import GoogleProvider from allauth.socialaccount.models import SocialApp def gmail_auth_init(request): # 获取我们在后台配置的Google应用 social_app = SocialApp.objects.get(provider='google') provider = GoogleProvider(request) # 构建授权请求,指定自定义的回调URL auth_request = provider.get_auth_request( request, redirect_uri='http://localhost:8000/accounts/google/gmail/callback/' # 要和Google控制台填的一致 ) return redirect(auth_request.url)
然后在urls.py里添加对应的路由:
# urls.py from django.urls import path from . import views urlpatterns = [ # 其他已有的路由 path('accounts/google/gmail/auth/', views.gmail_auth_init, name='gmail_auth_init'), path('accounts/google/gmail/callback/', views.gmail_auth_callback, name='gmail_auth_callback'), ]
5. 自定义回调视图处理并存储凭证
这个视图是核心,用来处理Google授权后的回调,把拿到的token存到我们自己的模型里:
# views.py 继续添加 from django.contrib.auth.decorators import login_required from allauth.socialaccount.models import SocialToken from .models import GmailCredential from datetime import datetime, timezone @login_required def gmail_auth_callback(request): # 用allauth的工具处理回调,拿到授权token provider = GoogleProvider(request) sociallogin = provider.sociallogin_from_request(request) token = sociallogin.token # 把token信息存到我们的自定义模型里 credential, created = GmailCredential.objects.get_or_create(user=request.user) credential.access_token = token.token credential.refresh_token = token.token_secret # 把时间戳转成datetime格式存储 credential.expires_at = datetime.fromtimestamp(token.expires_at, timezone.utc) credential.save() # 授权成功后重定向到你指定的页面,比如用户的Gmail管理页面 return redirect('gmail_auth_success')
这里用了@login_required是因为要把凭证关联到当前登录的用户,但注意:这个授权是独立于Google登录的,用户可以用普通的用户名密码登录,再完成Gmail授权。
6. 在视图里调用Gmail API
现在有了存储的凭证,就可以在视图里调用Gmail API了,比如获取用户的邮件列表:
# views.py 继续添加 import requests from django.shortcuts import render @login_required def gmail_get_emails(request): credential = GmailCredential.objects.get(user=request.user) # 先检查access_token是否过期 if datetime.now(timezone.utc) >= credential.expires_at: # 用refresh_token刷新token social_app = SocialApp.objects.get(provider='google') provider = GoogleProvider(request) new_token = provider.refresh_token( social_app, credential.refresh_token ) # 更新本地存储的凭证 credential.access_token = new_token.token credential.expires_at = datetime.fromtimestamp(new_token.expires_at, timezone.utc) credential.save() # 调用Gmail API获取邮件列表 headers = {'Authorization': f'Bearer {credential.access_token}'} response = requests.get( 'https://www.googleapis.com/gmail/v1/users/me/messages', headers=headers, params={'maxResults': 10} ) emails = response.json() # 把邮件数据传到模板展示 return render(request, 'gmail_emails.html', {'emails': emails})
最后你可以写一个模板gmail_emails.html来展示这些邮件数据。
备注:内容来源于stack exchange,提问作者Kovy Jacob
相关产品推荐
相关产品推荐

