自定义AuthBackend后,无法使用Django的is_authenticated及@login_required问题求助
解决Django迁移PHP应用时自定义User模型无法使用@login_required的问题
问题描述
我有PHP开发背景,刚接触Django,正在把一款Web应用从PHP框架迁移到Django,必须保留原有数据库结构。我的User表结构和Django自带的auth.User模型不符,已经通过自定义AuthBackend完成了认证功能,但登录后使用@login_required装饰器时会报错:'User' object has no attribute 'is_authenticated'。我不想让User模型继承auth.AbstractUser或auth.AbstractBaseUser,因为要保留原表结构,该如何解决?
问题补充:自定义User模型代码
class User(models.Model): employee = models.ForeignKey(Employee, models.DO_NOTHING) user_role = models.ForeignKey(UserRole, models.DO_NOTHING, blank=True, null=True) username = models.CharField(max_length=50, blank=False, null=False) password = models.CharField(max_length=50, blank=True, null=True) created_on = models.DateTimeField() last_updated_on = models.DateTimeField(blank=True, null=True) last_password_change = models.DateTimeField(blank=True, null=True) status = models.IntegerField(db_comment='0-Deleted, 1-Active, 2-New') last_login = models.DateTimeField(blank=True, null=True) class Meta: managed = False db_table = 'user'
解决方案
1. 给自定义User模型添加is_authenticated属性
Django的@login_required装饰器依赖用户模型的is_authenticated属性(Django 1.10+已改为属性而非方法),直接在你的User模型中添加这个属性即可:
class User(models.Model): # 原有字段保持不变... employee = models.ForeignKey(Employee, models.DO_NOTHING) user_role = models.ForeignKey(UserRole, models.DO_NOTHING, blank=True, null=True) username = models.CharField(max_length=50, blank=False, null=False) password = models.CharField(max_length=50, blank=True, null=True) created_on = models.DateTimeField() last_updated_on = models.DateTimeField(blank=True, null=True) last_password_change = models.DateTimeField(blank=True, null=True) status = models.IntegerField(db_comment='0-Deleted, 1-Active, 2-New') last_login = models.DateTimeField(blank=True, null=True) class Meta: managed = False db_table = 'user' # 添加is_authenticated属性,根据业务逻辑判断用户是否已认证 @property def is_authenticated(self): # 这里以status=1(Active)作为已认证/活跃的判断条件 return self.status == 1
2. 补充兼容Django认证系统的必要属性(可选但推荐)
为了避免后续出现其他兼容性问题,建议添加Django认证系统预期的其他核心属性:
# 在User模型中继续添加以下属性 @property def is_active(self): # 与is_authenticated逻辑一致,判断用户是否处于活跃状态 return self.status == 1 @property def is_anonymous(self): # 自定义用户实例肯定不是匿名用户,固定返回False return False def get_username(self): # 返回模型中的username字段,匹配Django的预期接口 return self.username
3. 确保自定义AuthBackend返回正确的User实例
检查你的自定义认证后端,确保authenticate和get_user方法都返回这个自定义的User模型实例:
from django.contrib.auth.backends import BaseBackend from .models import User class CustomAuthBackend(BaseBackend): def authenticate(self, request, username=None, password=None, **kwargs): try: user = User.objects.get(username=username) # 注意:如果原PHP系统的密码是哈希存储,这里要替换成对应的哈希验证逻辑 if user.password == password and user.status == 1: return user except User.DoesNotExist: return None def get_user(self, user_id): try: return User.objects.get(pk=user_id) except User.DoesNotExist: return None
同时在settings.py中配置这个认证后端:
AUTHENTICATION_BACKENDS = [ 'your_app_name.backends.CustomAuthBackend', # 替换成你的实际路径 ]
4. 验证功能
现在重新启动服务,使用@login_required装饰器的视图应该可以正常工作了。
内容的提问来源于stack exchange,提问作者crishym
相关产品推荐
相关产品推荐

