django - Django Rest Auth - 社交视图的自定义注册逻辑
问题描述
我正在使用 Django Rest Framework 和 Django Rest Auth 构建一个 REST API。
我的用户有一个消费者资料。
class UserConsumerProfile(
SoftDeletableModel,
TimeStampedModel,
UniversallyUniqueIdentifiable,
Userable,
models.Model
):
def __str__(self):
return f'{self.user.email} ({str(self.uuid)})'
正如你所看到的,它由一些 mixin 组成,它们为它提供了一个 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 后发出第二个服务器请求,但这有点矫枉过正,并且会引入新的代码表面,从而导致更高的错误可能性.)
解决方案
简要看一下,DefaultAccountAdapter
您DefaultSocialAccountAdapter
可能有机会在您的 CustomAccountAdapter/CustomSocialAccountAdapter 中覆盖/实现 save_user(..) 以设置配置文件?
只看代码,似乎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 不适用于您的场景,适配器中还有一些其他“钩子”/功能可能值得我们研究。
推荐阅读
- c - C将char数组初始化为字符串,但尝试printf时为空
- ios - 尽管已正确初始化,XIB 视图仍不显示任何内容
- macos - Mac OS 上的新 Outlook 不会创建日志文件
- javascript - React:url中的props变量不收集数据
- python - 二维系统的欧拉方法
- windows - 与光标位置相关的奇怪的 Delphi IDE 行为
- node.js - 如何使用 angular 11 在 ionic.io 上创建全局组件?
- python - conda install package 命令不能每次都执行
- visual-studio-code - 更改语法突出显示提供程序
- python - 数据显示为带有 pandas.read_excel 的标题