You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Rest Framework+Simple JWT:黑名单Token仍可访问API问题

问题分析

你当前只拉黑了refresh token,但处于有效期内的access token默认不会被Simple JWT的黑名单机制校验,因此仍能通过认证访问API。此外需要先确认黑名单功能的基础配置是否完整。

解决步骤

1. 确认黑名单基础配置

  • 确保INSTALLED_APPS中已添加黑名单应用:
    INSTALLED_APPS = [
        # ... 其他已有应用
        'rest_framework_simplejwt.token_blacklist',
    ]
    
  • 执行数据库迁移,生成黑名单相关数据表:
    python manage.py migrate
    

2. 登出时同时拉黑access token

修改LogoutAPIView,在拉黑refresh token的同时,提取并拉黑当前请求的access token:

from rest_framework.permissions import IsAuthenticated
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken, AccessToken

class LogoutAPIView(APIView):
    def post(self, request):
        refresh_token = request.data.get('refresh')
        # 从请求头提取Bearer格式的access token
        auth_header = request.headers.get('Authorization')
        access_token = auth_header.split(' ')[-1] if auth_header and auth_header.startswith('Bearer ') else None

        if refresh_token:
            try:
                # 拉黑refresh token
                refresh_token_obj = RefreshToken(refresh_token)
                refresh_token_obj.blacklist()
                
                # 拉黑access token(如果存在)
                if access_token:
                    access_token_obj = AccessToken(access_token)
                    access_token_obj.blacklist()
                
                return Response({'detail': 'Successfully logged out.'}, status=status.HTTP_200_OK)
            except Exception as e:
                return Response({'detail': 'Invalid token.'}, status=status.HTTP_400_BAD_REQUEST)
        else:
            return Response({'detail': 'Refresh token not provided.'}, status=status.HTTP_400_BAD_REQUEST)

3. 强制认证时检查access token黑名单

如果需要确保所有access token请求都校验黑名单,可自定义认证类替换默认的JWTAuthentication:

from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework_simplejwt.token_blacklist.models import OutstandingToken, BlacklistedToken

class BlacklistCheckedJWTAuthentication(JWTAuthentication):
    def authenticate(self, request):
        user_token_pair = super().authenticate(request)
        if not user_token_pair:
            return None
        
        user, token = user_token_pair
        # 检查当前token是否在黑名单中
        try:
            outstanding_token = OutstandingToken.objects.get(token=str(token))
            if BlacklistedToken.objects.filter(token=outstanding_token).exists():
                return None  # 认证失败,返回401
        except OutstandingToken.DoesNotExist:
            return None
        
        return user_token_pair

之后更新settings.py中的默认认证类:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'your_app_name.views.BlacklistCheckedJWTAuthentication',  # 替换为你的自定义类路径
    ]
}

或者仅在单个视图中使用该认证类:

class HelloView(APIView):
    authentication_classes = [BlacklistCheckedJWTAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request):
        user = self.request.user
        return Response(f"Hello, {user.username}!")

额外建议

  • 缩短ACCESS_TOKEN_LIFETIME,降低未拉黑access token的滥用风险:
    SIMPLE_JWT = {
        'ACCESS_TOKEN_LIFETIME': datetime.timedelta(minutes=15),  # 调整为15分钟
        # ... 其他原有配置
    }
    
  • 前端登出后需立即销毁本地存储的access token,避免重复提交无效请求。

内容的提问来源于stack exchange,提问作者MrHolmes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 22:35:00