Django中的临时用户

时间:2018-11-07 10:22:46

标签: django

我想在我的项目中实现临时用户。原因是人们应该能够通过Facebook Oauth或Facebook Account Kit在我的应用程序中进行身份验证。

我有2个决定,但每个决定都不理想。

1)。创建用户和临时用户模型。第一个将具有有关常规用户+唯一数据库字段的所有信息。该临时用户将只有phone_numberfacebook_id。临时用户将在auth/端点上创建,并且响应将具有auth_token,以便以后可以在所有必需字段中进行注册。

问题是::如何确定用户是临时用户,而他的auth_token仅对registration/端点合法?

2)创建具有两种类型的基本用户模型:regulartemporary。该模型将仅具有常规字段。此外,还有与用户具有OneToOne关系的不同模型。只有类型为regular的用户才能拥有具有OneToOne关系的实例。

问题是:用户模型应具有USERNAME_FIELDREQUIRED_FIELDS才能通过管理面板登录+不同类型的用户应具有不同的管理员。

已更新

class User(AbstractBaseUser, TimeStampedModel, PermissionsMixin):
    is_regular = models.BooleanField(
        default=False
    )
    id = models.CharField(
        max_length=11,
        primary_key=True,
        default=custom_uuid,
        editable=False
    )
    phone_number = PhoneNumberField(
        null=True
    )
    facebook_id = models.CharField(
        max_length=255,
        null=True
    )

    objects = UserManager()
    USERNAME_FIELD = 'phone_number'
    REQUIRED_FIELDS = []

1 个答案:

答案 0 :(得分:1)

通过讨论,有很多方法可以解决此问题。但是将两种不同的模型用于身份验证是一个坏主意。因为Django Auth的设计是假设一个用户模型。

这就是我应该采取的方式:

  1. 我会使用Facebook的图形API存储facebook_id而不是使用email。创建密码时,我会使用唯一的UUID。
  2. 放置临时标记(模型布尔字段)以跟踪用户是否通过社交媒体注册。因此,当他尝试登录正常路径或注册时,我会知道他没有密码,因此我将向他发送以重置他的密码。成功重置密码后,我将删除该临时标记
  3. 其他绝对必要的信息,我将使用一个单独的模型来存储它们。例如:

    class Profile(models.Model):
        ...
        phone_number = models.CharField(max_length=30)
        user = models.OneToOneField(settings.AUTH_USER_MODEL)
    

    并登录后检查用户是否具有个人资料:

    if not hasattr(user, 'profile'):
         # redirect to more information page
    
  4. 对于其他访问管理网站的权限,应通过常规注册或社会注册来限制创建。对于这些用户,这些字段(is_staffis_superuser等默认情况下应为False。对于创建管理员用户,您可以使用createsuperuser命令。对于工作人员用户,您以后可以分配一个普通用户用户可以通过在管理员网站或is_staff上放置True标志Django Shell来进行人员配备。

更新(来自评论...)

您可以使用自定义后端来验证Facebook用户:

from django.contrib.auth.backends import ModelBackend
from django.db.models import Q

class CustomModelbackend(ModelBackend):
    def authenticate(self, phone_no=None, password=None, facebook_id=None, **kwargs):
        # Override
        UserModel = User
        try:
            user = UserModel.objects.get(Q(phone_no=phone_no) | Q(facebook_id=facebook_id))
            if password and user.check_password(password):   
                return user
            elif facebook_id:
                return user
        except Exception as e:
            # log exception

并将其添加到settings.py中的AUTHENTICATION_BACKENDS

AUTHENTICATION_BACKENDS = ['path.to.custom_backend.CustomBackend']

并调用如下所示的authenticate方法:

 authenticate(phone_no=phone_number, password=password)  # for normal auth
 authenticate(facebook_id=facebook_id)  # for social auth

但是您不能使您的phone_no唯一,因为有可能phone_no为空,无法用于社交登录,但是您可以将其放在USERNAME_FIELD中。因此,当您运行django开发人员服务器时,会看到警告( runserver 命令)

更新(2)

您可以尝试这样:

NORMAL_USER = "N"
OAUTH_USER = "O"
AT_USER = "A"
USER_TYPES=(
    (NORMAL_USER, 'Normal User'),
    (OAUTH_USER, 'Oauth User'),
    (AT_USER, 'Account Toolkit User')
)

class User(...):
    username = models.CharField(max_length=255, default=uuid.uuid4, unique=True)  # it might be unnecessary
    account_type = models.CharField(max_length=2, choices = USER_TYPES, default=NORMAL_USER)
    identifier = models.CharField(max_length=255)
    ...

    class Meta:
        unique_togather = ('account_type', 'identifier',)


# for Oauth Creation

User.objects.create(account_type=OAUTH_USER, identifier=facebook_id)  # or email

# for Toolkit Creation

User.objects.create(account_type=AT_USER, identifier=phone_number)

# For normal User
User.objects.create(identifier=username, username=username)

#backend, and does not need to use ModelBackend, it will work with adminsite
class CustomBackend(...):
    def authenticate(self, **kwargs):
        try:
            identifier= kwargs.get('username')
            password=kwargs.get('password')
            account_type=kwargs.get('account_type', NORMAL_USER)
            user = User.objects.get(identifier=identifier, account_type=account_type)
            if user.check_password(password):
                return user
        except Exception:
            # log exception

# authentication
from django.contrib.auth import authenticate
user = authenticate(username=identifier, password=password, account_type=OAUTH_USER)