Django JWT认证中间件报错:缺少必需参数'get_response'解决方法
问题解决:Django JWT中间件初始化错误
错误原因
你犯了一个关键错误:把Django中间件注册到了Django REST Framework(DRF)的认证类列表中。DRF的DEFAULT_AUTHENTICATION_CLASSES要求的是继承rest_framework.authentication.BaseAuthentication的认证类,而你的TokenMiddleware是标准的Django中间件,它的__init__方法需要get_response参数,但DRF实例化认证类时会调用无参构造,因此触发TypeError。
另外,你的中间件逻辑存在问题:当前会拦截所有请求,只要没有Bearer Token就直接返回错误,这会导致不需要认证的接口(比如登录、注册)也无法访问。
修复步骤
1. 移除错误的认证类注册
打开settings.py,删除REST_FRAMEWORK中DEFAULT_AUTHENTICATION_CLASSES里的'my_app.middleware.TokenMiddleware':
REST_FRAMEWORK = { # 移除错误的认证类注册 # 'DEFAULT_AUTHENTICATION_CLASSES': [ # 'my_app.middleware.TokenMiddleware', # ], 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', # Add other renderers as needed ] # Other DRF settings... }
2. 调整中间件逻辑,允许跳过认证的路径
修改TokenMiddleware,添加不需要认证的路径白名单,比如登录、注册接口:
import jwt from django.http import JsonResponse from django.conf import settings from django.utils.deprecation import MiddlewareMixin class TokenMiddleware(MiddlewareMixin): # 白名单:不需要认证的路径,可根据实际需求修改 EXEMPT_PATHS = ['/login/', '/register/'] def __call__(self, request): # 检查当前路径是否在白名单中,跳过认证 if request.path in self.EXEMPT_PATHS: return self.get_response(request) authorization = request.META.get('HTTP_AUTHORIZATION') if authorization and authorization.startswith('Bearer '): token = authorization.split(' ')[1] try: jwks_client = jwt.PyJWKClient(settings.JWT_VERIFY_URL) header = jwt.get_unverified_header(token) key = jwks_client.get_signing_key(header["kid"]).key jwt.decode(token, key, algorithms=[header["alg"]]) except jwt.ExpiredSignatureError: return JsonResponse({'error': 'Token has expired'}, status=401) except jwt.DecodeError: return JsonResponse({'error': 'Token is invalid'}, status=401) except Exception as e: # 捕获其他JWT相关异常 return JsonResponse({'error': str(e)}, status=401) else: return JsonResponse({'message': 'Authentication Bearer Token is required.'}, status=401) response = self.get_response(request) return response
3. 调整中间件顺序
修改MIDDLEWARE列表,将TokenMiddleware放到跨域中间件之后,避免跨域请求先被拦截:
MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "corsheaders.middleware.CorsMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "my_app.middleware.TokenMiddleware", ]
更优方案:使用DRF认证类替代中间件
如果是为DRF接口做JWT认证,更推荐遵循DRF的设计规范,编写专属的认证类而非中间件,这样能更好地和DRF的权限控制等功能集成:
import jwt from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed from django.conf import settings class JWTAuthentication(BaseAuthentication): def authenticate(self, request): authorization = request.META.get('HTTP_AUTHORIZATION') if not authorization or not authorization.startswith('Bearer '): raise AuthenticationFailed('Authentication Bearer Token is required.') token = authorization.split(' ')[1] try: jwks_client = jwt.PyJWKClient(settings.JWT_VERIFY_URL) header = jwt.get_unverified_header(token) key = jwks_client.get_signing_key(header["kid"]).key payload = jwt.decode(token, key, algorithms=[header["alg"]]) # 可根据payload中的信息获取并返回用户对象,比如: # user = User.objects.get(id=payload['user_id']) # return (user, token) return (None, token) # 无需绑定用户时返回此值 except jwt.ExpiredSignatureError: raise AuthenticationFailed('Token has expired') except jwt.DecodeError: raise AuthenticationFailed('Token is invalid') except Exception as e: raise AuthenticationFailed(str(e))
然后在settings.py中注册该认证类:
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'my_app.authentication.JWTAuthentication', # 替换为你的认证类实际路径 ], 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', ] }
内容的提问来源于stack exchange,提问作者Abdulaziz Ibrahim
相关产品推荐
相关产品推荐

