如何通过ngrok在请求中包含Django CSRF令牌?
我刚好折腾过局域网Django应用集成Facebook Login的场景,给你梳理一下关键实现步骤和踩过的坑:
局域网Django + Facebook Login 实现指南
一、先搞定Facebook回调地址的限制(ngrok配置)
Facebook要求回调地址必须是localhost或公网可访问的域名,局域网服务刚好卡在这里,用ngrok就能完美解决:
- 启动ngrok映射你的本地Django端口,比如本地跑8000端口,执行命令:
ngrok http 8000 - 复制ngrok生成的公网域名(比如
https://abc-12-34-56-78.ngrok.io),登录Facebook开发者后台,找到你的App→「产品」→「Facebook登录」→「设置」,把这个域名加上回调路径(比如https://abc-12-34-56-78.ngrok.io/facebook/callback)添加到「有效的OAuth跳转URI」列表里。注意:每次重启ngrok都会换域名,要记得更新这个配置,嫌麻烦可以买ngrok付费版用固定域名。
二、Django端的基础认证配置
我个人推荐用django-allauth来做社交认证,比自己手写OAuth2流程省心太多:
- 先安装依赖:
pip install django-allauth - 在
settings.py里添加配置:INSTALLED_APPS = [ # 你的其他Django应用 'allauth', 'allauth.account', 'allauth.socialaccount', 'allauth.socialaccount.providers.facebook', ] # 配置认证后端 AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', 'allauth.account.auth_backends.AuthenticationBackend', ] # Facebook Provider配置 SOCIALACCOUNT_PROVIDERS = { 'facebook': { 'APP': { 'client_id': '你的Facebook App ID', 'secret': '你的Facebook App Secret', 'key': '' }, 'SCOPE': ['email', 'public_profile'], # 要获取的用户权限 'FIELDS': ['id', 'email', 'name', 'picture'], # 要拉取的用户字段 'VERSION': 'v18.0' # 用最新的Graph API版本 } } - 把allauth的路由加到项目的
urls.py:urlpatterns = [ # 其他路由 path('accounts/', include('allauth.urls')), ]
三、AJAX提交用户数据到本地视图的关键细节
你提到登录后用AJAX把用户数据POST到/fb_login存库,这里有几个必须注意的点:
- 一定要带CSRF令牌:Django默认会拦截没有CSRF令牌的POST请求,前端可以这么处理:
// 从模板的csrf_token标签里拿令牌 const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value; // 发送AJAX请求 fetch('/fb_login', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrftoken }, body: JSON.stringify({ facebook_id: response.authResponse.userID, name: response.name, email: response.email, access_token: response.authResponse.accessToken }) }) - 后端必须验证access_token的合法性:前端传的数据可能被篡改,所以一定要调用Facebook的调试接口校验token有效性,比如:
import requests from django.conf import settings def validate_fb_token(access_token): app_id = settings.SOCIALACCOUNT_PROVIDERS['facebook']['APP']['client_id'] app_secret = settings.SOCIALACCOUNT_PROVIDERS['facebook']['APP']['secret'] debug_url = f"https://graph.facebook.com/debug_token?input_token={access_token}&access_token={app_id}|{app_secret}" response = requests.get(debug_url) return response.json().get('data', {}).get('is_valid', False) - 处理用户登录状态:验证通过后,要么创建新用户,要么更新已有用户,然后用Django的
login()方法设置用户登录状态:from django.http import JsonResponse from django.contrib.auth import login from django.contrib.auth.models import User import json def fb_login(request): if request.method != 'POST': return JsonResponse({'status': 'error', 'msg': '仅支持POST请求'}) data = json.loads(request.body) fb_id = data.get('facebook_id') access_token = data.get('access_token') # 先验证token if not validate_fb_token(access_token): return JsonResponse({'status': 'error', 'msg': '无效的Facebook令牌'}) # 查找或创建用户 user, created = User.objects.get_or_create(username=fb_id, defaults={ 'first_name': data.get('name'), 'email': data.get('email') }) # 设置登录状态 login(request, user) return JsonResponse({'status': 'success', 'msg': '登录成功'})
四、局域网环境的额外注意事项
- 确保你的Django服务绑定的是
0.0.0.0而不是127.0.0.1,这样局域网内的设备才能访问,启动命令用:python manage.py runserver 0.0.0.0:8000 - 测试的时候先用ngrok的公网域名打开你的Django页面,确认能正常访问,再测试Facebook登录流程,避免因为网络问题导致回调失败。
内容的提问来源于stack exchange,提问作者phepp
相关产品推荐
相关产品推荐

