Django Rest Framework TokenAuthentication登出失效问题解决
Django Rest Framework TokenAuthentication 登出失效问题
我在使用DRF的TokenAuthentication时,访问http://192.168.1.67:8000/api/categories/需要登录认证,但点击登出按钮后操作未生效。终端显示触发登出时发起了两个请求:
[18/May/2023 10:42:14] "GET /api-auth/logout/?next=/api/categories/ HTTP/1.1" 302 0 [18/May/2023 10:42:15] "GET /api/categories/ HTTP/1.1" 200 32866
相关代码
urls.py
urlpatterns = [ path('create/', views.CreateUserView.as_view(), name='create'), path('logout/',views.LogoutView.as_view(), name='logout'), path('token/', views.CreateTokenView.as_view(), name='token'), path('me/', views. ManageUserView.as_view(), name='me'), path('login/', obtain_auth_token, name='login' ) ]
settings.py
LOGOUT_REDIRECT_URL = "/" ACCOUNT_LOGOUT_REDIRECT_URL = "/" REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', ], 'DEFAULT_SCHEMA_CLASS':'drf_spectacular.openapi.AutoSchema', 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', ), 'SWAGGER_SETTINGS' : { 'LOGIN_URL': 'rest_framework:login', 'LOGOUT_URL': 'rest_framework:logout' } }
views.py
class AnimalViewSet(viewsets.ModelViewSet): """ 该API端点用于查看动物描述。 - 查看特定动物,在URL后附加[/id](/api/animal/1/)。 - 查看某分类下的所有动物,使用[/category/id](/api/categories/1/)。 """ queryset = Animal.objects.all().order_by('name') serializer_class = AnimalSerializer permission_classes = ( IsAuthenticated, ) class CategoryViewSet(viewsets.ModelViewSet): """ 该API端点用于查看动物分类。 所有分类包含其直接子分类和动物。 - 查看特定分类,在URL后附加[/id](/api/categories/1/)。 - 获取所有顶级分类使用[/main_groups](/api/categories/main_groups)。 """ def get_serializer_class(self): if hasattr(self, 'action') and self.action == 'main_groups': return MainGroupSerializer return CategorySerializer queryset = Category.objects.all().order_by('name') queryset = CategorySerializer.eager_load(queryset) serializer_class = get_serializer_class(super) permission_classes = (IsAuthenticated, )
解决方法
问题核心:默认的LogoutView仅清除Session会话,不会删除DRF的Token令牌,导致用户仍可通过Token访问接口。
1. 自定义登出视图,删除用户Token
修改views.py,添加自定义LogoutView来删除当前用户的AuthToken:
from rest_framework.authtoken.models import Token from django.contrib.auth import logout from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status class LogoutView(APIView): def post(self, request): # 删除当前用户关联的Token Token.objects.filter(user=request.user).delete() # 清除Session会话 logout(request) return Response({"detail": "登出成功"}, status=status.HTTP_200_OK)
2. 修正URL配置
确保登出接口使用POST方法(GET方法不安全且不符合REST规范),urls.py保持原有配置即可,确保指向自定义的视图。
3. 调整前端登出请求方式
前端点击登出按钮时,需发送POST请求到/logout/接口。如果使用Swagger,需确保SWAGGER_SETTINGS中的LOGOUT_URL指向自定义的POST接口,或调整Swagger按钮的请求行为为POST。
4. 可选:优化认证配置(按需调整)
如果API仅使用Token认证,可在settings.py中调整认证类顺序或移除SessionAuthentication:
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.TokenAuthentication', # 不需要的话可注释以下两行 # 'rest_framework.authentication.BasicAuthentication', # 'rest_framework.authentication.SessionAuthentication', ], # 其他配置不变 }
验证效果
修改完成后,触发登出会看到类似日志:
[18/May/2023 XX:XX:XX] "POST /logout/ HTTP/1.1" 200 XX
此时再访问/api/categories/会返回401未认证,说明登出生效。
内容的提问来源于stack exchange,提问作者mightycode Newton
相关产品推荐
相关产品推荐

