如何用Firebase与Django Rest验证ID Token及对接认证流程?
Firebase Auth 对接 Django Rest Framework 全流程解析
先给你梳理下核心逻辑,再逐个解决你的疑问:
一、整体认证流程概览
整个对接的核心逻辑其实很清晰:
- 前端通过Firebase Auth完成账号登录,获取ID Token(就是你用
getIdTokenResult()拿到的token.token) - 前端将这个ID Token发送给Django后端
- 后端用Firebase Admin SDK验证Token的合法性
- 后端根据Token中的
uid或邮箱,关联/创建对应的Django用户 - 后续前端发起请求时,在请求头里带上这个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})
三、你的前端代码问题修正
你的前端请求有两个可以优化的点:
- 无需传递用户名和密码:已经通过Firebase完成登录验证,后端只需要ID Token就能确认身份
- 认证头格式要规范: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接口有两种解决方案:
- 给目标视图禁用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] # ... 你的视图逻辑 - 前端带上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是用来验证请求的认证类。
正确的做法是:
- 写一个处理前端登录请求的视图(比如上面的
FirebaseLoginView) - 在
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
相关产品推荐
相关产品推荐

