mirror of
				https://github.com/Tivix/django-rest-auth.git
				synced 2025-11-04 09:37:35 +03:00 
			
		
		
		
	Merge pull request #387 from aleksihakli/master
Implement connect social accounts functionality
This commit is contained in:
		
						commit
						41ae498be0
					
				| 
						 | 
					@ -111,11 +111,15 @@ Facebook
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter
 | 
					    from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter
 | 
				
			||||||
    from rest_auth.registration.views import SocialLoginView
 | 
					    from rest_auth.registration.views import SocialLoginView, SocialConnectView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class FacebookLogin(SocialLoginView):
 | 
					    class FacebookLogin(SocialLoginView):
 | 
				
			||||||
        adapter_class = FacebookOAuth2Adapter
 | 
					        adapter_class = FacebookOAuth2Adapter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Add a connect view if you want to allow connecting existing accounts
 | 
				
			||||||
 | 
					    class FacebookConnect(SocialConnectView):
 | 
				
			||||||
 | 
					        adapter_class = FacebookOAuth2Adapter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
4. Create url for FacebookLogin view:
 | 
					4. Create url for FacebookLogin view:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
| 
						 | 
					@ -123,6 +127,7 @@ Facebook
 | 
				
			||||||
    urlpatterns += [
 | 
					    urlpatterns += [
 | 
				
			||||||
        ...,
 | 
					        ...,
 | 
				
			||||||
        url(r'^rest-auth/facebook/$', FacebookLogin.as_view(), name='fb_login')
 | 
					        url(r'^rest-auth/facebook/$', FacebookLogin.as_view(), name='fb_login')
 | 
				
			||||||
 | 
					        url(r'^rest-auth/facebook/connect/$', FacebookConnect.as_view(), name='fb_connect')
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -136,13 +141,19 @@ If you are using Twitter for your social authentication, it is a bit different s
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter
 | 
					    from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter
 | 
				
			||||||
    from rest_auth.views import LoginView
 | 
					    from rest_auth.registration.views import SocialLoginView
 | 
				
			||||||
    from rest_auth.social_serializers import TwitterLoginSerializer
 | 
					    from rest_auth.social_serializers import TwitterLoginSerializer, TwitterConnectSerializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class TwitterLogin(LoginView):
 | 
					    class TwitterLogin(SocialLoginView):
 | 
				
			||||||
        serializer_class = TwitterLoginSerializer
 | 
					        serializer_class = TwitterLoginSerializer
 | 
				
			||||||
        adapter_class = TwitterOAuthAdapter
 | 
					        adapter_class = TwitterOAuthAdapter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Add a connect view if you want to allow connecting existing accounts
 | 
				
			||||||
 | 
					    class TwitterConnect(SocialConnectView):
 | 
				
			||||||
 | 
					        serializer_class = TwitterConnectSerializer
 | 
				
			||||||
 | 
					        adapter_class = TwitterOAuthAdapter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
4. Create url for TwitterLogin view:
 | 
					4. Create url for TwitterLogin view:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
| 
						 | 
					@ -150,6 +161,7 @@ If you are using Twitter for your social authentication, it is a bit different s
 | 
				
			||||||
    urlpatterns += [
 | 
					    urlpatterns += [
 | 
				
			||||||
        ...,
 | 
					        ...,
 | 
				
			||||||
        url(r'^rest-auth/twitter/$', TwitterLogin.as_view(), name='twitter_login')
 | 
					        url(r'^rest-auth/twitter/$', TwitterLogin.as_view(), name='twitter_login')
 | 
				
			||||||
 | 
					        url(r'^rest-auth/twitter/connect/$', TwitterConnect.as_view(), name='twitter_login')
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
.. note:: Starting from v0.21.0, django-allauth has dropped support for context processors. Check out http://django-allauth.readthedocs.org/en/latest/changelog.html#from-0-21-0 for more details.
 | 
					.. note:: Starting from v0.21.0, django-allauth has dropped support for context processors. Check out http://django-allauth.readthedocs.org/en/latest/changelog.html#from-0-21-0 for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,10 +14,6 @@ except ImportError:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from rest_framework import serializers
 | 
					from rest_framework import serializers
 | 
				
			||||||
from requests.exceptions import HTTPError
 | 
					from requests.exceptions import HTTPError
 | 
				
			||||||
# Import is needed only if we are using social login, in which
 | 
					 | 
				
			||||||
# case the allauth.socialaccount will be declared
 | 
					 | 
				
			||||||
if 'allauth.socialaccount' in settings.INSTALLED_APPS:
 | 
					 | 
				
			||||||
    from allauth.socialaccount.helpers import complete_social_login
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SocialLoginSerializer(serializers.Serializer):
 | 
					class SocialLoginSerializer(serializers.Serializer):
 | 
				
			||||||
| 
						 | 
					@ -186,3 +182,44 @@ class RegisterSerializer(serializers.Serializer):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VerifyEmailSerializer(serializers.Serializer):
 | 
					class VerifyEmailSerializer(serializers.Serializer):
 | 
				
			||||||
    key = serializers.CharField()
 | 
					    key = serializers.CharField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Import is needed only if we are using social login, in which
 | 
				
			||||||
 | 
					# case the allauth.socialaccount will be declared
 | 
				
			||||||
 | 
					if 'allauth.socialaccount' in settings.INSTALLED_APPS:
 | 
				
			||||||
 | 
					    from allauth.socialaccount.helpers import complete_social_login
 | 
				
			||||||
 | 
					    from allauth.socialaccount.models import SocialAccount
 | 
				
			||||||
 | 
					    from allauth.socialaccount.providers.base import AuthProcess
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class SocialAccountSerializer(serializers.ModelSerializer):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        serialize allauth SocialAccounts for use with a REST API
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        class Meta:
 | 
				
			||||||
 | 
					            model = SocialAccount
 | 
				
			||||||
 | 
					            fields = (
 | 
				
			||||||
 | 
					                'id',
 | 
				
			||||||
 | 
					                'provider',
 | 
				
			||||||
 | 
					                'uid',
 | 
				
			||||||
 | 
					                'last_login',
 | 
				
			||||||
 | 
					                'date_joined',
 | 
				
			||||||
 | 
					                'extra_data',
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class SocialConnectMixin(object):
 | 
				
			||||||
 | 
					        def get_social_login(self, *args, **kwargs):
 | 
				
			||||||
 | 
					            """
 | 
				
			||||||
 | 
					            set the social login process state to connect rather than login
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Refer to the implementation of get_social_login in base class and to the
 | 
				
			||||||
 | 
					            allauth.socialaccount.helpers module complete_social_login function.
 | 
				
			||||||
 | 
					            """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            social_login = super(SocialConnectMixin, self).get_social_login(*args, **kwargs)
 | 
				
			||||||
 | 
					            social_login.state['process'] = AuthProcess.CONNECT
 | 
				
			||||||
 | 
					            return social_login
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class SocialConnectSerializer(SocialConnectMixin, SocialLoginSerializer):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,11 +5,13 @@ from django.views.decorators.debug import sensitive_post_parameters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from rest_framework.views import APIView
 | 
					from rest_framework.views import APIView
 | 
				
			||||||
from rest_framework.response import Response
 | 
					from rest_framework.response import Response
 | 
				
			||||||
from rest_framework.permissions import AllowAny
 | 
					from rest_framework.permissions import (AllowAny,
 | 
				
			||||||
 | 
					                                        IsAuthenticated)
 | 
				
			||||||
 | 
					from rest_framework.decorators import detail_route
 | 
				
			||||||
 | 
					from rest_framework.viewsets import GenericViewSet
 | 
				
			||||||
from rest_framework.generics import CreateAPIView
 | 
					from rest_framework.generics import CreateAPIView
 | 
				
			||||||
from rest_framework import status
 | 
					from rest_framework import status
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from allauth.account.adapter import get_adapter
 | 
					 | 
				
			||||||
from allauth.account.views import ConfirmEmailView
 | 
					from allauth.account.views import ConfirmEmailView
 | 
				
			||||||
from allauth.account.utils import complete_signup
 | 
					from allauth.account.utils import complete_signup
 | 
				
			||||||
from allauth.account import app_settings as allauth_settings
 | 
					from allauth.account import app_settings as allauth_settings
 | 
				
			||||||
| 
						 | 
					@ -19,7 +21,8 @@ from rest_auth.app_settings import (TokenSerializer,
 | 
				
			||||||
                                    create_token)
 | 
					                                    create_token)
 | 
				
			||||||
from rest_auth.models import TokenModel
 | 
					from rest_auth.models import TokenModel
 | 
				
			||||||
from rest_auth.registration.serializers import (SocialLoginSerializer,
 | 
					from rest_auth.registration.serializers import (SocialLoginSerializer,
 | 
				
			||||||
                                                VerifyEmailSerializer)
 | 
					                                                VerifyEmailSerializer,
 | 
				
			||||||
 | 
					                                                SocialConnectSerializer)
 | 
				
			||||||
from rest_auth.utils import jwt_encode
 | 
					from rest_auth.utils import jwt_encode
 | 
				
			||||||
from rest_auth.views import LoginView
 | 
					from rest_auth.views import LoginView
 | 
				
			||||||
from .app_settings import RegisterSerializer, register_permission_classes
 | 
					from .app_settings import RegisterSerializer, register_permission_classes
 | 
				
			||||||
| 
						 | 
					@ -91,7 +94,15 @@ class VerifyEmailView(APIView, ConfirmEmailView):
 | 
				
			||||||
        return Response({'detail': _('ok')}, status=status.HTTP_200_OK)
 | 
					        return Response({'detail': _('ok')}, status=status.HTTP_200_OK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SocialLoginView(LoginView):
 | 
					if 'allauth.socialaccount' in settings.INSTALLED_APPS:
 | 
				
			||||||
 | 
					    from allauth.socialaccount import signals
 | 
				
			||||||
 | 
					    from allauth.socialaccount.models import SocialAccount
 | 
				
			||||||
 | 
					    from allauth.socialaccount.adapter import get_adapter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    from rest_auth.registration.serializers import SocialAccountSerializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class SocialLoginView(LoginView):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        class used for social authentications
 | 
					        class used for social authentications
 | 
				
			||||||
        example usage for facebook with access_token
 | 
					        example usage for facebook with access_token
 | 
				
			||||||
| 
						 | 
					@ -119,3 +130,62 @@ class SocialLoginView(LoginView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def process_login(self):
 | 
					        def process_login(self):
 | 
				
			||||||
            get_adapter(self.request).login(self.request, self.user)
 | 
					            get_adapter(self.request).login(self.request, self.user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class SocialConnectView(SocialLoginView):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        class used for social account linking
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        example usage for facebook with access_token
 | 
				
			||||||
 | 
					        -------------
 | 
				
			||||||
 | 
					        from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class FacebookConnect(SocialConnectView):
 | 
				
			||||||
 | 
					            adapter_class = FacebookOAuth2Adapter
 | 
				
			||||||
 | 
					        -------------
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        serializer_class = SocialConnectSerializer
 | 
				
			||||||
 | 
					        permission_classes = (IsAuthenticated,)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class SocialAccountViewSet(GenericViewSet):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        allauth SocialAccount REST API read and disconnect views for logged in users
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refer to the django-allauth package implementation of the models and
 | 
				
			||||||
 | 
					        account handling logic for more details, this viewset emulates the allauth web UI.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        serializer_class = SocialAccountSerializer
 | 
				
			||||||
 | 
					        permission_classes = (IsAuthenticated,)
 | 
				
			||||||
 | 
					        queryset = SocialAccount.objects.none()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def get_queryset(self):
 | 
				
			||||||
 | 
					            return SocialAccount.objects.filter(user=self.request.user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def list(self, request):
 | 
				
			||||||
 | 
					            """
 | 
				
			||||||
 | 
					            list SocialAccounts for the currently logged in user
 | 
				
			||||||
 | 
					            """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return Response(self.get_serializer(self.get_queryset(), many=True).data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @detail_route(methods=['POST'])
 | 
				
			||||||
 | 
					        def disconnect(self, request, pk):
 | 
				
			||||||
 | 
					            """
 | 
				
			||||||
 | 
					            disconnect SocialAccount from remote service for the currently logged in user
 | 
				
			||||||
 | 
					            """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            accounts = self.get_queryset()
 | 
				
			||||||
 | 
					            account = accounts.get(pk=pk)
 | 
				
			||||||
 | 
					            get_adapter(self.request).validate_disconnect(account, accounts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            account.delete()
 | 
				
			||||||
 | 
					            signals.social_account_removed.send(
 | 
				
			||||||
 | 
					                sender=SocialAccount,
 | 
				
			||||||
 | 
					                request=self.request,
 | 
				
			||||||
 | 
					                socialaccount=account
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return Response(self.get_serializer(account).data)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
from django.http import HttpRequest
 | 
					from django.http import HttpRequest
 | 
				
			||||||
from rest_framework import serializers
 | 
					from rest_framework import serializers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Import is needed only if we are using social login, in which
 | 
					# Import is needed only if we are using social login, in which
 | 
				
			||||||
# case the allauth.socialaccount will be declared
 | 
					# case the allauth.socialaccount will be declared
 | 
				
			||||||
if 'allauth.socialaccount' in settings.INSTALLED_APPS:
 | 
					if 'allauth.socialaccount' in settings.INSTALLED_APPS:
 | 
				
			||||||
| 
						 | 
					@ -8,8 +9,10 @@ if 'allauth.socialaccount' in settings.INSTALLED_APPS:
 | 
				
			||||||
    from allauth.socialaccount.models import SocialToken
 | 
					    from allauth.socialaccount.models import SocialToken
 | 
				
			||||||
    from allauth.socialaccount.providers.oauth.client import OAuthError
 | 
					    from allauth.socialaccount.providers.oauth.client import OAuthError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    from rest_auth.registration.serializers import SocialConnectMixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TwitterLoginSerializer(serializers.Serializer):
 | 
					
 | 
				
			||||||
 | 
					    class TwitterLoginSerializer(serializers.Serializer):
 | 
				
			||||||
        access_token = serializers.CharField()
 | 
					        access_token = serializers.CharField()
 | 
				
			||||||
        token_secret = serializers.CharField()
 | 
					        token_secret = serializers.CharField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,3 +76,7 @@ class TwitterLoginSerializer(serializers.Serializer):
 | 
				
			||||||
            attrs['user'] = login.account.user
 | 
					            attrs['user'] = login.account.user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return attrs
 | 
					            return attrs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class TwitterConnectSerializer(SocialConnectMixin, TwitterLoginSerializer):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user