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

重写simplejwt validate函数报NoneType对象无id属性错误

错误原因

该异常由代码执行顺序逻辑错误导致:

  1. Django内置authenticate()方法在用户名密码错误、用户不存在、用户被禁用等认证失败场景下,会直接返回None,而非用户实例。
  2. 现有代码拿到authenticate()返回值后,未做任何有效性判断就直接调用RefreshToken.for_user(user)生成令牌、触发登录信号。当入参user为None时,for_user()内部会尝试读取用户id字段,直接触发'NoneType' object has no attribute 'id'错误。
  3. 现有代码将USER_AUTHENTICATION_RULE校验放在令牌生成、信号发送之后,即便补全None判断,也会存在未通过认证规则的用户被生成令牌、错误触发登录信号的逻辑漏洞。
修复方法

调整validate方法内的执行顺序:优先完成用户身份校验,确认认证通过后再执行令牌生成、信号发送逻辑,修复后代码如下:

class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):

    def validate(self, attrs):
        authenticate_kwargs = {
            self.username_field: attrs[self.username_field],
            "password": attrs["password"],
        }
        try:
            authenticate_kwargs["request"] = self.context["request"]
        except KeyError:
            pass
        
        user = authenticate(**authenticate_kwargs)

        # 认证不通过直接抛异常,终止后续逻辑
        if not user or not api_settings.USER_AUTHENTICATION_RULE(user):
            raise exceptions.AuthenticationFailed(
                self.error_messages["no_active_account"],
                "no_active_account",
            )
        
        # 认证通过后再生成令牌、发送登录信号
        tokens = RefreshToken.for_user(user)
        request = self.context.get("request")
        if request:
            user_logged_in.send(sender=user.__class__, request=request, user=user)

        return {
            'refresh': str(tokens),
            'access': str(tokens.access_token),
            'user': str(user),
        }

核心修复点:

  • 将用户有效性校验前置,只要认证失败立刻抛出异常,不会执行后续依赖用户实例的逻辑
  • 读取request时使用get()方法做兼容,避免context无request字段时触发KeyError
  • 仅在用户确认认证成功后才触发user_logged_in信号,保证登录统计逻辑的准确性,不会统计登录失败的请求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 19:31:41