我能够使用 Django (1.6.4)、allauth (0.16.1) 和 Python (2.7) 成功通过 Google 和 Facebook 登录,并预期重定向到 settings.LOGIN_REDIRECT_URL,以防没有检索到电子邮件 ID 的现有用户来自提供商。但是,当已经存在与从提供商(fb 或 goolge)检索到的电子邮件 ID 相同的用户时,它总是重定向到 /accounts/social/signup/#= 注册页面,询问:
您将使用您的 Facebook/Google 帐户登录 example.com。作为 最后一步,请填写以下表格: 电子邮件是自动填写的。
我用
SOCIALACCOUNT_AUTO_SIGNUP = True
或False
测试过,但没有效果。我尝试更改 facebook 的 auth_type,但除了“重新请求”之外我没有看到任何选项
我有以下设置.py:
ACCOUNT_AUTHENTICATION_METHOD = "email" # Defaults to username_email
ACCOUNT_USERNAME_REQUIRED = False # Defaults to True
ACCOUNT_EMAIL_REQUIRED = True # Defaults to False
SOCIALACCOUNT_QUERY_EMAIL = ACCOUNT_EMAIL_REQUIRED
SOCIALACCOUNT_AUTO_SIGNUP = True
SOCIALACCOUNT_EMAIL_REQUIRED = False
ACCOUNT_ADAPTER = "myproject.adapter.MyLoginAccountAdapter"
LOGIN_URL = "/"
LOGIN_REDIRECT_URL = "/users/{id}/mytags"
如何停止此重定向到注册,并让提供商登录重定向到 LOGIN_REDIRECT_URL(特别是具有相同电子邮件 ID 的现有用户)?
注意:这个我已经尝试过了
更新:
@receiver(pre_social_login)
和
raise ImmediateHttpResponse
(看看我的答案)和有用的链接解决了这个问题:this 和 thisone
问题正在解决:我只是希望能够使用相同的电子邮件 ID 使用 facebook 和 google 互换登录,并在成功登录后始终重定向到 LOGIN_REDIRECT_URL,但 django-allauth 不允许我这样做。相反,它向我展示了一个我不想要的注册页面。
解决方案::使用 @receiver(pre_social_login)
调用函数
link_to_local_user()
,该函数首先登录,然后引发 ImmediateHttpResponse,后者又重定向到 LOGIN_REDIRECT_URL
#! myproject.adapter.py
from allauth.account.adapter import DefaultAccountAdapter
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from allauth.exceptions import ImmediateHttpResponse
from allauth.socialaccount.signals import pre_social_login
from allauth.account.utils import perform_login
from allauth.utils import get_user_model
from django.http import HttpResponse
from django.dispatch import receiver
from django.shortcuts import redirect
from django.conf import settings
import json
class MyLoginAccountAdapter(DefaultAccountAdapter):
'''
Overrides allauth.account.adapter.DefaultAccountAdapter.ajax_response to avoid changing
the HTTP status_code to 400
'''
def get_login_redirect_url(self, request):
"""
"""
if request.user.is_authenticated():
return settings.LOGIN_REDIRECT_URL.format(
id=request.user.id)
else:
return "/"
class MySocialAccountAdapter(DefaultSocialAccountAdapter):
'''
Overrides allauth.socialaccount.adapter.DefaultSocialAccountAdapter.pre_social_login to
perform some actions right after successful login
'''
def pre_social_login(self, request, sociallogin):
pass # TODOFuture: To perform some actions right after successful login
@receiver(pre_social_login)
def link_to_local_user(sender, request, sociallogin, **kwargs):
''' Login and redirect
This is done in order to tackle the situation where user's email retrieved
from one provider is different from already existing email in the database
(e.g facebook and google both use same email-id). Specifically, this is done to
tackle following issues:
* https://github.com/pennersr/django-allauth/issues/215
'''
email_address = sociallogin.account.extra_data['email']
User = get_user_model()
users = User.objects.filter(email=email_address)
if users:
# allauth.account.app_settings.EmailVerificationMethod
perform_login(request, users[0], email_verification='optional')
raise ImmediateHttpResponse(redirect(settings.LOGIN_REDIRECT_URL.format(id=request.user.id)))
#! settings.py
ACCOUNT_AUTHENTICATION_METHOD = "email" # Defaults to username_email
ACCOUNT_USERNAME_REQUIRED = False # Defaults to True
ACCOUNT_EMAIL_REQUIRED = True # Defaults to False
SOCIALACCOUNT_QUERY_EMAIL = ACCOUNT_EMAIL_REQUIRED
SOCIALACCOUNT_AUTO_SIGNUP = True
SOCIALACCOUNT_EMAIL_REQUIRED = False
ACCOUNT_ADAPTER = "myproject.adapter.MyLoginAccountAdapter"
SOCIALACCOUNT_ADAPTER = 'myproject.adapter.MySocialAccountAdapter'
LOGIN_URL = "/"
LOGIN_REDIRECT_URL = "/users/{id}/mytags"
我使用了@amulllb 答案,但它有点过时了。
以下内容针对 Django 4.2 和 AllAuth 0.61.1 进行更新和测试,特别是针对 microsoft oauth 提供程序,网址为
https://docs.allauth.org/en/latest/socialaccount/providers/microsoft.html
在适配器.py中
from allauth.account.adapter import DefaultAccountAdapter
from allauth.account.utils import perform_login
from allauth.exceptions import ImmediateHttpResponse
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from allauth.socialaccount.signals import pre_social_login
from allauth.utils import get_user_model
from django.conf import settings
from django.dispatch import receiver
from django.shortcuts import redirect
# change yourproject.exceptions accordingly
from yourproject.exceptions import EmailNotFoundException
"""
taken from
https://stackoverflow.com/a/24358708/80353
tested against django 4.2 allauth 0.61.1
must use these as settings
ACCOUNT_AUTHENTICATION_METHOD = "email" # Defaults to username_email
ACCOUNT_USERNAME_REQUIRED = False # Defaults to True
ACCOUNT_EMAIL_REQUIRED = True # Defaults to False
THE FOLLOWING ARE USING DEFAULT, so can choose not to set
SOCIALACCOUNT_QUERY_EMAIL = ACCOUNT_EMAIL_REQUIRED
SOCIALACCOUNT_AUTO_SIGNUP = True
SOCIALACCOUNT_EMAIL_REQUIRED = ACCOUNT_EMAIL_REQUIRED
# change yourproject.adapter accordingly
ACCOUNT_ADAPTER = "yourproject.adapter.MyLoginAccountAdapter"
SOCIALACCOUNT_ADAPTER = 'yourproject.adapter.MySocialAccountAdapter'
"""
class MyLoginAccountAdapter(DefaultAccountAdapter):
"""
Overrides allauth.account.adapter.DefaultAccountAdapter.ajax_response to avoid changing
the HTTP status_code to 400
"""
def get_login_redirect_url(self, request):
"""
get the redirect login
"""
if request.user.is_authenticated:
return settings.LOGIN_REDIRECT_URL.format(id=request.user.id)
else:
return "/"
class MySocialAccountAdapter(DefaultSocialAccountAdapter):
"""
Overrides allauth.socialaccount.adapter.DefaultSocialAccountAdapter.pre_social_login to
perform some actions right after successful login
"""
def pre_social_login(self, request, sociallogin):
pass # TODOFuture: To perform some actions right after successful login
@receiver(pre_social_login)
def link_to_local_user(sender, request, sociallogin, **kwargs):
"""Login and redirect
This is done in order to tackle the situation where user's email retrieved
from one provider is different from already existing email in the database
(e.g facebook and google both use same email-id). Specifically, this is done to
tackle following issues:
* https://github.com/pennersr/django-allauth/issues/215
"""
# Most oauth providers use "email"
# but for microsoft graph uses "mail"
# Check for 'email' or 'mail' in sociallogin.account.extra_data
email_address = sociallogin.account.extra_data.get(
"email"
) or sociallogin.account.extra_data.get("mail")
if not email_address:
# If neither is found, raise the custom exception
raise EmailNotFoundException()
User = get_user_model()
if users := User.objects.filter(email=email_address):
# allauth.account.app_settings.EmailVerificationMethod
perform_login(request, users[0], email_verification="optional")
raise ImmediateHttpResponse(
redirect(settings.LOGIN_REDIRECT_URL.format(id=request.user.id))
)
在例外情况.py
class EmailNotFoundException(Exception):
"""Exception raised when email is not found in social login data."""
def __init__(self, message="Email or mail not found in social login data"):
self.message = message
super().__init__(self.message)
这与@amulllb 的答案有何不同?is_authenticated()
而我更改为 .is_authenticated 因为 Django 停止使用 is_authenticated 作为方法一段时间了。
email_address = sociallogin.account.extra_data['email']
,而我检查了
email
和
mail
。
mail
是 Microsoft Graph 返回的内容。我还添加了一个例外,以防提供者既不使用
email
也不使用
mail
。