[英]Custom user model and custom authentication not working in django. Authentication form is not passing validation tests
我正在嘗試為我的應用程序實現自定義用戶模型和自定義身份驗證。
我能夠創建模型並進行遷移。 但是,當我創建表單並實現登錄模板時,出現此錯誤-
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>]
具有用戶名的用戶說db中存在xyz和密碼“ ABC”。
1.當我嘗試使用現有的用戶名和密碼登錄時,會拋出錯誤。 User model with this Login already exists.
名的User model with this Login already exists.
2.當我嘗試使用不存在的用戶名和密碼(讓我們說xyz123)登錄時,拋出錯誤error authenticate() takes 0 positional arguments but 2 were given
我關注了多篇文章,但主要是django官方文檔。 閱讀多篇文章以解決問題,但失敗了。
請提出我在做什么錯。
更新1:將AuthenticationForm從ModelForm更改為普通Form類。 錯誤1已解決。
更新2:不使用Daniel指出的自定義后端,它沒有用,因為我沒有在其中做任何新的事情。 因此,錯誤2也得以解決。
更新3:現在在創建超級用戶功能中將用戶保存到數據庫之前對密碼進行哈希處理。 user.set_password(password)
首先,您將密碼以純文本格式存儲在覆蓋的create_superuser
方法中。 您絕對不能這樣做 。 除了安全性問題外,它實際上不會起作用,因為身份驗證后端會在將提交的密碼與保存的版本進行比較之前對提交的密碼進行哈希處理,因此它永遠不會匹配。
其次,您的實際問題是您的AuthenticationForm是ModelForm。 這樣,它將嘗試查看是否可以使用該電子郵件和密碼創建用戶。 沒有理由使其成為模型形式,您應該只使用帶有CharFields的簡單形式來獲取電子郵件和密碼。
請注意,在解決了純文本密碼問題之前,您實際上將無法登錄。 還請注意,您的自定義auth后端-以及不符合docs中描述的接口而破壞了authenticate方法-不會執行內置操作無法執行的任何操作; 它沒有意義,應該將其刪除。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.