我的目标是为我的Django站点的用户创建最简单的登录体验。我想像这样:
好的,这部分很简单,只需安装django-allauth并对其进行配置。
但我也想给与本地用户一起使用该网站的选项。它将再走一步:
好的,默认身份验证和allauth都可以做到。但是现在是百万美元的问题。
如果他们更改了登录方式,我如何自动将其Google,FB和本地帐户相关联?
看到他们以任何方式登录,我都有他们的电子邮件地址。是否可以使用django-allauth做到这一点?我知道我可以通过用户干预来做到这一点。今天,默认行为是拒绝登录,说电子邮件已经注册。
如果不可能仅通过配置来完成,我将接受给出答案的答案,该答案使我对应在allauth代码中进行哪些修改以支持此工作流程提供了一些指导。
这样做有很多原因。用户将忘记他们用来进行身份验证的方法,并且有时会使用Google,有时是FB以及有时是本地用户帐户。我们已经有很多本地用户帐户,社交帐户将成为一个新功能。我希望用户保持其身份。我设想可以询问用户朋友列表,因此,如果他们使用Google登录,我也希望拥有其FB帐户。
这是一个爱好网站,对安全性没有很高的要求,所以请不要回答这不是明智的安全性实现。
稍后,我将创建一个自定义用户模型,以仅将电子邮件作为登录ID。但是,我对一个答案很满意,那就是让我自动关联具有所需用户名的默认用户模型的帐户。
我正在使用Django == 1.5.4和django-allauth == 0.13.0
你将需要覆盖sociallogin适配器,特别是pre_social_login方法,该方法在与社交提供程序进行身份验证之后但在allauth处理此登录之前被调用。
在my_adapter.py,执行类似这样的操作
my_adapter.py
from django.contrib.auth.models import User from allauth.account.models import EmailAccount from allauth.exceptions import ImmediateHttpResponse from allauth.socialaccount.adapter import DefaultSocialAccountAdapter class MyAdapter(DefaultSocialAccountAdapter): def pre_social_login(self, request, sociallogin): # This isn't tested, but should work try: user = User.objects.get(email=sociallogin.email) sociallogin.connect(request, user) # Create a response object raise ImmediateHttpResponse(response) except User.DoesNotExist: pass
然后在你的设置中,将社交适配器更改为你的适配器
SOCIALACCOUNT_ADAPTER = 'myapp.my_adapter.MyAdapter`
而且你应该能够通过这种方式将多个社交帐户关联到一个用户。
我不再使用它了。发生了太多的魔术。相反,我启用了SOCIALACCOUNT_EMAIL_REQUIRED和'facebook': { 'VERIFIED_EMAIL': False, ... }。因此,allauth将在社交注册表单上重定向社交登录,以输入有效的电子邮件地址。如果已经注册,则会出现错误,请先登录然后再连接帐户。对我来说足够公平了。
SOCIALACCOUNT_EMAIL_REQUIRED和'facebook': { 'VERIFIED_EMAIL': False, ... }
我正在尝试改进这种用例,并提出了以下解决方案:
from allauth.account.models import EmailAddress from allauth.socialaccount.adapter import DefaultSocialAccountAdapter class SocialAccountAdapter(DefaultSocialAccountAdapter): def pre_social_login(self, request, sociallogin): """ Invoked just after a user successfully authenticates via a social provider, but before the login is actually processed (and before the pre_social_login signal is emitted). We're trying to solve different use cases: - social account already exists, just go on - social account has no email or email is unknown, just go on - social account's email exists, link social account to existing user """ # Ignore existing social accounts, just do this stuff for new ones if sociallogin.is_existing: return # some social logins don't have an email address, e.g. facebook accounts # with mobile numbers only, but allauth takes care of this case so just # ignore it if 'email' not in sociallogin.account.extra_data: return # check if given email address already exists. # Note: __iexact is used to ignore cases try: email = sociallogin.account.extra_data['email'].lower() email_address = EmailAddress.objects.get(email__iexact=email) # if it does not, let allauth take care of this new social account except EmailAddress.DoesNotExist: return # if it does, connect this new social login to the existing user user = email_address.user sociallogin.connect(request, user)
据我测试,它似乎运行良好。但是非常欢迎你提出意见和建议!