Django登录认证后部分视图返回AnonymousUser问题排查
问题现象
调用login()完成用户登录后,CheckAuthView视图能通过request.user.is_authenticated正常识别已认证用户,但CreateClubView视图中request.user返回AnonymousUser,访问request.session['id']触发KeyError。登录接口返回成功,且前端可通过CheckAuthView验证登录状态并访问首页。
相关代码
登录视图LoginView
class LoginView(APIView): serializer_class = LoginUserSerializer def post(self, request): serializer = self.serializer_class(data=request.data) if serializer.is_valid(): username = serializer.data.get('username') password = serializer.data.get('password') # 检查用户是否存在 user_exist_query = User.objects.filter(username=username) if not user_exist_query.exists(): return JsonResponse({"error": "用户名不存在"}, status = 401) # 验证用户名密码 user_auth_query = authenticate(username=username, password=password) if user_auth_query is not None: login(request, user_auth_query) return JsonResponse({"message": "登录成功"}, status = 200) else: return JsonResponse({"error": "用户名或密码错误"}, status = 401) return JsonResponse({"error": "请求参数错误"}, status=400)
正常工作的CheckAuthView视图
class CheckAuthView(APIView): def get(self, request): if request.user.is_authenticated: return Response(status=status.HTTP_200_OK) else: return Response(status=status.HTTP_400_BAD_REQUEST)
该视图用于保护React前端路由,已登录时允许访问首页,未登录则跳转,证明此处request.user可获取真实用户。
存在问题的CreateClubView视图
class CreateClubView(APIView): serilizer_class = ClubSerializer def post(self, request): serializer = self.serilizer_class(data=request.data) print(request.user.is_authenticated) if serializer.is_valid(): clubName = serializer.data.get('name') clubDesc = serializer.data.get('description') clubLoc = serializer.data.get('location') clubEmail = serializer.data.get('email') clubContact = serializer.data.get('contact') clubWebsite = serializer.data.get('website') clubOrganizer = request.session['id'] queryset = Club.objects.filter(name=clubName) if queryset.exists(): return Response(status=status.HTTP_400_BAD_REQUEST) club = Club.objects.create(name=clubName, description=clubDesc, location=clubLoc, email=clubEmail, contact=clubContact, website=clubWebsite, organizer=clubOrganizer) club.save() return Response(status=status.HTTP_201_CREATED) return Response(status=status.HTTP_400_BAD_REQUEST)
打印request.user返回AnonymousUser,访问request.session['id']触发KeyError。
前端React调用代码
const response: Response = await fetch('http://127.0.0.1:8000/api/clubs/create', { method: 'POST', headers: headers, body: JSON.stringify(form), }) if (response.ok) { console.log("俱乐部创建成功"); navigate("/home"); } else { console.log("俱乐部创建失败"); }
Django中间件配置
MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", 'corsheaders.middleware.CorsMiddleware', "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", ]
排查方向与解决方案
1. 前端请求未携带Session Cookie
Django Session认证依赖sessionid Cookie传递用户会话信息,fetch API默认不会自动携带Cookie。需修改前端请求配置:
const response: Response = await fetch('http://127.0.0.1:8000/api/clubs/create', { method: 'POST', headers: headers, body: JSON.stringify(form), credentials: 'include' // 强制携带Cookie })
2. CORS配置未允许凭证传递
检查Django settings.py中的CORS配置,确保开启允许凭证:
CORS_ALLOW_CREDENTIALS = True CORS_ALLOWED_ORIGINS = [ "http://localhost:3000", # 替换为你的前端实际地址 ]
3. 修正视图拼写错误(次要)
CreateClubView中的serilizer_class拼写错误,应为serializer_class,虽不影响认证,但建议修正以避免潜在问题。
4. 避免直接操作Session获取用户ID
无需手动存储request.session['id'],认证成功后直接使用request.user.id即可,同时建议先校验用户认证状态:
class CreateClubView(APIView): serializer_class = ClubSerializer def post(self, request): # 先校验用户是否认证 if not request.user.is_authenticated: return Response(status=status.HTTP_401_UNAUTHORIZED) serializer = self.serializer_class(data=request.data) if serializer.is_valid(): # 替换原session取值逻辑 clubOrganizer = request.user.id # 其余代码保持不变
总结
核心问题是前端请求未携带Session Cookie,导致后端无法识别用户会话。优先修正前端fetch的credentials配置,同时确保Django的CORS设置允许凭证传递,即可解决request.user为匿名用户的问题。
内容的提问来源于stack exchange,提问作者zayaanra

