version 0.0.5.5: added method to logout, refactored existed serializers and views a lot
This commit is contained in:
parent
cb3fbcac93
commit
687b4d3a82
|
|
@ -55,6 +55,19 @@ class User(ImageMixin, AbstractUser):
|
||||||
def remove_token(self):
|
def remove_token(self):
|
||||||
Token.objects.filter(user=self).delete()
|
Token.objects.filter(user=self).delete()
|
||||||
|
|
||||||
|
def remove_access_tokens(self, source):
|
||||||
|
"""Method to remove user access tokens"""
|
||||||
|
self.oauth2_provider_accesstoken.filter(application__source=source)\
|
||||||
|
.delete()
|
||||||
|
|
||||||
|
def revoke_refresh_tokens(self, source):
|
||||||
|
"""Method to remove user refresh tokens"""
|
||||||
|
refresh_tokens = self.oauth2_provider_refreshtoken.filter(
|
||||||
|
application__source=source)
|
||||||
|
for token in refresh_tokens:
|
||||||
|
token.revoke()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def get_username(self):
|
def get_username(self):
|
||||||
|
"""Get user username"""
|
||||||
return self.username
|
return self.username
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,8 @@ from rest_framework import serializers
|
||||||
from rest_framework import validators as rest_validators
|
from rest_framework import validators as rest_validators
|
||||||
|
|
||||||
from account import models as account_models
|
from account import models as account_models
|
||||||
from utils import exceptions as utils_exceptions
|
|
||||||
from authorization.models import Application
|
from authorization.models import Application
|
||||||
from django.utils.translation import gettext_lazy as _
|
from utils import exceptions as utils_exceptions
|
||||||
|
|
||||||
|
|
||||||
# Mixins
|
# Mixins
|
||||||
|
|
@ -85,6 +84,10 @@ class LoginSerializer(BaseAuthSerializerMixin, serializers.ModelSerializer):
|
||||||
fields = ('username', 'password', 'source')
|
fields = ('username', 'password', 'source')
|
||||||
|
|
||||||
|
|
||||||
|
class LogoutSerializer(BaseAuthSerializerMixin):
|
||||||
|
"""Serializer for logout"""
|
||||||
|
|
||||||
|
|
||||||
# OAuth
|
# OAuth
|
||||||
class OAuth2Serialzier(BaseAuthSerializerMixin):
|
class OAuth2Serialzier(BaseAuthSerializerMixin):
|
||||||
"""Serializer OAuth2 authorization"""
|
"""Serializer OAuth2 authorization"""
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from django.conf import settings
|
||||||
from django.conf.urls import url, include
|
from django.conf.urls import url, include
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from oauth2_provider.views import AuthorizationView
|
from oauth2_provider.views import AuthorizationView
|
||||||
from rest_framework_social_oauth2.views import invalidate_sessions
|
from rest_framework_social_oauth2 import views as drf_social_oauth2_views
|
||||||
from social_core.utils import setting_name
|
from social_core.utils import setting_name
|
||||||
from social_django import views as social_django_views
|
from social_django import views as social_django_views
|
||||||
|
|
||||||
|
|
@ -30,15 +30,21 @@ urlpatterns_social_django = [
|
||||||
urlpatterns_rest_framework_social_oauth2 = [
|
urlpatterns_rest_framework_social_oauth2 = [
|
||||||
url(r'^authorize/?$', AuthorizationView.as_view(), name="authorize"),
|
url(r'^authorize/?$', AuthorizationView.as_view(), name="authorize"),
|
||||||
url('', include('social_django.urls', namespace="social")),
|
url('', include('social_django.urls', namespace="social")),
|
||||||
url(r'^invalidate-sessions/?$', invalidate_sessions, name="invalidate_sessions")
|
url(r'^invalidate-sessions/?$', drf_social_oauth2_views.invalidate_sessions,
|
||||||
|
name="invalidate_sessions")
|
||||||
]
|
]
|
||||||
|
|
||||||
urlpatterns_api = [
|
urlpatterns_api = [
|
||||||
|
# sign up
|
||||||
path('social/signup/', views.SocialSignUpView.as_view(), name='signup-social'),
|
path('social/signup/', views.SocialSignUpView.as_view(), name='signup-social'),
|
||||||
|
# sign in
|
||||||
path('login/username/', views.LoginByUsernameView.as_view(), name='login-username'),
|
path('login/username/', views.LoginByUsernameView.as_view(), name='login-username'),
|
||||||
path('login/email/', views.LoginByEmailView.as_view(), name='login-email'),
|
path('login/email/', views.LoginByEmailView.as_view(), name='login-email'),
|
||||||
path('revoke-token/', views.RevokeTokenView.as_view(), name="revoke_token"),
|
# for admin sign in page
|
||||||
path('token/', views.TokenView.as_view(), name="token"), # for admin login page
|
path('token/', drf_social_oauth2_views .TokenView.as_view(), name="token"),
|
||||||
|
# logout
|
||||||
|
path('logout/', views.LogoutView.as_view(), name="logout"),
|
||||||
|
path('revoke-token/', views.RevokeTokenView.as_view(), name="revoke-token"),
|
||||||
]
|
]
|
||||||
|
|
||||||
urlpatterns = urlpatterns_api + \
|
urlpatterns = urlpatterns_api + \
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"""Common views for application Account"""
|
"""Common views for application Account"""
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from rest_framework import status
|
||||||
from braces.views import CsrfExemptMixin
|
from braces.views import CsrfExemptMixin
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
@ -8,20 +9,20 @@ from oauth2_provider.oauth2_backends import OAuthLibCore
|
||||||
from oauth2_provider.settings import oauth2_settings
|
from oauth2_provider.settings import oauth2_settings
|
||||||
from oauth2_provider.views.mixins import OAuthLibMixin
|
from oauth2_provider.views.mixins import OAuthLibMixin
|
||||||
from rest_framework import permissions
|
from rest_framework import permissions
|
||||||
from rest_framework.generics import GenericAPIView, CreateAPIView
|
from rest_framework.generics import GenericAPIView
|
||||||
|
from rest_framework.views import APIView
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework_social_oauth2.oauth2_backends import KeepRequestCore
|
from rest_framework_social_oauth2.oauth2_backends import KeepRequestCore
|
||||||
from rest_framework_social_oauth2.oauth2_endpoints import SocialTokenServer
|
from rest_framework_social_oauth2.oauth2_endpoints import SocialTokenServer
|
||||||
|
from account import models as account_models
|
||||||
from authorization.models import Application
|
from authorization.models import Application
|
||||||
from authorization.serializers import common as serializers
|
from authorization.serializers import common as serializers
|
||||||
from utils import exceptions as utils_exceptions
|
from utils import exceptions as utils_exceptions
|
||||||
|
|
||||||
|
|
||||||
# Mixins
|
# Mixins
|
||||||
class OAuth2ViewMixin(GenericAPIView):
|
class BaseViewMixin(GenericAPIView):
|
||||||
"""Basic mixin for OAuth2 views"""
|
"""BaseMixin for classic auth views"""
|
||||||
|
|
||||||
def get_client_id(self, source) -> str:
|
def get_client_id(self, source) -> str:
|
||||||
"""Get application client id"""
|
"""Get application client id"""
|
||||||
qs = Application.objects.by_source(source=source)
|
qs = Application.objects.by_source(source=source)
|
||||||
|
|
@ -41,6 +42,13 @@ class OAuth2ViewMixin(GenericAPIView):
|
||||||
raise utils_exceptions.SerivceError(data={
|
raise utils_exceptions.SerivceError(data={
|
||||||
'detail': _('Not found an application with this source')})
|
'detail': _('Not found an application with this source')})
|
||||||
|
|
||||||
|
|
||||||
|
class OAuth2ViewMixin(CsrfExemptMixin, OAuthLibMixin, BaseViewMixin):
|
||||||
|
"""Basic mixin for OAuth2 views"""
|
||||||
|
server_class = oauth2_settings.OAUTH2_SERVER_CLASS
|
||||||
|
validator_class = oauth2_settings.OAUTH2_VALIDATOR_CLASS
|
||||||
|
oauthlib_backend_class = OAuthLibCore
|
||||||
|
|
||||||
def prepare_request_data(self, validated_data: dict) -> dict:
|
def prepare_request_data(self, validated_data: dict) -> dict:
|
||||||
"""Preparing request data"""
|
"""Preparing request data"""
|
||||||
source = validated_data.get('source')
|
source = validated_data.get('source')
|
||||||
|
|
@ -60,9 +68,8 @@ class OAuth2ViewMixin(GenericAPIView):
|
||||||
raise utils_exceptions.ServiceError()
|
raise utils_exceptions.ServiceError()
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
# Login
|
||||||
class LoginByUsernameView(CsrfExemptMixin, OAuthLibMixin,
|
class LoginByUsernameView(OAuth2ViewMixin, GenericAPIView):
|
||||||
OAuth2ViewMixin, GenericAPIView):
|
|
||||||
"""
|
"""
|
||||||
Implements an endpoint to provide access tokens
|
Implements an endpoint to provide access tokens
|
||||||
|
|
||||||
|
|
@ -72,9 +79,6 @@ class LoginByUsernameView(CsrfExemptMixin, OAuthLibMixin,
|
||||||
* Password
|
* Password
|
||||||
* Client credentials
|
* Client credentials
|
||||||
"""
|
"""
|
||||||
server_class = oauth2_settings.OAUTH2_SERVER_CLASS
|
|
||||||
validator_class = oauth2_settings.OAUTH2_VALIDATOR_CLASS
|
|
||||||
oauthlib_backend_class = OAuthLibCore
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
permission_classes = (permissions.AllowAny,)
|
||||||
serializer_class = serializers.LoginSerializer
|
serializer_class = serializers.LoginSerializer
|
||||||
|
|
||||||
|
|
@ -114,8 +118,49 @@ class LoginByEmailView(LoginByUsernameView):
|
||||||
serializer_class = serializers.LoginByEmailSerializer
|
serializer_class = serializers.LoginByEmailSerializer
|
||||||
|
|
||||||
|
|
||||||
class SocialSignUpView(CsrfExemptMixin, OAuthLibMixin,
|
# Logout
|
||||||
OAuth2ViewMixin, GenericAPIView):
|
class LogoutView(GenericAPIView):
|
||||||
|
"""Logout view"""
|
||||||
|
permission_classes = (permissions.IsAuthenticated, )
|
||||||
|
serializer_class = serializers.LogoutSerializer
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
"""Method to logout user by deleting access tokens by source"""
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
# Setup attributes
|
||||||
|
source = serializer.validated_data.get('source')
|
||||||
|
request.user.revoke_refresh_tokens(source=source)
|
||||||
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
|
|
||||||
|
class RevokeTokenView(OAuth2ViewMixin, GenericAPIView):
|
||||||
|
"""
|
||||||
|
Implements an endpoint to revoke access or refresh tokens
|
||||||
|
"""
|
||||||
|
permission_classes = (permissions.AllowAny,)
|
||||||
|
serializer_class = serializers.OAuth2Serialzier
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
# Use the rest framework `.data` to fake the post body of the django request.
|
||||||
|
# Preparing request data
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
request_data = self.prepare_request_data(serializer.validated_data)
|
||||||
|
# Use the rest framework `.data` to fake the post body of the django request.
|
||||||
|
request._request.POST = request._request.POST.copy()
|
||||||
|
for key, value in request_data.items():
|
||||||
|
request._request.POST[key] = value
|
||||||
|
|
||||||
|
url, headers, body, status = self.create_revocation_response(request._request)
|
||||||
|
response = Response(data=json.loads(body) if body else '', status=status if body else 204)
|
||||||
|
|
||||||
|
for k, v in headers.items():
|
||||||
|
response[k] = v
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
class SocialSignUpView(OAuth2ViewMixin, GenericAPIView):
|
||||||
"""
|
"""
|
||||||
Implements an endpoint to convert a provider token to an access token
|
Implements an endpoint to convert a provider token to an access token
|
||||||
|
|
||||||
|
|
@ -125,7 +170,6 @@ class SocialSignUpView(CsrfExemptMixin, OAuthLibMixin,
|
||||||
* Client credentials
|
* Client credentials
|
||||||
"""
|
"""
|
||||||
server_class = SocialTokenServer
|
server_class = SocialTokenServer
|
||||||
validator_class = oauth2_settings.OAUTH2_VALIDATOR_CLASS
|
|
||||||
oauthlib_backend_class = KeepRequestCore
|
oauthlib_backend_class = KeepRequestCore
|
||||||
permission_classes = (permissions.AllowAny,)
|
permission_classes = (permissions.AllowAny,)
|
||||||
serializer_class = serializers.OAuth2Serialzier
|
serializer_class = serializers.OAuth2Serialzier
|
||||||
|
|
@ -153,36 +197,6 @@ class SocialSignUpView(CsrfExemptMixin, OAuthLibMixin,
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
class RevokeTokenView(CsrfExemptMixin, OAuthLibMixin,
|
|
||||||
OAuth2ViewMixin, GenericAPIView):
|
|
||||||
"""
|
|
||||||
Implements an endpoint to revoke access or refresh tokens
|
|
||||||
"""
|
|
||||||
server_class = oauth2_settings.OAUTH2_SERVER_CLASS
|
|
||||||
validator_class = oauth2_settings.OAUTH2_VALIDATOR_CLASS
|
|
||||||
oauthlib_backend_class = OAuthLibCore
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
serializer_class = serializers.OAuth2Serialzier
|
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
|
||||||
# Use the rest framework `.data` to fake the post body of the django request.
|
|
||||||
# Preparing request data
|
|
||||||
serializer = self.get_serializer(data=request.data)
|
|
||||||
serializer.is_valid(raise_exception=True)
|
|
||||||
request_data = self.prepare_request_data(serializer.validated_data)
|
|
||||||
# Use the rest framework `.data` to fake the post body of the django request.
|
|
||||||
request._request.POST = request._request.POST.copy()
|
|
||||||
for key, value in request_data.items():
|
|
||||||
request._request.POST[key] = value
|
|
||||||
|
|
||||||
url, headers, body, status = self.create_revocation_response(request._request)
|
|
||||||
response = Response(data=json.loads(body) if body else '', status=status if body else 204)
|
|
||||||
|
|
||||||
for k, v in headers.items():
|
|
||||||
response[k] = v
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
class TokenView(CsrfExemptMixin, OAuthLibMixin, GenericAPIView):
|
class TokenView(CsrfExemptMixin, OAuthLibMixin, GenericAPIView):
|
||||||
"""
|
"""
|
||||||
Implements an endpoint to provide access tokens
|
Implements an endpoint to provide access tokens
|
||||||
|
|
@ -193,9 +207,6 @@ class TokenView(CsrfExemptMixin, OAuthLibMixin, GenericAPIView):
|
||||||
* Password
|
* Password
|
||||||
* Client credentials
|
* Client credentials
|
||||||
"""
|
"""
|
||||||
server_class = oauth2_settings.OAUTH2_SERVER_CLASS
|
|
||||||
validator_class = oauth2_settings.OAUTH2_VALIDATOR_CLASS
|
|
||||||
oauthlib_backend_class = OAuthLibCore
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
permission_classes = (permissions.AllowAny,)
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user