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

在Django中使用JWT认证实现登出:解决token仍可用的问题

DRF + Simple JWT 登出后黑名单Token仍生效的解决办法

1. 检查核心配置是否正确

首先确认Simple JWT的黑名单模块已正确配置:

  • 在INSTALLED_APPS中添加rest_framework_simplejwt.token_blacklist
  • 在项目配置中开启黑名单功能:
    SIMPLE_JWT = {
        'BLACKLIST_AFTER_ROTATION': True,
        # 其他JWT配置...
    }
    
  • 确保DRF的认证类配置包含Simple JWT的认证器:
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework_simplejwt.authentication.JWTAuthentication',
            # 其他认证类...
        ],
    }
    

2. 修正登出接口逻辑

不要手动创建BlacklistedToken记录,必须使用Simple JWT内置的blacklist()方法处理Refresh Token:

from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework.response import Response
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def logout(request):
    try:
        # 从请求体获取refresh token
        refresh_token = request.data.get("refresh")
        if not refresh_token:
            return Response({"error": "Refresh token required"}, status=400)
        
        token = RefreshToken(refresh_token)
        # 调用内置方法加入黑名单
        token.blacklist()
        return Response(status=205)
    except Exception as e:
        return Response({"error": str(e)}, status=400)

该方法会自动关联OutstandingToken并生成有效的黑名单记录,避免手动操作导致的关联缺失。

3. 验证黑名单记录是否正确生成

通过Django Shell确认Token已被加入黑名单:

from rest_framework_simplejwt.token_blacklist.models import BlacklistedToken, OutstandingToken

# 查询目标refresh token对应的OutstandingToken
outstanding_token = OutstandingToken.objects.filter(token__exact="你的refresh_token").first()
if outstanding_token:
    # 检查是否已加入黑名单
    is_blacklisted = BlacklistedToken.objects.filter(token=outstanding_token).exists()
    print(f"Token是否在黑名单: {is_blacklisted}")
else:
    print("未找到对应的OutstandingToken,可能token已过期或未被正确记录")

如果OutstandingToken不存在,说明该Refresh Token已过期或从未被系统记录,此时无法加入黑名单。

4. 处理Access Token的即时失效问题

注意:Simple JWT的黑名单默认只限制Refresh Token和后续生成的Access Token,已签发的Access Token在过期前仍会生效(出于性能考虑,默认不实时校验Access Token的黑名单)。

若需要让Access Token立即失效,可通过以下方式实现:

  1. 在用户模型中添加last_logout字段:
    from django.db import models
    from django.contrib.auth.models import AbstractUser
    from django.utils import timezone
    
    class CustomUser(AbstractUser):
        last_logout = models.DateTimeField(null=True, blank=True)
    
  2. 自定义认证类,校验Access Token的签发时间是否早于用户的登出时间:
    from rest_framework_simplejwt.authentication import JWTAuthentication
    from rest_framework.exceptions import AuthenticationFailed
    
    class CustomJWTAuthentication(JWTAuthentication):
        def authenticate(self, request):
            user, token = super().authenticate(request)
            if user.last_logout and token.payload['iat'] < user.last_logout.timestamp():
                raise AuthenticationFailed("Token已失效")
            return user, token
    
  3. 在DRF配置中替换默认认证类为自定义类,并在登出接口更新last_logout:
    # 登出接口中添加
    user = request.user
    user.last_logout = timezone.now()
    user.save()
    

5. 排查缓存影响

如果项目启用了缓存,可能导致Token校验结果被缓存,可在JWT配置中关闭缓存:

SIMPLE_JWT = {
    # 其他配置...
    'USE_CACHE': False,
}

或者手动清理缓存,确保新的黑名单规则生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 18:45:39