You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Django项目Google登录遇400 Bad Request错误求助

Django REST + React Google登录400错误解决方案

核心问题

你后端用id_token.verify_oauth2_token验证的是Google ID Token,但前端传递的是access_token——这两个令牌用途完全不同,Google的验证方法只认ID Token,直接验证access_token会触发ValueError,导致返回400错误。

修复步骤

1. 前端修改:传递ID Token而非access_token

在useGoogleLogin中指定返回ID Token,并将其发送给后端:

const gLogin = useGoogleLogin({
  responseType: 'id_token', // 要求Google返回ID Token
  onSuccess: tokenResponse => {
    axios.post('http://127.0.0.1:8000/api/auth/google/signin/', {
      token: tokenResponse.id_token // 传递id_token而非access_token
    })
    .then(response => {
      console.log('Successfully logged in');
    })
    .catch(error => {
      console.error('failed to login');
    })
  },
});

2. 后端代码优化

除了令牌类型问题,优化代码规范和异常处理:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.contrib.auth import authenticate, login
from google.oauth2 import id_token
from google.auth.transport import requests
from django.conf import settings

class GoogleSignInView(APIView):
    def post(self, request):
        token = request.data.get('token')
        if not token:
            return Response({'error': 'Token is missing.'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            # 验证ID Token的有效性
            idinfo = id_token.verify_oauth2_token(
                token, requests.Request(), settings.GOOGLE_CLIENT_ID
            )
            # 校验令牌签发方,防止伪造
            if idinfo['iss'] not in ['accounts.google.com', 'https://accounts.google.com']:
                raise ValueError('Invalid token issuer.')
            
            email = idinfo.get('email')
            # 确保用户邮箱已验证
            if not email or not idinfo.get('email_verified'):
                return Response({'error': 'Email not verified or missing.'}, status=status.HTTP_400_BAD_REQUEST)
            
            # 验证系统内用户
            user = authenticate(request, email=email)
            if user:
                login(request, user)
                return Response({'success': True})
            else:
                return Response({'error': 'User does not exist.'}, status=status.HTTP_404_NOT_FOUND)
        
        except ValueError as e:
            # 令牌无效、过期、签名错误等都会触发此异常
            return Response({'error': f'Invalid token: {str(e)}'}, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            return Response({'error': f'Server error: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

3. 必要检查项

  • Google Cloud配置:确保OAuth 2.0客户端已添加正确的授权JavaScript来源(如http://localhost:3000),避免令牌被Google判定为非法来源。
  • Django认证后端:若用邮箱作为登录标识,需在settings.py配置支持邮箱登录的认证后端:
    AUTHENTICATION_BACKENDS = [
        'django.contrib.auth.backends.ModelBackend',
        # 自定义后端示例(需自行实现)
        'your_app.backends.EmailAuthenticationBackend',
    ]
    
  • CORS设置:用django-cors-headers库允许前端域名访问后端API,settings.py配置示例:
    INSTALLED_APPS = ['corsheaders']
    MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware']
    CORS_ALLOWED_ORIGINS = ["http://localhost:3000"]
    

额外说明

Google的access_token用于调用Google开放API(如通讯录、日历),而ID Token专用于身份验证——登录场景下使用ID Token是OpenID Connect的标准流程,不要混淆两者的用途。

内容的提问来源于stack exchange,提问作者Nandan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 14:02:38