【问题标题】:Django custom user authentication is not working properlyDjango 自定义用户身份验证无法正常工作
【发布时间】:2015-10-04 16:48:48
【问题描述】:

我正在使用自定义用户身份验证模型,它使用电子邮件地址作为用户名并创建用户,但 即使密码 1 与密码 2 不同,注册也会成功完成。 我无法调试问题。

这里是 models.py 文件:

class UserManager(auth_models.BaseUserManager):
    def create_user(self, email, first_name, last_name, password):
            """
                Creates and saves a user with given email,
                first name, last name and password.
            """
            if not email:
                    raise ValueError("users must have an email address")

            user = self.model(
                    email=UserManager.normalize_email(email),
                    first_name=first_name,
                    last_name=last_name,
            )
            user.set_password(password)
            user.save(self._db)
            return user

    def create_superuser(self, email, first_name, last_name, password):
            """
                Creates and saves a super_user with given email,
                first name, last name and password.
            """
            if not email:
                    raise ValueError("users must have an email address")

            user = self.model(
                    email=UserManager.normalize_email(email),
                    first_name=first_name,
                    last_name=last_name,
            )
            user.is_admin = True
            user.set_password(password)
            user.save(self._db)
            return user



class User(auth_models.AbstractBaseUser):
    email = models.EmailField(unique=True)
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=20)
    joined_at = models.DateTimeField(auto_now_add=True)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['first_name', 'last_name', ]

    def get_full_name(self):
            return self.first_name + " " + self.last_name

    def get_short_name(self):
            return self.first_name

    def __str__(self):
            return self.get_full_name() + ", email= " + self.email

    @property
    def is_staff(self):
            return self.is_admin

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

    def has_module_perms(self, app_label):
            return True

    class Meta:
            verbose_name_plural = "users"

admin.py

class UserCreationForm(forms.ModelForm):
    """
        A form for creating new users. Includes all the required
        fields, plus a repeated password.
    """

    password1 = forms.CharField(label='password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='confirm password', widget=forms.PasswordInput)

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

    def clean_password(self):
            """
                check that the two password entries match
            """
            password1 = self.cleaned_data.get("password1")
            password2 = self.cleaned_data.get("password2")
            if password1 and password2 and password1 != password2:
                    raise forms.ValidationError("passwords don't match")
            return password2

    def save(self, commit=True):
            user = super(UserCreationForm, self).save(commit=False)
            user.set_password(self.cleaned_data["password1"])
            if commit:
                    user.save()
            return user


class UserChangeForm(forms.ModelForm):
    """
        A form for updating users. includes all the fields
        on the user, but replaces the password field with
        the admin's password hash display field.
    """

    password = ReadOnlyPasswordHashField()

    class Meta:
            model = User
            fields = ('first_name', 'last_name', 'email', 'password', 'is_active', 'is_admin')

    def clean_password(self):
            """
                Regardless of what the user provides, return the initial value.
                This is done here, rather than on the field, because the field
                does not have access to the initial value.
            """
            return self.initial["password"]

views.py

def register(request):
    args = {}
    args.update(csrf(request))
    if request.method == 'POST':
            form = UserCreationForm(request.POST)
            args['form'] = form
            if form.is_valid():
                    form.save()
                    return HttpResponseRedirect('/home/')
    else:
            args['form'] = UserCreationForm()
    return render_to_response('authentication/signup.html', args, context_instance=RequestContext(request))

【问题讨论】:

    标签: django django-models django-forms django-admin django-custom-user


    【解决方案1】:

    尝试将clean_password() 函数中存在的密码比较逻辑移至UserCreationForm 中的clean() 函数。

    clean_fieldname() 函数应在字段 fieldname 上运行,而不是在任何其他字段上运行。

    此外,当字段验证相互依赖时,放置验证逻辑的最佳位置是在 clean() 方法内。

    来自Django docs:

    我们一次对多个字段执行验证,因此 form 的 clean() 方法是执行此操作的好地方。

    在调用表单的clean() 方法时,所有个人 将运行字段清理方法(前两节),所以 self.cleaned_data 将填充任何幸存的数据,因此 远的。所以你还需要记住考虑到 您要验证的字段可能无法在初始状态下存活 单独的现场检查。

    代码:

    class UserCreationForm(forms.ModelForm):
        ...
    
        def clean(self):
            cleaned_data = super(UserCreationForm, self).clean()
            password1 = cleaned_data.get("password1")
            password2 = cleaned_data.get("password2")
            if password1 and password2 and password1 != password2:
                raise forms.ValidationError("passwords don't match")
            return cleaned_data 
    

    【讨论】:

    • 是的,它成功了!谢谢 !但为什么它以前不起作用?
    • 你真正的问题是方法名没有声明,我在回答中解释了。
    • @ShubhamGaurav 当您需要执行依赖于多个字段的验证时,您需要在self.cleaned_data 已完全生成时将逻辑放入clean() 函数中。在执行clean_password() 的代码时,可能会发生password1password2 字段仍然不在self.cleaned_data 字典中,从而不执行引发ValidationError 的代码。
    【解决方案2】:

    问题是,您没有“密码”字段, 您需要将方法名称更改为 clean_password1 或 clean_password2。

    您创建的方法 clean_password,永远不会被调用 因为没有叫密码的字段

    def clean_password1(self):
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("passwords don't match"")
        return password1
    

    【讨论】:

    • 不工作。即使密码不一样也能注册成功!
    • 您可以像 Rahul 所说的那样在 clean() 中验证这一点,但这里真正的问题是我所说的方法名称。
    • 还是不行!但是将逻辑移动到 clean() 绝对可以。 clean_password1() 或 clean_password2() 不起作用。
    • 可能,方法里面的逻辑有一些错误。我用我的代码再次编辑。现在试试..哈哈,我很抱歉之前没有理会内部逻辑。
    • 我已经尝试了所有方法,但它不起作用,除非逻辑在 clean() 方法中。
    猜你喜欢
    • 2015-02-16
    • 2022-12-22
    • 2013-03-04
    • 2016-10-25
    • 2016-11-09
    • 1970-01-01
    • 1970-01-01
    • 2018-07-24
    • 1970-01-01
    相关资源
    最近更新 更多