Django API:登录生成Token但Profile视图提示未认证及AnonymousUser无email问题
问题原因
- 重定向丢失认证信息:Login视图登录成功后执行重定向,你设置的
request.META['HTTP_AUTHORIZATION']仅对当前POST请求有效,重定向后的GET请求是全新请求,不会携带Token头,导致Profile视图无法识别已认证用户。 - 浏览器未自动携带Token:Postman是手动添加了Token请求头才正常,而浏览器端请求Profile时,没有在请求头中携带Token,因此
request.user为AnonymousUser,访问user.email就会触发'AnonymousUser' object has no attribute 'email'错误。
解决办法
1. 调整Login视图的返回逻辑
去掉重定向,直接返回Token给前端,让前端存储并在后续请求中携带:
class LoginView(APIView): permission_classes = (permissions.AllowAny,) # 移除不必要的TokenAuthentication,登录请求不需要携带Token # authentication_classes = (TokenAuthentication,) def post(self, request): username = request.data.get('username') password = request.data.get('password') user = authenticate(username=username, password=password) if user is not None: token, created = Token.objects.get_or_create(user=user) # 返回Token和用户信息,而非重定向 return Response({"token": token.key, "username": user.username}) else: return Response({'error': 'Invalid credentials'}, status=400)
2. 前端请求Profile时携带Token
前端拿到Token后,存储到本地(比如localStorage),每次请求Profile时在请求头中添加Authorization字段:
// 登录成功后存储Token fetch('/login/', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({username: 'your-username', password: 'your-password'}) }) .then(res => res.json()) .then(data => { localStorage.setItem('authToken', data.token); }); // 请求Profile时携带Token fetch('/profile/', { headers: { 'Authorization': 'Token ' + localStorage.getItem('authToken') } }) .then(res => res.json()) .then(data => console.log(data));
3. 优化Profile视图的权限控制
将Profile视图的权限改为IsAuthenticated,让DRF自动拦截未认证请求,避免手动判断的冗余:
from rest_framework.permissions import IsAuthenticated class ProfileView(APIView): permission_classes = (IsAuthenticated,) def get(self, request): # 已认证用户直接返回信息,无需判断is_authenticated return Response({'username': request.user.username, 'email': request.user.email})
可选:改用Session认证(服务端渲染场景)
如果你的项目是服务端渲染(比如用Django模板),不想用Token,可以改用Session认证:
- 移除Login视图中的Token相关代码,保留
login(request, user) - 确保
settings.py中启用SessionAuthentication(默认已启用) - Profile视图无需手动处理Token,
request.user会自动通过Session识别:
class LoginView(APIView): permission_classes = (permissions.AllowAny,) def post(self, request): username = request.data.get('username') password = request.data.get('password') user = authenticate(username=username, password=password) if user is not None: login(request, user) return redirect('myprofile:profile') else: return Response({'error': 'Invalid credentials'}, status=400) class ProfileView(APIView): permission_classes = (IsAuthenticated,) def get(self, request): return Response({'username': request.user.username, 'email': request.user.email})
这种方式下,浏览器会自动携带Session Cookie,无需手动处理Token。
内容的提问来源于stack exchange,提问作者Dani barchen
相关产品推荐
相关产品推荐

