我正在尝试为我的应用程序实现自定义用户模型和自定义身份验证 我能够创建模型并进行迁移。但是当我创建一个表单并实现了登录模板时,我收到了这个错误 -
login
User model with this Login already exists.
查看我正在验证用户的位置
from django.shortcuts import render_to_response, redirect, render
from django.template import RequestContext
from django.contrib.auth import login, logout , authenticate
from accounts.forms import AuthenticationForm
from django.contrib.auth.decorators import login_required
def accounts_login(request):
context = {}
if request.method == "POST":
form = AuthenticationForm(request.POST) #getting error here
print(form)
if form.is_valid():
user = authenticate(login = request.POST["login"], password = request.POST["password"])
if user is not None:
print(user)
login(request,user)
next_url = request.POST["next"]
return redirect(next_url, args=(), kwargs={})
#more code - not required here. Let me know if needed.
身份验证表单
from django import forms
from accounts.models import UserModel
class AuthenticationForm(forms.Form):
login = forms.CharField(max_length=128, required=True)
password = forms.CharField(max_length=128, required=True)
我的自定义用户模型和用户管理器 -
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.utils import timezone
from django.db.models import Max
class MyUserManager(BaseUserManager):
use_in_migrations = True
def create_user(self,login, parent_type, last_name, first_name, password):
return create_superuser(self,login, parent_type, last_name, first_name, password)
def create_superuser(self,login, parent_type, last_name, first_name, password):
maxx = self.model.objects.all().aggregate(Max('sys_id'))
print(maxx)
user = self.model(
sys_id = maxx["sys_id__max"] + 1,
login = login,
password = password,
parent_type = parent_type,
last_name = last_name,
first_name = first_name,
display_name = last_name + " " + first_name,
created_when = timezone.now()
)
user.save(using=self._db)
# no difference here...actually can set is_admin = True or something like that.
return user
class UserModel(AbstractBaseUser):
# custom user class
SYSTEM = 0
TENANT = 1
parent_type_choices = (
(SYSTEM, 'System'),
(TENANT, 'Tenant')
)
sys_id = models.BigIntegerField(primary_key=True, blank=True)
parent_type = models.PositiveIntegerField(choices=parent_type_choices, null=False, blank=False)
parent_sys_id = models.ForeignKey('tenant.TenantModel', on_delete = models.SET_NULL, null=True, blank=True)
last_name = models.CharField(null=False, blank=False, max_length=40)
first_name = models.CharField(max_length=40, null=False, blank=False)
display_name = models.CharField(max_length=80, unique=True, null=False, blank=True)
login = models.CharField(max_length=40, unique=True, null=False, blank=False)
authentication_method = models.CharField(max_length=80, null=True, blank=True)
access_valid_start = models.DateTimeField(null=True, blank=True)
access_valid_end = models.DateTimeField(null=True, blank=True)
created_when = models.DateTimeField(null=True, blank=True, )
created_by = models.BigIntegerField(null=True, blank=True)
last_updated_when = models.DateTimeField(null=True, blank=True)
last_updated_by = models.BigIntegerField(null=True, blank=True)
notes = models.CharField(max_length=2048, null=True, blank=True)
is_active = models.BooleanField(default=True)
objects = MyUserManager()
USERNAME_FIELD = "login"
# REQUIRED_FIELDS must contain all required fields on your User model,
# but should not contain the USERNAME_FIELD or password as these fields will always be prompted for.
REQUIRED_FIELDS = ['parent_type', 'last_name', 'first_name']
class Meta:
app_label = "accounts"
db_table = "Users"
def __str__(self):
return self.display_name
def get_full_name(self):
return self.display_name
def get_short_name(self):
return self.last_name
def check_password(self,password):
return True
if self.password ==password:
return true
自定义后端
from django.conf import settings
from accounts.models import UserModel
class MyAuthBackend(object):
def authenticate(self, login, password):
try:
user = UserModel.objects.get(login=login)
if user.check_password(password):
return user
else:
print("wrong password")
return None
except User.DoesNotExist:
return None
except Exception as e:
print(repr(e))
return None
def get_user(self, user_id):
try:
user = User.objects.get(pk=user_id)
if user.is_active:
return user
return None
except User.DoesNotExist:
return None
在setting.py
中添加了这两个变量AUTH_USER_MODEL = 'accounts.UserModel'
AUTHENTICATION_BACKENDS = ('accounts.backends.MyAuthBackend',)
从命令行获取后端
>>> get_backends()
[<accounts.backends.MyAuthBackend object at 0x7f2c438afe80>]
使用用户名的用户可以说xyz和密码&#39; ABC&#39;存在于db。中
1.当我尝试使用现有用户名和密码登录时,它会引发错误User model with this Login already exists.
2.当我尝试使用不存在的用户名和密码登录时(假设为xyz123),它会抛出错误authenticate() takes 0 positional arguments but 2 were given
我关注了多篇文章,但主要是django官方文档。阅读多篇文章以解决问题但失败了 请告诉我我做错了什么。
更新1:将AuthenticationForm从ModelForm切换到普通的Form类。错误1已解决
更新2:没有像丹尼尔指出的那样使用我的自定义后端,它没用,因为我没有做任何新的事情。因此也解决了错误2
更新3:现在在创建超级用户功能之前将用户保存到数据库之前进行哈希密码。 user.set_password(password)
答案 0 :(得分:1)
首先,您要在覆盖的create_superuser
方法中以纯文本格式存储密码。你绝对不能这样做。除了安全问题之外,它实际上不会起作用,因为身份验证后端会在将提交的密码与保存的版本进行比较之前对其进行哈希处理,因此它永远不会匹配。
其次,您的实际问题是您的AuthenticationForm是ModelForm;因此,它将尝试查看是否可以使用该电子邮件和密码创建用户。没有理由让它成为一个模型形式,你应该只有一个带有CharFields的简单表格用于电子邮件和密码。
请注意,在修复纯文本密码问题之前,您实际上无法登录。另请注意,您的自定义身份验证后端 - 以及通过不符合in the docs所描述的接口而违反身份验证方法 - 不执行内置程序不执行的任何操作;这是毫无意义的,你应该删除它。