如何在Django中实现OAuth2授权读取用户Gmail?替代已废弃oauth2client
在Django中实现Google OAuth2授权读取用户邮件
前置准备
Google Cloud Console配置
- 创建新项目,启用Gmail API
- 配置OAuth同意屏幕(根据用户群体选择外部/内部类型,填写必要信息并添加测试用户)
- 创建OAuth 2.0客户端ID,选择Web应用类型,设置授权回调URL(如
http://localhost:8000/oauth2callback) - 记录生成的客户端ID和客户端密钥
安装依赖库
在Django项目中安装现代Google OAuth相关依赖:pip install django google-auth google-auth-oauthlib google-auth-httplib2 google-api-python-client
Django项目配置
在settings.py中添加Google OAuth参数:
# settings.py GOOGLE_CLIENT_ID = "你的客户端ID" GOOGLE_CLIENT_SECRET = "你的客户端密钥" GOOGLE_REDIRECT_URI = "http://localhost:8000/oauth2callback" # 授权范围:仅申请邮件只读权限,遵循最小权限原则 GOOGLE_SCOPES = ["https://www.googleapis.com/auth/gmail.readonly"]
核心视图实现
1. 授权发起视图
创建视图引导用户跳转至Google授权页面:
# views.py from django.shortcuts import redirect from google_auth_oauthlib.flow import Flow from django.conf import settings def google_auth(request): # 构建授权流程 flow = Flow.from_client_config( client_config={ "web": { "client_id": settings.GOOGLE_CLIENT_ID, "client_secret": settings.GOOGLE_CLIENT_SECRET, "redirect_uris": [settings.GOOGLE_REDIRECT_URI], "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", } }, scopes=settings.GOOGLE_SCOPES, redirect_uri=settings.GOOGLE_REDIRECT_URI, ) # 生成授权URL,请求离线访问以获取刷新令牌 authorization_url, state = flow.authorization_url( access_type="offline", include_granted_scopes="true" ) # 存储state到session用于回调验证,防止CSRF攻击 request.session["state"] = state return redirect(authorization_url)
2. 授权回调视图
处理Google返回的授权码,获取并存储访问令牌:
# views.py from django.http import HttpResponseBadRequest from googleapiclient.discovery import build def oauth2callback(request): # 验证state参数一致性 if request.GET.get("state") != request.session.get("state"): return HttpResponseBadRequest("无效的state参数") flow = Flow.from_client_config( client_config={ "web": { "client_id": settings.GOOGLE_CLIENT_ID, "client_secret": settings.GOOGLE_CLIENT_SECRET, "redirect_uris": [settings.GOOGLE_REDIRECT_URI], "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", } }, scopes=settings.GOOGLE_SCOPES, state=request.session.get("state"), redirect_uri=settings.GOOGLE_REDIRECT_URI, ) # 用授权码交换令牌 flow.fetch_token(code=request.GET.get("code")) # 将凭证信息存入session(生产环境建议扩展用户模型,存储到数据库) credentials = flow.credentials request.session["credentials"] = { "token": credentials.token, "refresh_token": credentials.refresh_token, "token_uri": credentials.token_uri, "client_id": credentials.client_id, "client_secret": credentials.client_secret, "scopes": credentials.scopes, } return redirect("read_emails")
3. 读取邮件视图
使用存储的凭证调用Gmail API读取用户邮件:
# views.py from google.oauth2.credentials import Credentials from django.shortcuts import render def read_emails(request): # 从session获取凭证信息 credentials_data = request.session.get("credentials") if not credentials_data: return redirect("google_auth") # 构建Credentials对象,库会自动处理令牌刷新 credentials = Credentials(**credentials_data) # 创建Gmail API客户端 service = build("gmail", "v1", credentials=credentials) # 获取用户最近10封邮件的基础信息 results = service.users().messages().list(userId="me", maxResults=10).execute() messages = results.get("messages", []) email_list = [] for msg in messages: msg_data = service.users().messages().get(userId="me", id=msg["id"], format="metadata").execute() headers = msg_data.get("payload", {}).get("headers", []) # 提取邮件主题和发件人信息 subject = next((h["value"] for h in headers if h["name"] == "Subject"), "无主题") sender = next((h["value"] for h in headers if h["name"] == "From"), "未知发件人") email_list.append({"subject": subject, "sender": sender, "id": msg["id"]}) return render(request, "emails.html", {"emails": email_list})
URL配置
在项目urls.py中添加路由:
# urls.py from django.urls import path from . import views urlpatterns = [ path("google-auth/", views.google_auth, name="google_auth"), path("oauth2callback/", views.oauth2callback, name="oauth2callback"), path("read-emails/", views.read_emails, name="read_emails"), ]
模板示例(emails.html)
<!DOCTYPE html> <html> <head> <title>我的邮件</title> </head> <body> <h1>最近邮件</h1> <ul> {% for email in emails %} <li> <strong>主题:</strong> {{ email.subject }}<br> <strong>发件人:</strong> {{ email.sender }} </li> {% empty %} <li>暂无邮件</li> {% endfor %} </ul> <a href="{% url 'google_auth' %}">重新授权</a> </body> </html>
关键注意事项
- 令牌存储:生产环境禁止将令牌存在session中,建议扩展Django用户模型,添加字段存储refresh_token、token等信息
- HTTPS要求:生产环境必须使用HTTPS,否则Google OAuth服务会拒绝回调请求
- 错误处理:需添加异常捕获逻辑(如令牌过期、API调用失败等),提升用户体验
- 权限范围:始终遵循最小权限原则,仅申请业务必需的权限
内容的提问来源于stack exchange,提问作者Kovy Jacob
相关产品推荐
相关产品推荐

