16π
DSA doesnβt logout accounts (or flush sessions) at the moment. AuthAlreadyAssociated
highlights the scenario where the current user is not associated to the current social account trying to be used. There are a couple solutions that might suite your project:
-
Define a sub-class of
social_auth.middleware.SocialAuthExceptionMiddleware
and override the default behavior (process_exception()
) to redirect or setup the warning you like in the way you prefer. -
Add a pipeline method (replacing
social_auth.backend.pipeline.social.social_auth_user
) that logouts the current user instead of raising an exception.
5π
My approach to this problem was a little different, instead of tackling this in the pipeline, I made sure that a user was never passed into the pipeline in the first place. This way, even if the social_auth.user does not match the logged in user, the social_auth.user will be logged in on top of the currently logged in user.
I think itβs as easy as overriding the complete
action.
urls.py
path('complete/<str:backend>/', 'account.views.complete', name='complete'),
account/views.py
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_exempt
from social_core.actions import do_complete
from social_django.utils import psa
from social_django.views import _do_login
@never_cache
@csrf_exempt
@psa('social:complete')
def complete(request, backend, *args, **kwargs):
"""Override this method so we can force user to be logged out."""
return do_complete(request.backend, _do_login, user=None,
redirect_name=REDIRECT_FIELD_NAME, request=request,
*args, **kwargs)
5π
Solution for people wondering how to override social_user pipeline under python-social-auth version 3+
In your settings.py:
SOCIAL_AUTH_PIPELINE = (
'social_core.pipeline.social_auth.social_details',
'social_core.pipeline.social_auth.social_uid',
'social_core.pipeline.social_auth.auth_allowed',
# Path to your overrided method
# You can set any other valid path.
'myproject.apps.python-social-auth-overrided.pipeline.social_auth.social_user',
'social_core.pipeline.user.get_username',
'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',
)
In your overrided social_user:
from django.contrib.auth import logout
def social_user(backend, uid, user=None, *args, **kwargs):
provider = backend.name
social = backend.strategy.storage.user.get_social_auth(provider, uid)
if social:
if user and social.user != user:
logout(backend.strategy.request)
elif not user:
user = social.user
return {'social': social,
'user': user,
'is_new': user is None,
'new_association': False}
You can delete commented lines if you want.
- Can Django run on Gunicorn alone (no Apache or nginx)?
- Is the Global Request variable in Python/Django available?
- How can I automatically let syncdb add a column (no full migration needed)
- Django ForeignKey limit_choices_to a different ForeignKey id
0π
I got the same problem. I solved it by inserting below code in settings
AUTHENTICATION_BACKENDS = (
'...',
'social_core.backends.facebook.FacebookOAuth2',
'...',
)
SOCIAL_AUTH_PIPELINE = (
'...',
'social_core.pipeline.user.user_details',
'...',
)
0π
What I have done is:
-
Define a class that inherits from
SocialAuthExceptionMiddleware
-
Implement the method
process_exception
, -
Add the implemented class to
MIDDLEWARE
list onsettings.py
.
In middleware.py
, which should be in your appsβs directory, i.e., same directory of your views.py
file associated with your app, define the following class:
from django.shortcuts import redirect
from django.urls import reverse
from social_core.exceptions import AuthAlreadyAssociated
class FacebookAuthAlreadyAssociatedMiddleware(SocialAuthExceptionMiddleware):
"""Redirect users to desired-url when AuthAlreadyAssociated exception occurs."""
def process_exception(self, request, exception):
if isinstance(exception, AuthAlreadyAssociated):
if request.backend.name == "facebook":
message = "This facebook account is already in use."
if message in str(exception):
# Add logic if required
# User is redirected to any url you want
# in this case to "app_name:url_name"
return redirect(reverse("app_name:url_name"))
In settings.py
, add the implemented class to the MIDDLEWARE
list:
MIDDLEWARE = [
# Some Django middlewares
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.middleware.common.CommonMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"social_django.middleware.SocialAuthExceptionMiddleware",
# the middleware you just implemented
"app_name.middleware.FacebookAuthAlreadyAssociatedMiddleware",
]
This solved my problem, and I was able to handle the flow of control when the AuthAlreadyAssociated
exception was raised.