首页 > 解决方案 > 如何在 Django 中存储和验证不同的用户类型?

问题描述

有两种不同类型的用户,A 和 B。A 类型的用户使用用户名和密码进行身份验证,而 B 类型的用户使用电子邮件和密码进行身份验证。该项目使用基于令牌的身份验证。

问题是:如何同时管理这两种用户类型?

我考虑过的方法:

除此之外,我必须为登录用户存储一些自定义信息,如设备类型、位置等。是否可以覆盖 authtoken_token 表来存储这些信息,或者我必须为此创建一个单独的模型?

标签: djangodjango-rest-framework

解决方案


以下实现应该可以工作(未经测试):

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,
    })

说明: 基本上,我们创建了一个序列化程序,它只检查一个usernameemail是否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之间关联一个模型来解决这个问题。UserToken

您可以轻松地Client从 中子类化模型models.py以添加您自己的自定义字段,如下所示:

from durin.models import Client

class CustomClient(Client):
    ## extra fields you want
    device_type = models.CharField()

然后覆盖与此项目代码中的LoginView完成方式类似的内容。


推荐阅读