Python Django电子邮件登录/验证'用户为None',使用模型后端,自定义用户模型

brccelvz  于 2022-11-18  发布在  Go
关注(0)|答案(2)|浏览(187)

我尝试在www.example.com中进行电子邮件登录/验证views.py,但它返回“user is None”。我尝试仅使用电子邮件登录而不是用户名。如果我尝试使用电子邮件登录,它似乎会在views.py中显示“user is None”和自定义错误消息“invalid credentials”。
Django版本:3.0.4 //型号:自定义用户模型(AbstractBaseUser)-〉USERNAME_FIELD = '电子邮件' //后端:ModelBackend -〉使用电子邮件作为用户名
问题1:在www.example.com中的def登录Views.py返回“用户为None”//问题2:模型具有密码(默认)、密码1和密码2(均由UserCreationForm定义)
1.用户模型.py

from django.conf import settings
from django.contrib.auth import authenticate
from django.contrib.auth.models import AbstractBaseUser
from django.db import models
from django import forms
from django.utils import timezone

from .users_managers import UserManager

class User(AbstractBaseUser):
    USERNAME_FIELD = 'email'

    email = models.EmailField(
        verbose_name='email',
        max_length=255,
        db_index=True,
        unique=True,
    )
    password1 = PasswordModelField('password', max_length=50, error_messages={something},)
    password2 = PasswordModelField('password check', max_length=50, error_messages={something},)
    ...
    objects = UserManager()

    class Meta:
        db_table = 'users'
        verbose_name = 'user'
        verbose_name_plural = 'users'

1.用户表单.py

from django import forms
from django.contrib.auth import authenticate, get_user_model
from django.contrib.auth.forms import ReadOnlyPasswordHashField

from .users_models import User

class UserCreationForm(forms.ModelForm):
    password1 = forms.CharField(
        label='password',
        strip=False,
        widget=forms.PasswordInput(attrs={'placeholder': 'something'}),
        error_messages={something},
    )
    password2 = forms.CharField(
        label='password check',
        widget=forms.PasswordInput,
        error_messages={something},
    )

   class Meta:
        model = User
        fields = ('email', 'password1', 'password2', ... )
   ...
   def save(self, commit=True):
        user = super().save(commit=False)
        user.set_password(self.cleaned_data['password1']) # set_password

        if commit:
            user.save()
        return user

class UserLoginForm(forms.Form):
    email = forms.EmailField(
        label='email',
        max_length=255,
        widget=forms.TextInput(attrs={'autofocus': True}),
    )
    password = forms.CharField(
        label='password',
        strip=False,
        widget=forms.PasswordInput,
    )
  1. backend.py
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
# from django.contrib.auth.models import check_password
from django.contrib.auth.hashers import check_password

class EmailBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None):
        user_model = get_user_model()
        if '@' in username:
            kwargs = {'email': username}
        else:
            kwargs = {'username': username}
        try:
            user = user_model.objects.get(**kwargs)
            if user.check_password(password):
                return user
            else:
                return None
        except user_model.DoesNotExist:
            return None

    def get_user(self, id=None):
        user_model = get_user_model()
        try:
            return user_model.objects.get(pk=id)
        except user_model.DoesNotExist:
            return None
  1. settings.py
# AUTH_USER_MODEL = 'apps.User' # if I use this code, It returns errors. 

AUTHENTICATION_BACKENDS = [
    'apps.backend.EmailBackend',
    'django.contrib.auth.backends.ModelBackend',
]
  1. login.html
{% extends 'apps/base.html' %}
{% load static %}
{% block content %}
<div class="container">
    <h1>login</h1>
    {% if error %}
        <p>{{ error }}</p>
    {% endif %}
    <form method="POST" action="{% url 'login' %}">
        {% csrf_token %}
        {{ form.as_p }}
        <input type="submit" class="btn btn-primary" value="login">
    </form>
</div>
{% endblock %}
  1. views.py
from django import forms
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.template import loader
from django.contrib import auth, admin
from django.contrib.auth import login, authenticate
from django.contrib.auth.models import User, Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.contrib.redirects.models import Redirect
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponseRedirect
from django.apps import AppConfig

from apps.users_forms import UserCreationForm, UserLoginForm, UserChangeForm
from apps.users_models import User

@csrf_exempt
def signup(request):
    if request.method == 'POST':
        creation_form = UserCreationForm(request.POST)
        if creation_form.is_valid():
            creation_form.save()
            return redirect('index')
    else:
        creation_form = UserCreationForm()
    return render(request, 'signup.html', {'form': creation_form})

@csrf_exempt
def signin(request):
    if request.user.is_authenticated:
        return redirect(reverse('index'))
    if request.method == "POST":
        login_form = UserLoginForm(request.POST)

        if login_form.is_valid():
            username = login_form.cleaned_data['email'] # take email in form for username
            password = login_form.cleaned_data['password']
            user = authenticate(username=username, password=password)
            if user is not None: # not going here !!!
                if user.is_active:
                    login(request, user)
                    return redirect('index')
            else:
                return render(request, 'login.html', 
                    {'form': login_form, 'error': 'invalid credentials'}) 
                # errors here !!!!! always views.py returns this messages !!!!!
    else:
        login_form = UserLoginForm()
        return render(request, 'login.html', {'form': login_form})

我怎样才能解决这个问题?

lp0sw83n

lp0sw83n1#

试试这个

user = authenticate(email=email, password=password)

或使用检查密码

from django.contrib.auth.hashers import check_password

# inside view function
# ...
user = User.objects.get(email=email)
if check_password(password, user.password):
    if user.is_active:
        login(request, user)
# ...
pkln4tw6

pkln4tw62#

我对这个问题困惑了四天,问题是我,像你一样,我在使用user.save(),我看不出问题出在哪里,但我用调试的眼光看了看,结果发现如果你使用user.save(),它会以某种方式扰乱密码的哈希,别问我怎么会不知道。所以我用Django提供的user.create()方法解决了这个问题,效果非常好:

@api_view(['POST'])
def create_user(request):
    new_user = UserSerializer(data=request.data)
    if new_user.is_valid():
        user_saved = new_user.create(request.data)
        return Response('User {} created'.format(user_saved.username), 
                                           status=status.HTTP_200_OK)
    else:
        return Response('User not created', status=status.HTTP_200_OK)

我使用了类似的代码,但是您可以使用user.create()来完成您希望的操作。

相关问题