使用dj-rest-auth实现Google登录时,兑换访问令牌失败
解决Google社交登录的invalid_grant(Malformed auth code)错误
问题详情
通过dj-rest-auth和Django REST Framework配置Google社交登录后,向接口传递授权码时收到400错误:
请求内容
{"code": "4%google-auth-code"}
返回内容
{"non_field_errors": ["Failed to exchange code for access token"]}
捕获的底层错误
Error retrieving access token: b'{\n "error": "invalid_grant",\n "error_description": "Malformed auth code."\n}'
已确认Google Cloud Console中的重定向URL配置正常。
当前代码配置
settings.py
INSTALLED_APPS = [ ... 'django.contrib.sites', 'rest_framework', 'rest_framework.authtoken', 'dj_rest_auth', 'dj_rest_auth.registration', 'allauth', 'allauth.account', 'allauth.socialaccount', 'allauth.socialaccount.providers.google', ... ] MIDDLEWARE = [ ... 'allauth.account.middleware.AccountMiddleware', ] SITE_ID = 1 SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'my_social_key' SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'google_secret' SOCIALACCOUNT_PROVIDERS = { 'google': { 'APP': { 'client_id': SOCIAL_AUTH_GOOGLE_OAUTH2_KEY, 'secret': SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET, }, } } AUTHENTICATION_BACKENDS = [ 'allauth.account.auth_backends.AuthenticationBackend', ] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.TokenAuthentication', ] }
user/urls.py
from django.urls import path from user import views app_name = 'user' urlpatterns = [ ... path('auth/google/', views.GoogleLogin.as_view(), name='google_login'), ... ]
user/views.py
from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter from allauth.socialaccount.providers.oauth2.client import OAuth2Client from dj_rest_auth.registration.views import SocialLoginView class GoogleLogin(SocialLoginView): adapter_class = GoogleOAuth2Adapter callback_url = 'http://localhost:8000/api/auth/google/' client_class = OAuth2Client
requirements.txt
dj-rest-auth==6.0.0 django-allauth==0.61.0
解决方案
解码URL编码的授权码:请求中的code包含
%字符,说明是URL编码后的字符串,Google无法识别这种格式。需要前端在传递前用decodeURIComponent(code)解码;如果是测试场景,直接使用原始的授权码(不要带URL编码的转义字符)。如果前端无法处理,可在后端视图中添加解码逻辑:from urllib.parse import unquote from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter from allauth.socialaccount.providers.oauth2.client import OAuth2Client from dj_rest_auth.registration.views import SocialLoginView class GoogleLogin(SocialLoginView): adapter_class = GoogleOAuth2Adapter callback_url = 'http://localhost:8000/api/auth/google/' client_class = OAuth2Client def post(self, request, *args, **kwargs): if 'code' in request.data: request.data['code'] = unquote(request.data['code']) return super().post(request, *args, **kwargs)验证授权码有效性:确认授权码是Google OAuth2流程中正常返回的,未过期(有效期10分钟)、未被重复使用(授权码仅能使用一次),且没有被篡改。
严格匹配回调URL:再次核对
views.py中的callback_url与Google Cloud Console里配置的授权重定向URI,必须完全一致,包括协议(HTTP/HTTPS)、域名、端口、路径,不能有任何拼写或格式差异。核对客户端密钥与ID:确保
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY和SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET与Google Cloud中的客户端ID、密钥完全匹配,没有多余空格或特殊字符。检查版本兼容性:确认dj-rest-auth 6.0.0与django-allauth 0.61.0的兼容性,可尝试更新到最新兼容版本,参考官方文档确认版本匹配关系。
内容的提问来源于stack exchange,提问作者Grister
相关产品推荐
相关产品推荐

