一尘不染

Django allauth社交登录:使用注册的电子邮件自动链接社交网站配置文件

django

我的目标是为我的Django站点的用户创建最简单的登录体验。我想像这样:

  1. 登录屏幕显示给用户
  2. 用户选择使用Facebook或Google登录
  3. 用户在外部站点输入密码
  4. 用户可以通过身份验证的用户与我的网站进行交互

好的,这部分很简单,只需安装django-allauth并对其进行配置。

但我也想给与本地用户一起使用该网站的选项。它将再走一步:

  1. 登录屏幕显示给用户
  2. 用户选择注册
  3. 用户输入凭证
  4. 网站发送验证电子邮件
  5. 用户单击电子邮件链接,并可以通过身份验证的用户与我的网站进行交互

好的,默认身份验证和allauth都可以做到。但是现在是百万美元的问题。

如果他们更改了登录方式,我如何自动将其Google,FB和本地帐户相关联?

看到他们以任何方式登录,我都有他们的电子邮件地址。是否可以使用django-allauth做到这一点?我知道我可以通过用户干预来做到这一点。今天,默认行为是拒绝登录,说电子邮件已经注册。

如果不可能仅通过配置来完成,我将接受给出答案的答案,该答案使我对应在allauth代码中进行哪些修改以支持此工作流程提供了一些指导。

这样做有很多原因。用户将忘记他们用来进行身份验证的方法,并且有时会使用Google,有时是FB以及有时是本地用户帐户。我们已经有很多本地用户帐户,社交帐户将成为一个新功能。我希望用户保持其身份。我设想可以询问用户朋友列表,因此,如果他们使用Google登录,我也希望拥有其FB帐户。

这是一个爱好网站,对安全性没有很高的要求,所以请不要回答这不是明智的安全性实现。

稍后,我将创建一个自定义用户模型,以仅将电子邮件作为登录ID。但是,我对一个答案很满意,那就是让我自动关联具有所需用户名的默认用户模型的帐户。

我正在使用Django == 1.5.4和django-allauth == 0.13.0


阅读 526

收藏
2020-04-03

共2个答案

一尘不染

你将需要覆盖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

然后在你的设置中,将社交适配器更改为你的适配器

SOCIALACCOUNT_ADAPTER = 'myapp.my_adapter.MyAdapter`

而且你应该能够通过这种方式将多个社交帐户关联到一个用户。

2020-04-03
一尘不染

我不再使用它了。发生了太多的魔术。相反,我启用了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)

据我测试,它似乎运行良好。但是非常欢迎你提出意见和建议!

2020-04-03