django - 如何在 Django 中存储和验证不同的用户类型?
问题描述
有两种不同类型的用户,A 和 B。A 类型的用户使用用户名和密码进行身份验证,而 B 类型的用户使用电子邮件和密码进行身份验证。该项目使用基于令牌的身份验证。
问题是:如何同时管理这两种用户类型?
我考虑过的方法:
为两种用户类型分离模型并实现自定义身份验证后端以验证使用电子邮件登录的用户
单用户模型可满足两种用户类型。但是,这意味着我必须添加附加字段(电子邮件)并为 A 类型的用户填充一些随机值
除此之外,我必须为登录用户存储一些自定义信息,如设备类型、位置等。是否可以覆盖 authtoken_token 表来存储这些信息,或者我必须为此创建一个单独的模型?
解决方案
以下实现应该可以工作(未经测试):
from rest_framework import serializers as rfs
from rest_framework.decorators import api_view
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
from django.contrib.auth import get_user_model
User = get_user_model()
### serializers.py
class UserSerializer(rfs.ModelSerializer):
class Meta:
model = User
fields = ["username", "email"]
class UserLoginSerializer(rfs.Serializer):
username = rfs.CharField(required=False)
email = rfs.EmailField(required=False)
password = rfs.CharField(style={"input_type": "password")
user = UserSerializer(read_only=True)
def validate(self, data):
username = data.get("username", None)
email = data.get("email", None)
# case: both were given
if username and email:
raise rfs.ValidationError("Only one of email or username should be given.")
# case none were given
elif (not username and not email):
raise rfs.ValidationError("One of email or username is required.")
elif username:
data["user"] = User.objects.get(username=username)
elif email:
data["user"] = User.objects.get(email=email)
return data
### views.py
@api_view(["POST"])
def login_view(request):
serializer = LoginSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response({
"token": token.key,
"user_id": user.pk,
})
说明:
基本上,我们创建了一个序列化程序,它只检查一个username
或email
是否POSTed
由用户进行。
对于你的第二个问题,
我必须为登录用户存储一些自定义信息,例如设备类型、位置等。
您可能可以创建一个模型,例如:
from django.db import models
from rest_framework.authtoken.models import Token
class UserTokenClient(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="token_client")
token = models.ForeignKey(Token, related_name="client")
## extra fields you want
device_type = models.CharField()
或者,您可以使用我编写的包 django-rest-durin
,它试图通过在每个和Client
之间关联一个模型来解决这个问题。User
Token
您可以轻松地Client
从 中子类化模型models.py
以添加您自己的自定义字段,如下所示:
from durin.models import Client
class CustomClient(Client):
## extra fields you want
device_type = models.CharField()
然后覆盖与此项目代码中的LoginView
完成方式类似的内容。