Django REST Framework自定义用户模型下JWT令牌失效问题排查
DRF自定义User模型下JWT令牌验证失败排查方案
问题场景
已基于Django REST Framework实现JWT登录功能,使用自定义User模型,依赖库、settings.py配置均已完成,登录接口可正常返回access和refresh令牌,但用access令牌以Bearer方式在Postman访问带IsAuthenticated权限的BalanceAPI时,始终返回令牌无效/过期错误。
依赖与环境版本
- Python 3.11.6
- asgiref 3.7.2
- Django 5.0
- django-debug-toolbar 4.2.0
- djangorestframework 3.14.0
- djangorestframework-simplejwt 5.3.1
- PyJWT 2.8.0
错误响应
{ "detail": "Given token not valid for any token type", "code": "token_not_valid", "messages": [ { "token_class": "AccessToken", "token_type": "access", "message": "Token is invalid or expired" } ] }
排查与解决步骤
1. 适配自定义User模型的JWT配置
确保自定义User模型继承自AbstractUser或AbstractBaseUser,且settings.py中指定正确的用户模型与JWT关联字段:
# settings.py AUTH_USER_MODEL = 'your_app.YourCustomUser' SIMPLE_JWT = { 'USER_ID_FIELD': 'id', # 对应自定义User模型的主键字段,若用其他主键需修改 'USER_ID_CLAIM': 'user_id', }
同时确认模型已实现__str__方法,避免令牌生成时出现序列化异常。
2. 校验令牌签名与密钥一致性
检查settings.py中的SECRET_KEY是否在令牌生成和验证时完全一致,避免开发/测试环境密钥不匹配。simplejwt默认使用Django的SECRET_KEY签名,不要随意覆盖SIGNING_KEY配置,除非明确使用自定义密钥:
# 错误示例:若未确认自定义密钥,请勿添加该行 # SIMPLE_JWT = {'SIGNING_KEY': 'your_custom_key'}
3. 规范请求头格式
Postman中请求头必须严格遵循格式:
- 键:
Authorization - 值:
Bearer <你的access令牌>
注意Bearer与令牌之间有一个空格,避免小写拼写或多余空格导致验证失败。
4. 同步时间与校验令牌有效期
检查令牌有效期配置,确保测试时access令牌未过期:
# settings.py from datetime import timedelta SIMPLE_JWT = { 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5), # 默认5分钟,可临时延长用于测试 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), }
同时确认服务器与本地设备的系统时间一致,时间差过大可能导致令牌被判定为过期。
5. 配置DRF认证类
确保settings.py中DRF默认认证类包含JWT认证:
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework_simplejwt.authentication.JWTAuthentication', # 其他认证类按需保留 ], }
若BalanceAPI视图单独指定了认证类,需确保包含JWTAuthentication:
from rest_framework_simplejwt.authentication import JWTAuthentication from rest_framework.permissions import IsAuthenticated class BalanceAPI(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] # 视图逻辑
6. 手动解码验证令牌
在Django Shell中解码令牌,定位具体错误:
import jwt from django.conf import settings token = "你的access令牌" try: payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"]) print(payload) except jwt.ExpiredSignatureError: print("令牌已过期") except jwt.InvalidTokenError as e: print(f"令牌无效: {e}")
根据解码结果排查签名错误、字段缺失等问题。
内容的提问来源于stack exchange,提问作者dj-Yang
相关产品推荐
相关产品推荐

