nev*_*ves 38 django django-1.5 django-allauth
我的目标是为我的Django站点的用户创建最简单的登录体验.我想象的是:
好的,这部分很简单,只需安装django-allauth并进行配置即可.
但我也想提供与本地用户一起使用该网站的选项.它还有另一个步骤:
好的,默认身份验证和allauth都可以做到.但现在是百万美元的问题.
如果他们更改登录方式,我该如何自动关联他们的Google,FB和本地帐户?
看到他们登录的方式,我有他们的电子邮件地址.是否有可能使用django-allauth?我知道我可以通过用户干预来做到这一点.今天,默认行为是拒绝登录,说明电子邮件已经注册.
如果不可能只进行配置,我会接受答案,这个答案给出了我应该在allauth代码中进行哪些修改以支持此工作流程的方向.
有很多理由这样做.用户将忘记他们用于进行身份验证的方法,有时会使用Google,有时使用FB,有时还会使用本地用户帐户.我们已经有很多本地用户帐户和社交帐户将是一个新功能.我希望用户保持自己的身份.我设想可以询问用户好友列表,所以如果他们使用Google登录,我也想拥有他们的FB帐户.
这是一个业余爱好网站,没有很好的安全要求,所以请不要回答这不是一个明智的安全实施.
稍后,我将创建一个自定义用户模型,将电子邮件作为登录ID.但我会很满意答案,让我自动关联具有所需用户名的默认用户模型的帐户.
我正在使用Django == 1.5.4和django-allauth == 0.13.0
ssp*_*oss 29
注意(2018-10-23):我不再使用它了.太多的魔法发生了.相反,我能SOCIALACCOUNT_EMAIL_REQUIRED和'facebook': { 'VERIFIED_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)
Run Code Online (Sandbox Code Playgroud)
据我所知,它似乎运作良好.但非常欢迎投入和建议!
els*_*sar 28
您需要覆盖sociallogin适配器,特别pre_social_login是在使用社交提供程序进行身份验证之后调用的方法,但是在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
Run Code Online (Sandbox Code Playgroud)
在您的设置中,将社交适配器更改为适配器
SOCIALACCOUNT_ADAPTER = 'myapp.my_adapter.MyAdapter`
Run Code Online (Sandbox Code Playgroud)
您应该能够以这种方式将多个社交帐户连接到一个用户.
根据babus对此相关主题的评论,上面提出的答案引入了一个很大的安全漏洞,在allauth docs中有记录:
"从Facebook文件中不清楚该帐户是否经过验证意味着该电子邮件地址也已经过验证.例如,验证也可以通过电话或信用卡进行.要在保险箱上方面,默认是将Facebook的电子邮件地址视为未经验证."
这样说,我可以使用您的电子邮件ID在Facebook注册或在Facebook上将您的电子邮件更改为您的电子邮件并登录该网站以访问您的帐户.
因此,考虑到这一点,并建立在@sspross答案的基础上,我的方法是将用户重定向到登录页面,并通知她/他的副本,并邀请他使用她/他的其他帐户登录,并链接他们一旦他们登录.我承认这与原始问题不同,但在这样做时,没有引入安全漏洞.
因此,我的适配器看起来像:
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'))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9701 次 |
| 最近记录: |