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
相关产品推荐
相关产品推荐

