Социальная аутентификация (dj_rest_auth) с пользователем с несколькими ролями

#user_model:

class User(AbstractUser, PermissionsMixin):

    class Role(models.TextChoices):
        SELLER = "seller"
        BUYER = "buyer"
        SUPER = "super"

    name = models.CharField(max_length=100)
    phone = models.CharField(max_length=15)
    email = models.EmailField()
    created_at = models.DateTimeField(default=timezone.now)
    shipping_address = models.CharField(max_length=100, blank=True, null=True)
    role = models.CharField(
        max_length=100, default=Role.SELLER.value, choices=Role.choices
    )
    updated_at = models.DateTimeField(default=timezone.now, null=True)
    first_name = None
    last_name = None
    profile_picture = models.ImageField(
        default="profile 1.jpg", upload_to="profile_images"
    )
    is_staff = models.BooleanField(default=False)
    is_blocked = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    is_superuser = models.BooleanField(default=False)
    username = models.CharField(max_length=30, unique=True)
    USERNAME_FIELD = "username"
    REQUIRED_FIELDS = ["email", "name", "role"]
    objects = myUserManager()
    class Meta:
        unique_together = [("email", "role"), ("phone", "role")]
        ordering = ["id"]
        db_table = "users"

Я реализовал dj_rest_auth с Google Authentication, и он функционирует так, как задумано. Однако возникает ограничение, когда он поддерживает только пользователей с одной ролью. Например, если мы создаем пользователя с ролью seller, он успешно создает учетную запись и входит в систему. Однако если мы попытаемся войти в систему с ролью пользователя, например покупатель, она ошибочно вернет пользователя-продавца и войдет вместо него.

#CustomSocialLoginSerializer:

import requests
from allauth.socialaccount.models import SocialAccount
from dj_rest_auth.registration.serializers import SocialLoginSerializer
from django.contrib.auth import get_user_model
from django.core.files.base import ContentFile
from rest_framework import serializers
from rest_framework.response import Response

User = get_user_model()


class CustomSocialSerializer(SocialLoginSerializer):
    role = serializers.ChoiceField(choices=User.Role.choices, required=True)

    def validate(self, attrs):
        attrs = super().validate(attrs)
        user = attrs["user"]
        role = attrs.get("role")
        if role:
            user.role = role
            user.username = User.generate_username(user.email, user.role)
            try:
                sociallogin = SocialAccount.objects.get(user=user)
                user.name = sociallogin.extra_data.get("name", "")
                picture = sociallogin.extra_data.get("picture", "")
                if picture:
                    response = requests.get(picture)
                    if response.status_code == 200:
                        user.profile_picture.save(
                            f"{user.name}_picture.jpg",
                            ContentFile(response.content),
                            save=True,
                        )
            except:
                return Response({"Message": "Failed to save extra Details !"})
            user.save()
        return attrs

#views.py:

class CustomLoginView(SocialLoginView):
    serializer_class = CustomSocialSerializer


class GoogleLogin(CustomLoginView):
    adapter_class = GoogleOAuth2Adapter
    callback_url = "/"
    client_class = OAuth2Client

Я обнаружил, что процесс аутентификации Google ищет UID аккаунта SocialAccount, и если находит совпадение, то просто регистрирует пользователя на основе этого ID. Как я могу изменить эту функциональность, чтобы добиться другого поведения?

    def _lookup_by_socialaccount(self):
        assert not self.is_existing
        try:
            a = SocialAccount.objects.get(
                provider=self.account.provider, uid=self.account.uid
            )
            # Update account
            a.extra_data = self.account.extra_data
            self.account = a
            self.user = self.account.user
            a.save()
            signals.social_account_updated.send(
                sender=SocialLogin, request=context.request, sociallogin=self
            )
            # Update token
            if app_settings.STORE_TOKENS and self.token:
                assert not self.token.pk
                try:
                    t = SocialToken.objects.get(
                        account=self.account, app=self.token.app
                    )
                    t.token = self.token.token
                    if self.token.token_secret:
                        # only update the refresh token if we got one
                        # many oauth2 providers do not resend the refresh token
                        t.token_secret = self.token.token_secret
                    t.expires_at = self.token.expires_at
                    t.save()
                    self.token = t
                except SocialToken.DoesNotExist:
                    self.token.account = a
                    self.token.save()
            return True
        except SocialAccount.DoesNotExist:
            pass
Вернуться на верх