Django allauth社交登录:使用已注册的电子邮件自动链接社交网站配置文件
我的目标是为我的Django网站的用户创造一种最简单的登录体验。我想象的是:Django allauth社交登录:使用已注册的电子邮件自动链接社交网站配置文件,django,django-1.5,django-allauth,Django,Django 1.5,Django Allauth,我的目标是为我的Django网站的用户创造一种最简单的登录体验。我想象的是: 登录屏幕显示给用户 用户选择使用Facebook或Google登录 用户在外部站点中输入密码 用户可以作为经过身份验证的用户与我的站点交互 好的,这部分很简单,只需安装和配置它 但我也希望能让本地用户使用该网站。这将有另一个步骤: 登录屏幕显示给用户 用户选择注册 用户输入凭据 网站发送验证电子邮件 用户单击电子邮件链接,可以作为经过身份验证的用户与我的网站进行交互 好的,默认身份验证和allauth都可以做到。但现在
我正在使用Django==1.5.4和Django allauth==0.13.0我刚刚在源代码中找到了这条注释:
if account_settings.UNIQUE_EMAIL:
if email_address_exists(email):
# Oops, another user already has this address. We
# cannot simply connect this social account to the
# existing user. Reason is that the email adress may
# not be verified, meaning, the user may be a hacker
# that has added your email address to his account in
# the hope that you fall in his trap. We cannot check
# on 'email_address.verified' either, because
# 'email_address' is not guaranteed to be verified.
所以,设计是不可能的 您需要覆盖SocialIn适配器,特别是方法,该方法在与社交提供商进行身份验证后调用,但在allauth处理此登录之前调用 在
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`
您应该能够通过这种方式将多个社交帐户连接到一个用户。注意(2018-10-23):我不再使用它了。太多的魔法正在发生。相反,我启用了SOCIALACCOUNT\u EMAIL\u REQUIRED
和'facebook':{'VERIFIED\u EMAIL':False,…}
。因此,allauth将在社交注册表单上重定向社交登录,以输入有效的电子邮件地址。如果已经注册,则会显示一个错误,首先登录,然后连接帐户。对我来说很公平
我正在尝试改进这种用例,并提出了以下解决方案:
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)
就我所能测试的而言,它似乎工作得很好。但我们非常欢迎您的意见和建议
如果他们更改了登录方式,我如何自动关联他们的Google、FB和本地帐户
这是可能的,但您必须小心安全问题。检查场景:
根据babus的评论,在本次(,)之前发布的建议答案引入了一个巨大的安全漏洞,记录在allauth文档中: “从Facebook文档中不清楚帐户是否已验证是否意味着电子邮件地址也已验证。例如,也可以通过电话或信用卡进行验证。为了安全起见,默认情况下,将来自Facebook的电子邮件地址视为未经验证。” 这么说来,我可以用你的电子邮件ID在facebook上注册,或者在facebook上将我的电子邮件改为你的,然后登录到该网站以访问你的帐户 因此,考虑到这一点,在@sspross-answer的基础上,我的方法是将用户重定向到登录页面,并将副本通知她/他,并邀请他使用她/他的其他帐户登录,并在登录后链接他们。我承认这与原来的问题不同,但这样做不会引入安全漏洞 因此,我的适配器如下所示:
from django.contrib.auth.models import User
from allauth.account.models import EmailAddress
from allauth.exceptions import ImmediateHttpResponse
from django.shortcuts import redirect
from django.contrib import messages
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
class MyAdapter(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, bounce back to the login page
account = User.objects.get(email=email).socialaccount_set.first()
messages.error(request, "A "+account.provider.capitalize()+" account already exists associated to "+email_address.email+". Log in with that instead, and connect your "+sociallogin.account.provider.capitalize()+" account through your profile page to link them together.")
raise ImmediateHttpResponse(redirect('/accounts/login'))
django social auth正是你想要的东西。您可以将授权逻辑放在