version 0.0.5.5: added method to logout, refactored existed serializers and views a lot

This commit is contained in:
Anatoly 2019-08-10 13:43:00 +03:00
parent cb3fbcac93
commit 687b4d3a82
4 changed files with 86 additions and 53 deletions

View File

@ -55,6 +55,19 @@ class User(ImageMixin, AbstractUser):
def remove_token(self):
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
def get_username(self):
"""Get user username"""
return self.username

View File

@ -4,9 +4,8 @@ from rest_framework import serializers
from rest_framework import validators as rest_validators
from account import models as account_models
from utils import exceptions as utils_exceptions
from authorization.models import Application
from django.utils.translation import gettext_lazy as _
from utils import exceptions as utils_exceptions
# Mixins
@ -85,6 +84,10 @@ class LoginSerializer(BaseAuthSerializerMixin, serializers.ModelSerializer):
fields = ('username', 'password', 'source')
class LogoutSerializer(BaseAuthSerializerMixin):
"""Serializer for logout"""
# OAuth
class OAuth2Serialzier(BaseAuthSerializerMixin):
"""Serializer OAuth2 authorization"""

View File

@ -3,7 +3,7 @@ from django.conf import settings
from django.conf.urls import url, include
from django.urls import path
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_django import views as social_django_views
@ -30,15 +30,21 @@ urlpatterns_social_django = [
urlpatterns_rest_framework_social_oauth2 = [
url(r'^authorize/?$', AuthorizationView.as_view(), name="authorize"),
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 = [
# sign up
path('social/signup/', views.SocialSignUpView.as_view(), name='signup-social'),
# sign in
path('login/username/', views.LoginByUsernameView.as_view(), name='login-username'),
path('login/email/', views.LoginByEmailView.as_view(), name='login-email'),
path('revoke-token/', views.RevokeTokenView.as_view(), name="revoke_token"),
path('token/', views.TokenView.as_view(), name="token"), # for admin login page
# for admin sign in 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 + \

View File

@ -1,6 +1,7 @@
"""Common views for application Account"""
import json
from rest_framework import status
from braces.views import CsrfExemptMixin
from django.conf import settings
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.views.mixins import OAuthLibMixin
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_social_oauth2.oauth2_backends import KeepRequestCore
from rest_framework_social_oauth2.oauth2_endpoints import SocialTokenServer
from account import models as account_models
from authorization.models import Application
from authorization.serializers import common as serializers
from utils import exceptions as utils_exceptions
# Mixins
class OAuth2ViewMixin(GenericAPIView):
"""Basic mixin for OAuth2 views"""
class BaseViewMixin(GenericAPIView):
"""BaseMixin for classic auth views"""
def get_client_id(self, source) -> str:
"""Get application client id"""
qs = Application.objects.by_source(source=source)
@ -41,6 +42,13 @@ class OAuth2ViewMixin(GenericAPIView):
raise utils_exceptions.SerivceError(data={
'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:
"""Preparing request data"""
source = validated_data.get('source')
@ -60,9 +68,8 @@ class OAuth2ViewMixin(GenericAPIView):
raise utils_exceptions.ServiceError()
# Create your views here.
class LoginByUsernameView(CsrfExemptMixin, OAuthLibMixin,
OAuth2ViewMixin, GenericAPIView):
# Login
class LoginByUsernameView(OAuth2ViewMixin, GenericAPIView):
"""
Implements an endpoint to provide access tokens
@ -72,9 +79,6 @@ class LoginByUsernameView(CsrfExemptMixin, OAuthLibMixin,
* Password
* Client credentials
"""
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.LoginSerializer
@ -114,8 +118,49 @@ class LoginByEmailView(LoginByUsernameView):
serializer_class = serializers.LoginByEmailSerializer
class SocialSignUpView(CsrfExemptMixin, OAuthLibMixin,
OAuth2ViewMixin, GenericAPIView):
# Logout
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
@ -125,7 +170,6 @@ class SocialSignUpView(CsrfExemptMixin, OAuthLibMixin,
* Client credentials
"""
server_class = SocialTokenServer
validator_class = oauth2_settings.OAUTH2_VALIDATOR_CLASS
oauthlib_backend_class = KeepRequestCore
permission_classes = (permissions.AllowAny,)
serializer_class = serializers.OAuth2Serialzier
@ -153,36 +197,6 @@ class SocialSignUpView(CsrfExemptMixin, OAuthLibMixin,
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):
"""
Implements an endpoint to provide access tokens
@ -193,9 +207,6 @@ class TokenView(CsrfExemptMixin, OAuthLibMixin, GenericAPIView):
* Password
* Client credentials
"""
server_class = oauth2_settings.OAUTH2_SERVER_CLASS
validator_class = oauth2_settings.OAUTH2_VALIDATOR_CLASS
oauthlib_backend_class = OAuthLibCore
permission_classes = (permissions.AllowAny,)
def post(self, request, *args, **kwargs):