在Django项目中使用Google API结合AllAuth认证系统,主要涉及以下几个核心概念:
pip install django-allauth google-auth google-auth-oauthlib google-api-python-client
INSTALLED_APPS = [
...
'django.contrib.sites',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.google',
...
]
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend'
]
SITE_ID = 1
# Google OAuth配置
SOCIALACCOUNT_PROVIDERS = {
'google': {
'SCOPE': [
'profile',
'email',
'https://www.googleapis.com/auth/drive.readonly',
# 添加其他需要的scope
],
'AUTH_PARAMS': {
'access_type': 'offline',
}
}
}
http://yourdomain.com/accounts/google/login/callback/
用户通过AllAuth登录后,可以在视图中获取访问令牌:
from allauth.socialaccount.models import SocialToken
def get_google_token(request):
if request.user.is_authenticated:
try:
social_token = SocialToken.objects.get(
account__user=request.user,
account__provider='google'
)
access_token = social_token.token
refresh_token = social_token.token_secret
# 使用令牌访问Google API
return access_token, refresh_token
except SocialToken.DoesNotExist:
return None, None
return None, None
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
def access_google_drive(request):
access_token, refresh_token = get_google_token(request)
if not access_token:
return HttpResponse("未找到Google令牌", status=401)
credentials = Credentials(
token=access_token,
refresh_token=refresh_token,
token_uri='https://oauth2.googleapis.com/token',
client_id=settings.SOCIALACCOUNT_PROVIDERS['google']['APP']['client_id'],
client_secret=settings.SOCIALACCOUNT_PROVIDERS['google']['APP']['secret']
)
try:
service = build('drive', 'v3', credentials=credentials)
results = service.files().list(
pageSize=10, fields="nextPageToken, files(id, name)").execute()
items = results.get('files', [])
if not items:
return HttpResponse("Google Drive中没有找到文件")
else:
return render(request, 'drive_files.html', {'files': items})
except Exception as e:
return HttpResponse(f"访问Google Drive出错: {str(e)}", status=500)
原因: 访问令牌通常有1小时的有限生命周期
解决方案:
'access_type': 'offline'
以获取刷新令牌from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
def refresh_access_token(refresh_token):
credentials = Credentials(
None,
refresh_token=refresh_token,
token_uri='https://oauth2.googleapis.com/token',
client_id=settings.SOCIALACCOUNT_PROVIDERS['google']['APP']['client_id'],
client_secret=settings.SOCIALACCOUNT_PROVIDERS['google']['APP']['secret']
)
credentials.refresh(Request())
return credentials.token
原因: 请求的scope未包含在初始授权中
解决方案:
解决方案:
from google.auth.exceptions import RefreshError
try:
# 尝试使用令牌
except RefreshError:
# 令牌失效,引导用户重新登录
return redirect('socialaccount_login', provider='google')
from django.core.cache import cache
from allauth.socialaccount.models import SocialToken
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from celery import shared_task
@shared_task
def process_google_drive_files(user_id):
try:
social_token = SocialToken.objects.get(
account__user_id=user_id,
account__provider='google'
)
credentials = Credentials(
token=social_token.token,
refresh_token=social_token.token_secret,
token_uri='https://oauth2.googleapis.com/token',
client_id=settings.SOCIALACCOUNT_PROVIDERS['google']['APP']['client_id'],
client_secret=settings.SOCIALACCOUNT_PROVIDERS['google']['APP']['secret']
)
service = build('drive', 'v3', credentials=credentials)
# 执行后台任务...
except SocialToken.DoesNotExist:
# 处理令牌不存在的情况
pass
对于需要访问多个Google账户的情况,可以扩展模型存储多个令牌:
from django.db import models
from django.contrib.auth.models import User
class GoogleAccount(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
email = models.EmailField()
access_token = models.TextField()
refresh_token = models.TextField()
expires_at = models.DateTimeField()
def is_expired(self):
from django.utils import timezone
return self.expires_at <= timezone.now()
通过以上配置和代码示例,您可以在Django项目中成功集成带令牌的Google API,并利用AllAuth简化用户认证流程。