You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Django自定义JWT认证类未遵循AllowAny权限,过期Token拦截问题求助

问题根源分析

你的问题出在Django REST Framework的执行顺序上:DRF会先执行认证类的authenticate方法,完成认证逻辑后才会检查视图的权限类。也就是说,哪怕你的GoogleLogin视图设置了AllowAny,只要认证类在处理过期token时抛出了异常,DRF就会直接返回这个异常的响应,根本不会走到权限检查的环节。

你的JWTAuthentication类在捕获到ExpiredSignatureError时,直接抛出了ParseError('Token has expired'),这就导致带过期token的请求在认证阶段就被拦截,无法进入视图处理登录逻辑。

解决方案

我们需要调整认证类的逻辑:当遇到过期的auth_token时,不要抛出异常,而是返回None(表示认证失败)。这样DRF会继续执行到权限检查环节,AllowAny权限类会允许请求进入视图,而其他需要认证的视图(比如使用IsAuthenticated的视图)则会因为认证失败被拒绝访问,符合预期。

修改后的认证类代码

def get_authorization_header(request):
    raw_token = request.COOKIES.get('auth_token', ) or None
    auth = request.META.get('HTTP_AUTHORIZATION', )
    if isinstance(auth, str):
        auth = auth.encode(HTTP_HEADER_ENCODING)
    return auth

class JWTAuthentication(BaseAuthentication):
    keyword = 'auth_token'
    def authenticate(self, request):
        raw_token = request.COOKIES.get('auth_token', ) or None
        if raw_token is None:
            return None
        try:
            return self.authenticate_credentials(raw_token)
        except jwt.ExpiredSignatureError:
            # 过期token返回None,让权限类处理后续逻辑
            return None

    def authenticate_credentials(self, key):
        user_model = get_user_model()
        try:
            payload = jwt.decode(key, settings.SECRET_KEY, algorithms="HS256")
            user = user_model.objects.get(email=payload['email'])
        except jwt.DecodeError:
            raise exceptions.ParseError('Invalid token')
        except user_model.DoesNotExist:
            raise exceptions.ParseError('Invalid token')
        if not user.is_active:
            raise exceptions.AuthenticationFailed('User inactive or deleted')
        return (user, payload)

    def authenticate_header(self, request):
        return self.keyword

关键修改点说明

  1. authenticate方法中,新增对jwt.ExpiredSignatureError的捕获,遇到过期token时直接返回None,跳过异常抛出。
  2. 把原authenticate_credentials中的ExpiredSignatureError捕获逻辑移到了authenticate方法中,这样过期token不会触发错误响应,而是进入权限检查流程。
  3. 保留了对无效token(解码失败、用户不存在)的异常抛出,确保这些情况仍然会返回错误提示。

这样调整后,当请求携带过期的auth_token访问GoogleLogin视图时,认证类返回NoneAllowAny权限类会允许请求进入视图,你的登录逻辑就能正常执行,重新生成有效的JWT token并设置到cookie中。

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

火山引擎 最新活动