【问题标题】:authenticate() not working properly for djangodjango 的 authenticate() 无法正常工作
【发布时间】:2020-12-13 15:56:56
【问题描述】:

到目前为止,我所做的基本上是创建一个注册页面,用户在其中输入用户名和密码,然后将该密码存储为哈希密码(md5 哈希)。我遇到的问题是登录。用户输入他们的用户名和密码,然后使用 django 中的 authenticate() 方法对密码进行身份验证。问题是 authenticate() 返回 None 而不是匹配数据库中的用户和密码。我不知道这是否会影响任何事情,但我正在使用 PostgreSQL。

models.py

class MyAccountManager(BaseUserManager):
    def create_user(self, email,username,first_name,password= None):
        if not email:
            raise ValueError('User must have an email address')
        if not username:
            raise ValueError('User must have a username')
        if not first_name:
            raise ValueError('User must have a first name')
        user= self.model(
            email=self.normalize_email(email),
            username= username,
            first_name= first_name
        )
        user.set_password(password)
        user.save(using=self._db)
        return user
    
    def create_superuser(self, email, username, first_name, password):
        user= self.create_user(
            email= self.normalize_email(email),
            username=username,
            first_name= first_name,
            password= password,
        )
        user.is_admin= True
        user.is_staff= True
        user.is_superuser= True
        user.save(using=self._db)
        return user
    
class User(AbstractBaseUser, models.Model):
    email = models.EmailField(verbose_name='email', max_length=60, unique=True)
    username = models.CharField(max_length=30, unique=True)
    date_joined = models.DateTimeField(auto_now_add=True, verbose_name='date joined')
    last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
    is_admin = models.BooleanField(default=False)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

    USERNAME_FIELD= 'username'
    REQUIRED_FIELDS= ['email','first_name']
    
    objects= MyAccountManager()
    def __str__(self):
        return self.email

    def has_perm(self, perm, obj=None):
        return self.is_admin

    def has_module_perms(self, app_label):
        return True

forms.py

class LoginForm(forms.Form):
    username = forms.CharField(initial='' ,label='Username:',max_length=30)
    password = forms.CharField(max_length=20, widget=forms.PasswordInput())
    class Meta:
        model = User
        fields = ('username', 'password')
    def clean(self):
        cleaned_data = super(LoginForm, self).clean()
        confirm_password = cleaned_data.get('password')



class SignUpForm(forms.ModelForm):
    first_name = forms.CharField(required= True,initial='',max_length=20)
    last_name = forms.CharField(required=True,max_length=30, initial='')
    username = forms.CharField(max_length=30,initial='', required=True)
    password = forms.CharField(max_length= 20, initial='', widget = forms.PasswordInput())
    password2= forms.CharField(max_length=20, initial='',widget = forms.PasswordInput())
    email = forms.EmailField(max_length=60, initial='',)

    class Meta:
        model = User
        fields = ('first_name', 'last_name','username','password2','email')

    def clean(self):
        cleaned_data = super(SignUpForm,self).clean()
        password = cleaned_data.get('password')
        confirm_password = cleaned_data.get('password2')
        if(password != confirm_password):
            raise forms.ValidationError(
                'Password and Confirm Password do not match.'
            )

views.py

def signin_and_signup(request):

    if request.method == 'POST':
        logout(request)
        sign_in = LoginForm(request.POST)
        signup = SignUpForm(request.POST)
        if 'sign-in-name' in request.POST:
            if sign_in.is_valid():
                username = request.POST.get('username')
                password= request.POST.get('password')
                user = authenticate(username= username, password= password)
                if user:
                    return HttpResponse('success')
                else:
                    return HttpResponse('fail')
        elif 'sign-up-input-name' in request.POST:
            if(signup.is_valid()):
                user = signup.save(commit=False)
                nonHashed = signup.cleaned_data['password']
                varhash =  make_password(nonHashed, None, 'md5')
                user.set_password(varhash)
                user.save()

            else:
                print("Ran3<------------")
                signup = SignUpForm()
    else:
        sign_in = LoginForm()
        signup = SignUpForm()
    context = {'signin':sign_in, 'signup':signup}
    return render(request, 'home.html', context)

【问题讨论】:

    标签: python django


    【解决方案1】:

    如果您具有相同的属性,为什么要替换 django 提供的用户模型? 如果您想为用户扩展或添加新属性,例如许可证号、头像、职位,则会执行此操作。

    无论如何,您的 authenticate() 可能不起作用,因为您尚未在 settings.py 中注册新模型。

    AUTH_USER_MODEL = 'name_of_the_app.User'
    

    我建议你看一下官方文档 https://docs.djangoproject.com/en/3.1/topics/auth/customizing/

    另一件事可能是您的身份验证后端:

    试试:

    settings.py

    AUTHENTICATION_BACKENDS = [
        'name_of_the_app.admin.LoginBackend',
    ]
    

    你想要的地方,例如 admin.py

    from django.contrib.auth.backends import ModelBackend, UserModel
    from django.db.models import Q
    
    
    class LoginBackend(ModelBackend):
        def authenticate(self, request, username=None, password=None, **kwargs):
            try:  # to allow authentication through phone number or any other field, modify the below statement
                user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
            except UserModel.DoesNotExist:
                UserModel().set_password(password)
            except MultipleObjectsReturned:
                return models.User.objects.filter(email=username).order_by('id').first()
            else:
                if user.check_password(password) and self.user_can_authenticate(user):
                    return user
        
        def get_user(self, user_id):
            try:
                user = UserModel.objects.get(pk=user_id)
            except UserModel.DoesNotExist:
                return None
    
            return user if self.user_can_authenticate(user) else None
    

    如您所见,您也可以使用电子邮件登录

    【讨论】:

    • 我的 settings.py 中已经有了 AUTH_USER_MODEL,这就是我很困惑的原因
    • @kixsmart 现在检查身份验证后端:
    • 是的,伙计,我知道问题是什么,没有任何效果。如果这有所不同,但密码用 md5 散列
    猜你喜欢
    • 2013-10-21
    • 2014-03-07
    • 2013-02-25
    • 2015-01-06
    • 1970-01-01
    • 1970-01-01
    • 2017-08-13
    • 2016-06-05
    相关资源
    最近更新 更多