Django DRF实现登录数据库校验功能报错及优化方案咨询
错误原因
- 视图分支覆盖不全:当
serializer.is_valid()校验失败,或者coer_id存在但密码不匹配时,函数没有返回任何Response对象,最终返回None触发类型断言错误 - 序列化器参数取值错误:直接使用
serializer['coer_id']获取的是序列化器字段对象,而非客户端传入的实际值,需要从serializer.validated_data中取校验后的参数 - 校验逻辑错误:分开过滤coer_id和password的写法会导致只要数据库存在对应密码,任意coer_id都能登录,没有校验两个参数是否属于同一用户
- 额外安全隐患:当前代码明文存储密码,存在数据泄露风险
修复方案
修改views.py的check_login函数如下:
@api_view(['POST']) def check_login(request): serializer = login(data=request.data) # 处理参数校验失败的分支 if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) # 同时校验两个参数是否属于同一用户 user_exists = student_register.objects.filter( coer_id=serializer.validated_data['coer_id'], password=serializer.validated_data['password'] ).exists() if user_exists: return Response(serializer.data, status=status.HTTP_200_OK) # 用户名或密码错误统一返回401,避免暴露用户存在性 return Response(status=status.HTTP_401_UNAUTHORIZED)
可选优化建议:
- 序列化器重命名为
LoginSerializer,符合Python大驼峰命名规范 - 存储密码时使用Django自带的
make_password加密,校验时用check_password匹配,避免明文存储:
存密码示例:user.password = make_password(raw_password)
校验密码示例:user = student_register.objects.filter(coer_id=serializer.validated_data['coer_id']).first() if user and check_password(serializer.validated_data['password'], user.password): # 校验通过逻辑
同类登录校验的其他实现方式
- 基于Django原生认证系统实现:自定义用户模型继承
AbstractUser,替换默认用户表的用户名字段为coer_id,直接调用Django自带的authenticate(request, username=coer_id, password=password)方法完成校验,无需手动写过滤逻辑 - 基于Token的无状态登录:使用DRF生态的JWT工具实现令牌校验,或DRF自带的TokenAuthentication,登录成功后返回访问令牌,后续接口请求携带令牌即可完成身份校验,无需每次传递账号密码
- 封装为DRF认证类:将登录校验逻辑封装为自定义
BaseAuthentication子类,全局或局部配置到视图后,自动完成所有请求的身份校验,无需在每个视图函数重复写校验代码 - 第三方认证集成:对接OAuth2、短信验证码、扫码登录等认证方式,替换账号密码校验逻辑,适配不同业务场景
内容的提问来源于stack exchange,提问作者justjokingbro
相关产品推荐
相关产品推荐

