Django邮箱+用户名登录报错:'AnonymousUser' object has no attribute '_meta'
解决Django邮箱+用户名双登录中的AnonymousUser错误
问题重现
在Django项目中实现邮箱/用户名双登录功能,已在settings.py配置自定义认证后端AuthenticationEmailBackend和默认ModelBackend,但使用邮箱登录时触发错误:'AnonymousUser' object has no attribute '_meta',用户名登录正常。
相关配置与代码如下:
settings.py 配置
AUTHENTICATION_BACKENDS = ( "accounts.auth.AuthenticationEmailBackend", "django.contrib.auth.backends.ModelBackend", )
原视图代码
def login_view(request): if request.method == 'POST': email =request.POST['username'] password = request.POST['password'] user = authenticate(username=email, password=password) print(user) #if user is not None: login(request,user,backend="accounts.auth.AuthenticationEmailBackend") return redirect('/') else: pass return render(request,'accounts/login.html')
原自定义认证后端代码
class AuthenticationEmailBackend(object): def authenticate(self, username=None, password=None, **kwargs): UserModel = get_user_model() try: user = UserModel.objects.get(email=username) except UserModel.DoesNotExist: return None else: if user.check_password(password): return user return None def get_user(self, user_id): try: return User.objects.get(pk=user_id) except User.DoesNotExist: return None
错误原因
- 跳过用户有效性判断:视图中注释掉了
if user is not None:逻辑,当authenticate返回None(邮箱不存在或密码错误)时仍执行login,此时传入的user为None,login会创建AnonymousUser对象,但该对象不具备用户模型的_meta属性,触发报错。 - 硬编码依赖User模型:自定义后端的
get_user方法直接使用User.objects.get(),若项目使用自定义用户模型会引发查找错误,不符合Django最佳实践。 - 强制指定后端冗余:
login时手动指定后端,忽略了authenticate返回用户自带的_backend标识,可能导致认证上下文不匹配。
修复方案
1. 恢复用户非空验证逻辑
执行login前必须判断user是否有效,避免传入None。
2. 修正自定义后端的get_user方法
使用get_user_model()动态获取用户模型,兼容默认及自定义用户模型场景。
3. 移除login时的手动后端指定(可选)
authenticate会自动遍历配置的后端,返回验证通过的用户并绑定对应后端标识,无需手动指定。
修正后的完整代码
修正后的视图代码
def login_view(request): if request.method == 'POST': input_value = request.POST['username'] password = request.POST['password'] user = authenticate(username=input_value, password=password) if user is not None: login(request, user) return redirect('/') # 可添加登录失败提示逻辑 return render(request,'accounts/login.html')
修正后的自定义认证后端代码
from django.contrib.auth import get_user_model class AuthenticationEmailBackend(object): def authenticate(self, username=None, password=None, **kwargs): UserModel = get_user_model() try: user = UserModel.objects.get(email=username) except UserModel.DoesNotExist: return None if user.check_password(password): return user return None def get_user(self, user_id): UserModel = get_user_model() try: return UserModel.objects.get(pk=user_id) except UserModel.DoesNotExist: return None
注:若希望自定义后端仅处理邮箱登录,保留上述
authenticate逻辑即可,默认ModelBackend会自动处理用户名登录,配置的后端列表会按顺序依次验证。
内容的提问来源于stack exchange,提问作者Armin P
相关产品推荐
相关产品推荐

