在 Django 项目中允许同时使用电子邮件和用户名登录

3
我正在为一所学校创建一个Django项目,有三种主要用户类型-家长、教师和学生。对于家长和教师,我想让他们使用电子邮件登录(他们目前正在使用遗留系统的电子邮件登录)。
但是,对于学生,我希望他们使用传统的用户名登录方法(因为年幼的孩子没有电子邮件)。在Django中是否可以实现这一点,或者只允许一个用户身份验证模型?

相关链接:https://dev59.com/RFoU5IYBdhLWcg3wjHhL,但你需要同时检查电子邮件和用户名。我建议你验证两者,并在返回两个用户时抛出错误(想象一下一个使用电子邮件作为用户名的用户)。 - Victor T
谢谢。因此,一个字段可以接受用户名和电子邮件。这样家长/老师将使用电子邮件,而孩子们将使用他们的用户名? - Dan Tang
5个回答

8
你可以创建单独的AuthenticationEmailBackend 用于通过电子邮件记录日志,并将其添加到设置中的AUTHENTICATION_BACKENDS。这样,如果之前的AUTHENTICATION_BACKENDS 认证失败,就会使用不同的AUTHENTICATION_BACKENDS 作为备选方案。 app/auth.py
from django.contrib.auth import get_user_model
from django.contrib.auth.models import User


class AuthenticationEmailBackend(object):
    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 getattr(user, 'is_active', False) and user.check_password(password):
                return user
        return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

settings.py

AUTHENTICATION_BACKENDS = (
    "django.contrib.auth.backends.ModelBackend",
    ...
    "app.auth.AuthenticationEmailBackend",
)

如果您将默认的django.contrib.auth.backends.ModelBackend保留在用户列表中,则用户可以通过用户名或电子邮件进行登录。

5

看起来从Django 1.11开始,在authenticate方法中需要请求参数:

def authenticate(self, request, username=None, password=None)

根据Django文档中所说。

1
请不要将“谢谢”作为答案。它们实际上并没有回答问题,而且可能会被未来的访问者视为噪音。一旦您获得足够的声望,您将获得特权,可以投票支持您喜欢的答案。这样,问题的未来访问者将看到该答案的更高投票数,并且回答者也将获得声望积分的奖励。请参见为什么投票很重要 - help-info.de
欢迎来到Stack Overflow!这并不是对问题的答案。如果要批评或请求作者澄清,请在他们发表的帖子下留言 - 您始终可以在自己的帖子上发表评论,并且一旦您拥有足够的声望,就可以在任何帖子上发表评论 - help-info.de

2

对于Django 3.0:

# myapp/backends.py

from django.contrib.auth.backends import BaseBackend

from .models import MyUser


class EmailAuthenticationBackend(BaseBackend):

def authenticate(self, request, **kwargs):
    email = kwargs['username'].lower()  # If you made email case insensitive add lower()
    password = kwargs['password']
    try:
        my_user = MyUser.objects.get(email=email)
    except MyUser.DoesNotExist:
        return None
    else:
        if my_user.is_active and my_user.check_password(password):
            return my_user
    return None

def get_user(self, user_id):
    try:
        return MyUser.objects.get(pk=user_id)
    except MyUser.DoesNotExist:
        return None

这适用于Django 2.0和可能的早期版本:
# myapp/backends.py

from django.contrib.auth.backends import ModelBackend

from .models import MyUser


class EmailAuthenticationBackend(ModelBackend):

    def authenticate(self, request, **kwargs):
        email = kwargs['username']
        password = kwargs['password']
        try:
            my_user = MyUser.objects.get(email=email)
        except MyUser.DoesNotExist:
            return None
        else:
            if my_user.is_active and my_user.check_password(password):
                return my_user
        return None

不确定扩展ModelBackend是否是一个好主意,你可以创建自己的类。

然后,对于两个版本:

# settings.py

AUTHENTICATION_BACKENDS = [
    "django.contrib.auth.backends.ModelBackend",
    "myapp.backends.EmailAuthenticationBackend",
]

2

一个简单的后端程序,可以让你使用电子邮件地址或用户名登录。

它应该与另一个用于检查权限的后端结合使用:

settings.py:

AUTHENTICATION_BACKENDS = (
    'myproject.accounts.backends.EmailOrUsernameModelBackend',
    'django.contrib.auth.backends.ModelBackend' )

account/backends.py:

from django.conf import settings
from django.contrib.auth.models import User

class EmailOrUsernameModelBackend(object):
    def authenticate(self, username=None, password=None):
        if '@' in username:
            kwargs = {'email': username}
        else:
            kwargs = {'username': username}
        try:
            user = User.objects.get(**kwargs)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

并且对于不区分大小写的情况:

class EmailOrUsernameModelBackend(object):
    def authenticate(self, username=None, password=None):
        # user_model = get_user_model()
        if '@' in username:
            # kwargs = {'email': username}
            field = 'email'
        else:
            # kwargs = {'username': username}
            field = 'username'
        try:

            case_insensitive_username_field = '{}__iexact'.format(field)
            user = User._default_manager.get(**{case_insensitive_username_field: username})

            # user = User.objects.get(**kwargs)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

0

在 models.py 中

class UserDet(models.Model):
       email = models.EmailField(max_length=20)
 
       userName = models.CharField(max_length=20) 

in views.py

def user_login(request):
    response_data={}
    if request.session.has_key('login_id'):  #If user already logedin send to dashboard else check userid and password
        return render(request, '/dashboard.html')
    else:
        if request.method == 'POST':  # If request method is post then only process request
            #print('here in login')
            try:

                username = request.POST.get('username')
                password = request.POST.get('pass')

                if '@' in username: #check for email
                    try:
                         
                        for u in UserDet.objects.filter(email=username):
                            #username=u['userName']
                            
                            username=u.userName
                    except:
                        response_data['code']=1000
                        response_data['status']='fail'
                        return HttpResponse(json.dumps(response_data), content_type="application/json")

                if not request.POST.get('rememberme', None):  # check user select the remember me or not if yes then create session that expire after long time
                    #print('seeing it 0')
                    request.session.set_expiry(0)
                 
                
                user = authenticate(username=username, password=password) # Check user exist or not
                
                if user:  #if user exist then
                    if user.is_active: #check user is active or not if active then successfully loged in else send error
                        login(request,user)
                        
                        update_last_login(None, user)
                        request.session['login_id'] = user.id
                        response_data['code']=800
                        response_data['status']='success'
                        return HttpResponse(json.dumps(response_data), content_type="application/json")
                        #return render(request, '/dashboard.html')
                    else:
                        response_data['code']=900  #Error for User is not active
                        response_data['status']='fail'
                        return HttpResponse(json.dumps(response_data), content_type="application/json")
                        #return HttpResponse("Your account was inactive.")
                else: #Error or Invalid username or password
                    #print("Someone tried to login and failed.")
                    #print("They used username: {} and password: {}".format(username,password))
                    response_data['code']=1000
                    response_data['status']='fail'
                    return HttpResponse(json.dumps(response_data), content_type="application/json")
            
            except:
                response_data['code']=1001
                response_data['status']='fail'
                return HttpResponse(json.dumps(response_data), content_type="application/json")
        else: #Return to index
                return redirect('/', {})


 

  

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接