重写simplejwt validate函数报NoneType对象无id属性错误
错误原因
该异常由代码执行顺序逻辑错误导致:
- Django内置
authenticate()方法在用户名密码错误、用户不存在、用户被禁用等认证失败场景下,会直接返回None,而非用户实例。 - 现有代码拿到
authenticate()返回值后,未做任何有效性判断就直接调用RefreshToken.for_user(user)生成令牌、触发登录信号。当入参user为None时,for_user()内部会尝试读取用户id字段,直接触发'NoneType' object has no attribute 'id'错误。 - 现有代码将
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
相关产品推荐
相关产品推荐

