我希望django通过电子邮件验证用户,而不是通过用户名.一种方法是提供电子邮件值作为用户名值,但我不希望这样.原因是,我有一个网址/profile/<username>/,因此我没有网址/profile/abcd@gmail.com/.
另一个原因是所有电子邮件都是唯一的,但有时会发生用户名.因此我将自动创建用户名为fullName_ID.
我怎样才能让Django通过电子邮件进行身份验证?
这就是我创建用户的方式.
username = `abcd28`
user_email = `abcd@gmail.com`
user = User.objects.create_user(username, user_email, user_pass)
Run Code Online (Sandbox Code Playgroud)
这是我登录的方式.
email = request.POST['email']
password = request.POST['password']
username = User.objects.get(email=email.lower()).username
user = authenticate(username=username, password=password)
login(request, user)
Run Code Online (Sandbox Code Playgroud)
除了首先获取用户名之外,还有其他任何登录信息吗?
mip*_*adi 75
您应该编写自定义身份验证后端.这样的东西会起作用:
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
class EmailBackend(ModelBackend):
def authenticate(self, username=None, password=None, **kwargs):
UserModel = get_user_model()
try:
user = UserModel.objects.get(email=username)
except UserModel.DoesNotExist:
return None
else:
if user.check_password(password):
return user
return None
Run Code Online (Sandbox Code Playgroud)
然后,在您的设置中将该后端设置为您的身份验证后端:
AUTHENTICATION_BACKENDS = ['path.to.auth.module.EmailBackend']
Run Code Online (Sandbox Code Playgroud)
更新.继承,ModelBackend因为它实现了get_user()已经的方法.
小智 29
如果您正在开始一个新项目,django强烈建议您设置自定义用户模型.(参见https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project)
如果您这样做,请在您的用户模型中添加三行:
class MyUser(AbstractUser):
USERNAME_FIELD = 'email'
email = models.EmailField(_('email address'), unique=True) # changes email to unique and blank to false
REQUIRED_FIELDS = [] # removes email from REQUIRED_FIELDS
Run Code Online (Sandbox Code Playgroud)
然后authenticate(email=email, password=password)工作,而authenticate(username=username, password=password)停止工作.
Him*_*ngh 22
Django 3.x 的电子邮件身份验证
为了使用电子邮件/用户名和密码进行身份验证而不是默认的用户名和密码身份验证,我们需要覆盖 ModelBackend 类的两个方法:authenticate() 和 get_user():
get_user 方法接受一个 user_id——它可以是用户名、数据库 ID 或其他任何东西,但必须是你的用户对象唯一的——并返回一个用户对象或 None。如果您没有将电子邮件作为唯一键保存,则必须处理为 query_set 返回的多个结果。在下面的代码中,这是通过从返回的列表中返回第一个用户来处理的。
from django.contrib.auth.backends import ModelBackend, UserModel
from django.db.models import Q
class EmailBackend(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 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
Run Code Online (Sandbox Code Playgroud)
默认情况下,AUTHENTICATION_BACKENDS 设置为:
['django.contrib.auth.backends.ModelBackend']
Run Code Online (Sandbox Code Playgroud)
在 settings.py 文件中,在底部添加以下内容以覆盖默认值:
AUTHENTICATION_BACKENDS = ('appname.filename.EmailBackend',)
Run Code Online (Sandbox Code Playgroud)
我有一个类似的要求,其中用户名/电子邮件应该用于用户名字段.如果有人正在寻找身份验证后端的方法,请查看以下工作代码.如果您只需要电子邮件,您可以更改查询集.
from django.contrib.auth import get_user_model # gets the user_model django default or your own custom
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
# Class to permit the athentication using email or username
class CustomBackend(ModelBackend): # requires to define two functions authenticate and get_user
def authenticate(self, username=None, password=None, **kwargs):
UserModel = get_user_model()
try:
# below line gives query set,you can change the queryset as per your requirement
user = UserModel.objects.filter(
Q(username__iexact=username) |
Q(email__iexact=username)
).distinct()
except UserModel.DoesNotExist:
return None
if user.exists():
''' get the user object from the underlying query set,
there will only be one object since username and email
should be unique fields in your models.'''
user_obj = user.first()
if user_obj.check_password(password):
return user_obj
return None
else:
return None
def get_user(self, user_id):
UserModel = get_user_model()
try:
return UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
return None
Run Code Online (Sandbox Code Playgroud)
还要在settings.py中添加AUTHENTICATION_BACKENDS =('path.to.CustomBackend',)
正如 Ganesh 上面针对 django 2.x 所提到的,身份验证方法现在需要一个请求参数。
# backends.py
from django.contrib.auth import backends, get_user_model
from django.db.models import Q
UserModel = get_user_model()
class ModelBackend(backends.ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
# user = UserModel._default_manager.get_by_natural_key(username)
# You can customise what the given username is checked against, here I compare to both username and email fields of the User model
user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
UserModel().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
return super().authenticate(request, username, password, **kwargs)
Run Code Online (Sandbox Code Playgroud)
将您的后端添加到您的项目设置中
# settings.py
AUTHENTICATION_BACKENDS = ['path.to.ModelBackend']
Run Code Online (Sandbox Code Playgroud)
您的自定义 User 模型需要为活跃和经过验证的用户创建独一无二的电子邮件,您可以简单地使用以下内容:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
objects = UserManager()
email = models.EmailField(_('email address'), unique=True)
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
db_table = 'auth_user'
swappable = 'AUTH_USER_MODEL'
Run Code Online (Sandbox Code Playgroud)
但是为了防止有人阻止其他人使用他们的电子邮件,您应该添加电子邮件验证,并让您的注册和登录过程考虑到电子邮件可能不是唯一的(并且可能阻止新用户使用现有的和经过验证的电子邮件地址)。
Django 2.X 的电子邮件和用户名认证
请记住,这是一个常见问题,这里有一个模仿Django 源代码的自定义实现,但它使用用户名或电子邮件对用户进行身份验证,不区分大小写,保持定时攻击 保护,而不是对非活动用户进行身份验证。
from django.contrib.auth.backends import ModelBackend, UserModel
from django.db.models import Q
class CustomBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try:
user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
except UserModel.DoesNotExist:
UserModel().set_password(password)
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
Run Code Online (Sandbox Code Playgroud)
永远记住将它添加到您的 settings.py 正确的Authentication Backend。
小智 5
Django 3.0 似乎已经更新了这样做的方法。
我的工作方法是:
authentication.py # <-- 我将其放在应用程序中(在项目文件夹中与 settings.py 一起不起作用)
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import BaseBackend
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User
class EmailBackend(BaseBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
UserModel = get_user_model()
try:
user = UserModel.objects.get(email=username)
except UserModel.DoesNotExist:
return None
else:
if user.check_password(password):
return user
return None
def get_user(self, user_id):
UserModel = get_user_model()
try:
return UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
return None
Run Code Online (Sandbox Code Playgroud)
然后将其添加到settings.py文件中
AUTHENTICATION_BACKENDS = (
'appname.authentication.EmailBackend',
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
37417 次 |
| 最近记录: |