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

如何用Firebase与Django Rest验证ID Token及对接认证流程?

Firebase Auth 对接 Django Rest Framework 全流程解析

先给你梳理下核心逻辑,再逐个解决你的疑问:

一、整体认证流程概览

整个对接的核心逻辑其实很清晰:

  1. 前端通过Firebase Auth完成账号登录,获取ID Token(就是你用getIdTokenResult()拿到的token.token)
  2. 前端将这个ID Token发送给Django后端
  3. 后端用Firebase Admin SDK验证Token的合法性
  4. 后端根据Token中的uid或邮箱,关联/创建对应的Django用户
  5. 后续前端发起请求时,在请求头里带上这个ID Token,后端自动完成身份验证并识别用户

二、verify_id_token代码该放哪?怎么用?

这段验证代码不是直接写在普通视图里,更规范的做法是封装成自定义DRF认证类,让DRF在处理请求时自动调用它完成Token验证。

举个具体的实现例子:

# 在你的Django app下新建authentication.py文件
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
import firebase_admin
from firebase_admin import auth

# 初始化Firebase Admin SDK(确保你已经下载了serviceAccountKey.json)
if not firebase_admin._apps:
    cred = firebase_admin.credentials.Certificate('path/to/your/serviceAccountKey.json')
    firebase_admin.initialize_app(cred)

class FirebaseAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # 从请求头获取Token,DRF默认识别的格式是「Authorization: Bearer <token>」
        auth_header = request.META.get('HTTP_AUTHORIZATION')
        if not auth_header or not auth_header.startswith('Bearer '):
            return None  # 无Token时返回None,交给其他认证方式处理

        id_token = auth_header.split(' ')[1]
        try:
            # 这里就是你提到的Firebase验证代码
            decoded_token = auth.verify_id_token(id_token)
            uid = decoded_token['uid']
            email = decoded_token.get('email')

            # 关联Django用户:不存在则创建,存在则直接使用
            from django.contrib.auth.models import User
            user, created = User.objects.get_or_create(username=uid, defaults={'email': email})
            
            return (user, None)  # 返回(user, None)表示认证成功,DRF会把user绑定到request.user
        except auth.InvalidIdTokenError:
            raise AuthenticationFailed('无效的Firebase ID Token')
        except Exception as e:
            raise AuthenticationFailed(f'认证失败: {str(e)}')

之后你可以选择:

  • 全局启用:在settings.py里配置,让所有API都优先用这个认证方式
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'your_app.authentication.FirebaseAuthentication',
            # 保留Session认证,方便Django后台登录
            'rest_framework.authentication.SessionAuthentication',
        ],
    }
    
  • 局部启用:在特定视图类里单独指定,只让该视图使用Firebase认证
    from rest_framework.views import APIView
    from your_app.authentication import FirebaseAuthentication
    
    class FirebaseLoginView(APIView):
        authentication_classes = [FirebaseAuthentication]
    
        def post(self, request):
            # 这里request.user已经是认证后的Django用户了
            return Response({'message': '认证成功', 'user_id': request.user.id})
    

三、你的前端代码问题修正

你的前端请求有两个可以优化的点:

  1. 无需传递用户名和密码:已经通过Firebase完成登录验证,后端只需要ID Token就能确认身份
  2. 认证头格式要规范:DRF默认识别Authorization: Bearer <token>格式,而非直接传Token

修正后的前端代码:

async login() {
  this.error = null;
  try {
    const response = await firebase.auth().signInWithEmailAndPassword(this.email, this.password);
    const tokenResult = await response.user.getIdTokenResult();
    const idToken = tokenResult.token;

    fetch("/account/firebase/", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        // 改成标准的Bearer认证头格式
        "Authorization": `Bearer ${idToken}`,
      },
      // 不需要再传用户名密码了
      body: JSON.stringify({}),
    }).then((response) => response.json().then((data) => console.log(data)));
  } catch (error) {
    this.error = error;
  }
}

四、解决403 CSRF验证失败问题

Django默认会对POST请求做CSRF校验,针对API接口有两种解决方案:

  1. 给目标视图禁用CSRF校验:用装饰器给视图类添加豁免,适合纯API场景
    from django.views.decorators.csrf import csrf_exempt
    from django.utils.decorators import method_decorator
    
    @method_decorator(csrf_exempt, name='dispatch')
    class FirebaseLoginView(APIView):
        authentication_classes = [FirebaseAuthentication]
        # ... 你的视图逻辑
    
  2. 前端带上CSRF Token:从Django的Cookie中获取csrftoken,放到请求头里
    // 先写个工具函数获取CSRF Token
    function getCookie(name) {
      let cookieValue = null;
      if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
          const cookie = cookies[i].trim();
          if (cookie.substring(0, name.length + 1) === (name + '=')) {
            cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
            break;
          }
        }
      }
      return cookieValue;
    }
    const csrftoken = getCookie('csrftoken');
    
    // 然后在fetch请求中添加CSRF头
    fetch("/account/firebase/", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${idToken}`,
        "X-CSRFToken": csrftoken,
      },
      body: JSON.stringify({}),
    })
    

五、关于FirebaseAuthentication的路由问题

你不需要把FirebaseAuthentication直接注册为路由!路由对应的是视图,而FirebaseAuthentication是用来验证请求的认证类。

正确的做法是:

  1. 写一个处理前端登录请求的视图(比如上面的FirebaseLoginView)
  2. 在urls.py里给这个视图注册路由:
    from django.urls import path
    from your_app.views import FirebaseLoginView
    
    urlpatterns = [
        path('account/firebase/', FirebaseLoginView.as_view(), name='api-firebase-login'),
    ]
    

这样前端请求这个路由时,DRF会自动用FirebaseAuthentication验证请求头里的Token,认证成功后视图就能拿到request.user。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:04:46