Python Social Auth 为不同的用户复制电子邮件

Python Social Auth duplicating e-mails for different users

在我的网站上可以通过以下方式登录:

我在哪里使用系统内置的 django 用户和 python 社交身份验证。

问题:

假设我创建了以下帐户:

用户名:losimonassi 电子邮件:lorenzosimonassi@gmail.com

然后,当我尝试使用我的 gmail (lorenzosimonassi@gmail.com) 登录时,python 社交身份验证会使用相同的电子邮件创建另一个用户。因此,当我尝试使用我的电子邮件登录时,身份验证系统发现了两封相似的电子邮件,这引发了错误。

我正在尝试找到一种方法,当用户尝试使用 gmail 登录时,他的电子邮件将根据数据库进行检查,如果它已经存在,则该进程将通过重定向和警告消息停止(我认为它可以通过中间件实现)。

当然,对数据库的检查应该只对其他后端用户和普通用户进行检查,以避免阻止他自己的登录。

不想关联账号

settings.py

SOCIAL_AUTH_PIPELINE = (
    'social.pipeline.social_auth.social_details',
    'social.pipeline.social_auth.social_uid',
    'social.pipeline.social_auth.auth_allowed',
    'social.pipeline.social_auth.social_user',
    'social.pipeline.user.get_username',
    'social.pipeline.user.create_user',
    #'social.pipeline.social_auth.associate_user',
    #'social.pipeline.social_auth.load_extra_data',
    'social.pipeline.user.user_details'
)

admin image

你描述的情况我遇到过。我解决它的方式:向社交身份验证管道添加自定义步骤:

def check_email_exists(backend, details, uid, user=None, *args, **kwargs):
    email = details.get('email', '')
    provider = backend.name

    # check if social user exists to allow logging in (not sure if this is necessary)
    social = backend.strategy.storage.user.get_social_auth(provider, uid)
    # check if given email is in use
    exists = User.objects.filter(username=email).exists()

    # user is not logged in, social profile with given uid doesn't exist
    # and email is in use
    if not user and not social and exists:
        raise AuthException(backend)

将您的可调用对象添加到管道中:

SOCIAL_AUTH_PIPELINE = (
    'social.pipeline.social_auth.social_details',
    'social.pipeline.social_auth.social_uid',
    'social.pipeline.social_auth.auth_allowed',
    'social.pipeline.social_auth.social_user',
    'social.pipeline.user.get_username',
    'path.to.module.check_email_exists',  # move if appropriate
    'social.pipeline.user.create_user',
    'social.pipeline.user.user_details'
)

提高 AuthException 会将用户重定向到您的 settings.SOCIAL_AUTH_LOGIN_ERROR_URL。但是,如果这不是您想要的,还有另一种方法。 Python-social-auth 检查 return 管道任何部分的值。如果 return 值为 None,它就会继续。如果它是 dict,它将使用该字典更新 kwargs,以便这些值稍后在管道中可用。但是,如果 return 值为 HttpResponse,比如 HttpResponseRedirect,它将 return 响应给用户。所以,你可以做

而不是提高 AuthException
return HttpResponseRedirect(reverse('desired-endpoint'))

但是,请对此持保留态度:文档没有明确说明这一点,我很久以前就这样做过,所以我可能会弄错。

您可以选择通过在管道中添加一个内置但默认情况下不活动的步骤来通过电子邮件地址关联用户。 请注意,只有当您确定社交服务提供者验证了电子邮件地址时,您才应该这样做。否则我可以使用您的电子邮件注册社交提供商,登录您的网站并访问您网站上的用户。

Python 社交身份验证文档以及如何通过电子邮件关联用户: https://python-social-auth-docs.readthedocs.io/en/latest/use_cases.html?highlight=associate%20user#associate-users-by-email

从上面link:

SOCIAL_AUTH_PIPELINE = (
    'social_core.pipeline.social_auth.social_details',
    'social_core.pipeline.social_auth.social_uid',
    'social_core.pipeline.social_auth.auth_allowed',
    'social_core.pipeline.social_auth.social_user',
    'social_core.pipeline.user.get_username',
    'social_core.pipeline.social_auth.associate_by_email',  # <--- enable this one
    'social_core.pipeline.user.create_user',
    'social_core.pipeline.social_auth.associate_user',
    'social_core.pipeline.social_auth.load_extra_data',
    'social_core.pipeline.user.user_details',
)

编辑:正如杰克在评论中指出的那样,管道步骤的顺序很重要。