Django Rest Auth - Пользовательская логика регистрации для социальных представлений - PullRequest
0 голосов
/ 04 января 2019

Я создаю REST API с помощью Django Rest Framework и Django Rest Auth.

У моих пользователей есть профиль потребителя.

class UserConsumerProfile(
    SoftDeletableModel,
    TimeStampedModel,
    UniversallyUniqueIdentifiable,
    Userable,
    models.Model
):
    def __str__(self):
        return f'{self.user.email} ({str(self.uuid)})'

Как видите, он состоит из нескольких миксинов, которые дают ему UUID, отметку времени и обновленное поле, а также отношение OneToOne к пользователю.Я использую этот профайл потребителя в отношениях для связи данных с пользователем.

Этот профиль потребителя должен быть создан, как только пользователь зарегистрируется.

Вот сериализатор, который я написал для регистрации:

from profiles.models import UserConsumerProfile
from rest_auth.registration.serializers import RegisterSerializer

class CustomRegisterSerializer(RegisterSerializer):
    def custom_signup(self, request, user):
        profile = UserConsumerProfile.objects.create(user=user)
        profile.save()

Я подключил этот сериализатор в настройках:

REST_AUTH_REGISTER_SERIALIZERS = {
    "REGISTER_SERIALIZER": "accounts.api.serializers.CustomRegisterSerializer"
}

Он работает безупречно, когда пользователи регистрируются, используя его электронную почту.Но когда он регистрируется через Facebook, профиль потребителя не создается.

Я думал, что социальное представление также будет использовать сериализатор регистра при создании пользователей?Как запустить пользовательскую логику после регистрации в социальной сети?

РЕДАКТИРОВАТЬ для вознаграждения:

Вот настройки, которые я использую для Django Rest Auth:

# django-allauth configuration

ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_CONFIRM_EMAIL_ON_GET = True
ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = 1
ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = True
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
ACCOUNT_ADAPTER = 'accounts.adapter.CustomAccountAdapter'

SOCIALACCOUNT_ADAPTER = 'accounts.adapter.CustomSocialAccountAdapter'
SOCIALACCOUNT_PROVIDERS = {
    'facebook': {
        'METHOD': 'oauth2',
        'SCOPE': ['email', 'public_profile', 'user_friends'],
        'AUTH_PARAMS': {'auth_type': 'reauthenticate'},
        'INIT_PARAMS': {'cookie': True},
        'FIELDS': [
            'id',
            'email',
            'name',
            'first_name',
            'last_name',
            'verified',
            'locale',
            'timezone',
            'link',
            'gender',
            'updated_time',
        ],
        'EXCHANGE_TOKEN': True,
        'LOCALE_FUNC': 'path.to.callable',
        'VERIFIED_EMAIL': True,
        'VERSION': 'v2.12',
    }
}

# django-rest-auth configuration

REST_SESSION_LOGIN = False
OLD_PASSWORD_FIELD_ENABLED = True

REST_AUTH_SERIALIZERS = {
    "TOKEN_SERIALIZER": "accounts.api.serializers.TokenSerializer",
    "USER_DETAILS_SERIALIZER": "accounts.api.serializers.UserDetailSerializer",
}

REST_AUTH_REGISTER_SERIALIZERS = {
    "REGISTER_SERIALIZER": "accounts.api.serializers.CustomRegisterSerializer"
}

А вот пользовательские адаптеры (на случай, если они имеют значение):

from allauth.account.adapter import DefaultAccountAdapter
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from allauth.utils import build_absolute_uri
from django.http import HttpResponseRedirect
from django.urls import reverse


class CustomAccountAdapter(DefaultAccountAdapter):

    def get_email_confirmation_url(self, request, emailconfirmation):
        """Constructs the email confirmation (activation) url."""
        url = reverse(
            "accounts:account_confirm_email",
            args=[emailconfirmation.key]
        )
        ret = build_absolute_uri(
            request,
            url
        )
        return ret

    def get_email_confirmation_redirect_url(self, request):
        """
        The URL to return to after successful e-mail confirmation.
        """
        url = reverse(
            "accounts:email_activation_done"
        )
        ret = build_absolute_uri(
            request,
            url
        )
        return ret

    def respond_email_verification_sent(self, request, user):
        return HttpResponseRedirect(
            reverse('accounts:account_email_verification_sent')
        )


class CustomSocialAccountAdapter(DefaultSocialAccountAdapter):
    def get_connect_redirect_url(self, request, socialaccount):
        """
        Returns the default URL to redirect to after successfully
        connecting a social account.
        """
        assert request.user.is_authenticated
        url = reverse('accounts:socialaccount_connections')
        return url

Наконец, вот мнения:

from allauth.socialaccount.providers.facebook.views import \
    FacebookOAuth2Adapter
from rest_auth.registration.views import SocialConnectView, SocialLoginView


class FacebookLogin(SocialLoginView):
    adapter_class = FacebookOAuth2Adapter


class FacebookConnect(SocialConnectView):
    adapter_class = FacebookOAuth2Adapter

Я думал , что если бы я подключил сериализатор, как я это делал в начальной части вопроса, логика сериализатора регистра также запустится, когда кто-то зарегистрируется с помощью facebook.

Что мне нужно сделать, чтобы эта логика такжезапускать, когда кто-то регистрируется с помощью Facebook?

(Если я не могу это исправить, я могу сделать второй запрос к серверу после каждой регистрации на Facebook на стороне клиента, который создает userconsumerprofile, но это будет своего рода излишними введет новую поверхность кода, которая приведет к более высокой вероятности ошибок.)

Ответы [ 2 ]

0 голосов
/ 08 января 2019

Если коротко взглянуть на DefaultAccountAdapter и DefaultSocialAccountAdapter, это может быть возможностью переопределить / реализовать save_user (..) в вашем CustomAccountAdapter / CustomSocialAccountAdapter для настройки профиля?

Глядя только на код, кажется, что DefaultSocialAccountAdapter.save_user наконец вызовет DefaultAccountAdapter.save_user.

Нечто подобное может быть?

class CustomAccountAdapter(DefaultAccountAdapter):
    def save_user(self, request, user, form, commit=True):
        user = super(CustomAccountAdapter, self).save_user(request, user, form,
                                                           commit)
        UserConsumerProfile.objects.get_or_create(user=user)

        return user

В адаптерах есть несколько других "хуков" / функций, которые стоит изучить, если save_user не работает для вашего сценария.

0 голосов
/ 07 января 2019

Созданный вами REGISTER_SERIALIZER используется только RegisterView.Представления входа в систему и подключения к социальным сетям используют разные сериализаторы: SocialLoginSerializer и SocialConnectSerializer, которые не могут быть перезаписаны для настроек.

Я могу придумать два способа достижения желаемого поведения:

  • создать сериализаторы для входа в социальную сеть и подключить представления (наследуя сериализаторы по умолчанию) и установить их как serializer_class для представления,

  • использовать сигналы Джанго , особенно сигнал post_save для модели User, а когда экземпляр created, создайте UserConsumerProfile.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...