version 0.0.5.4: added endpoints to login with username or email, refactored auth serializers, added project exceptions, refactored base settings
This commit is contained in:
parent
237d6d3125
commit
cb3fbcac93
|
|
@ -54,3 +54,7 @@ class User(ImageMixin, AbstractUser):
|
||||||
|
|
||||||
def remove_token(self):
|
def remove_token(self):
|
||||||
Token.objects.filter(user=self).delete()
|
Token.objects.filter(user=self).delete()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def get_username(self):
|
||||||
|
return self.username
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ from account.serializers import web as serializers
|
||||||
|
|
||||||
class UserView(generics.RetrieveUpdateAPIView):
|
class UserView(generics.RetrieveUpdateAPIView):
|
||||||
"""### User update view."""
|
"""### User update view."""
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
serializer_class = serializers.UserSerializer
|
serializer_class = serializers.UserSerializer
|
||||||
queryset = models.User.objects.active()
|
queryset = models.User.objects.active()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ 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 _
|
||||||
|
|
||||||
|
|
||||||
# Mixins
|
# Mixins
|
||||||
|
|
@ -13,25 +15,49 @@ class BaseAuthSerializerMixin(serializers.Serializer):
|
||||||
source = serializers.ChoiceField(choices=Application.SOURCES)
|
source = serializers.ChoiceField(choices=Application.SOURCES)
|
||||||
|
|
||||||
|
|
||||||
# Classic
|
class LoginSerializerMixin(BaseAuthSerializerMixin):
|
||||||
class SignUpSerializer(BaseAuthSerializerMixin, serializers.ModelSerializer):
|
"""Mixin for login serializers"""
|
||||||
"""Serializer for signing up user"""
|
password = serializers.CharField(write_only=True)
|
||||||
email = serializers.CharField(
|
|
||||||
validators=(rest_validators.UniqueValidator(queryset=account_models.User.objects.all()), ),
|
|
||||||
write_only=True
|
class ClassicAuthSerializerMixin(BaseAuthSerializerMixin):
|
||||||
)
|
"""Classic authorization serializer mixin"""
|
||||||
username = serializers.CharField(
|
|
||||||
validators=(rest_validators.UniqueValidator(queryset=account_models.User.objects.all()), ),
|
|
||||||
write_only=True
|
|
||||||
)
|
|
||||||
password = serializers.CharField(write_only=True)
|
password = serializers.CharField(write_only=True)
|
||||||
newsletter = serializers.BooleanField()
|
newsletter = serializers.BooleanField()
|
||||||
|
|
||||||
|
|
||||||
|
# Classic
|
||||||
|
class LoginByEmailSerializer(LoginSerializerMixin, serializers.ModelSerializer):
|
||||||
|
"""Serializer for signing up user by email"""
|
||||||
|
email = serializers.CharField(write_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta-class"""
|
"""Meta-class"""
|
||||||
model = account_models.User
|
model = account_models.User
|
||||||
fields = ('email', 'username', 'newsletter',
|
fields = ('email', 'password', 'source')
|
||||||
'password', 'source')
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
"""Override validate method"""
|
||||||
|
try:
|
||||||
|
user = account_models.User.objects.get(email=attrs.get('email'))
|
||||||
|
attrs['username'] = user.get_username
|
||||||
|
except account_models.User.DoesNotExist:
|
||||||
|
raise utils_exceptions.UserNotFoundError()
|
||||||
|
else:
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
|
class UsernameSignUpSerializer(ClassicAuthSerializerMixin, serializers.ModelSerializer):
|
||||||
|
"""Serializer for signing up user by username"""
|
||||||
|
username = serializers.CharField(
|
||||||
|
validators=(rest_validators.UniqueValidator(queryset=account_models.User.objects.all()), ),
|
||||||
|
write_only=True
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Meta-class"""
|
||||||
|
model = account_models.User
|
||||||
|
fields = ('username', 'newsletter', 'password', 'source')
|
||||||
|
|
||||||
def validate_password(self, data):
|
def validate_password(self, data):
|
||||||
"""Custom password validation"""
|
"""Custom password validation"""
|
||||||
|
|
@ -50,9 +76,7 @@ class SignUpSerializer(BaseAuthSerializerMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class LoginSerializer(BaseAuthSerializerMixin, serializers.ModelSerializer):
|
class LoginSerializer(BaseAuthSerializerMixin, serializers.ModelSerializer):
|
||||||
"""Serializer for login user"""
|
"""Serializer for login user"""
|
||||||
username = serializers.CharField(
|
username = serializers.CharField(write_only=True)
|
||||||
write_only=True
|
|
||||||
)
|
|
||||||
password = serializers.CharField(write_only=True)
|
password = serializers.CharField(write_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,11 @@ 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 (ConvertTokenView, TokenView,
|
from rest_framework_social_oauth2.views import invalidate_sessions
|
||||||
RevokeTokenView, invalidate_sessions)
|
|
||||||
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
|
||||||
|
|
||||||
from authorization.views import web as views
|
from authorization.views import common as views
|
||||||
|
|
||||||
extra = getattr(settings, setting_name('TRAILING_SLASH'), True) and '/' or ''
|
extra = getattr(settings, setting_name('TRAILING_SLASH'), True) and '/' or ''
|
||||||
|
|
||||||
|
|
@ -36,8 +35,10 @@ urlpatterns_rest_framework_social_oauth2 = [
|
||||||
|
|
||||||
urlpatterns_api = [
|
urlpatterns_api = [
|
||||||
path('social/signup/', views.SocialSignUpView.as_view(), name='signup-social'),
|
path('social/signup/', views.SocialSignUpView.as_view(), name='signup-social'),
|
||||||
path('login/', views.LoginView.as_view(), name='login-classic'),
|
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('revoke-token/', views.RevokeTokenView.as_view(), name="revoke_token"),
|
||||||
|
path('token/', views.TokenView.as_view(), name="token"), # for admin login page
|
||||||
]
|
]
|
||||||
|
|
||||||
urlpatterns = urlpatterns_api + \
|
urlpatterns = urlpatterns_api + \
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,212 @@
|
||||||
"""Common views for application authorization"""
|
"""Common views for application Account"""
|
||||||
from django.shortcuts import render
|
import json
|
||||||
from rest_framework import views as rest_views
|
|
||||||
|
from braces.views import CsrfExemptMixin
|
||||||
|
from django.conf import settings
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
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.response import Response
|
||||||
|
from rest_framework_social_oauth2.oauth2_backends import KeepRequestCore
|
||||||
|
from rest_framework_social_oauth2.oauth2_endpoints import SocialTokenServer
|
||||||
|
|
||||||
|
from authorization.models import Application
|
||||||
|
from authorization.serializers import common as serializers
|
||||||
|
from utils import exceptions as utils_exceptions
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
# Mixins
|
||||||
|
class OAuth2ViewMixin(GenericAPIView):
|
||||||
|
"""Basic mixin for OAuth2 views"""
|
||||||
|
|
||||||
|
def get_client_id(self, source) -> str:
|
||||||
|
"""Get application client id"""
|
||||||
|
qs = Application.objects.by_source(source=source)
|
||||||
|
if qs.exists():
|
||||||
|
return qs.first().client_id
|
||||||
|
else:
|
||||||
|
raise utils_exceptions.SerivceError(data={
|
||||||
|
'detail': _('Application is not found')})
|
||||||
|
|
||||||
|
def get_client_secret(self, source) -> str:
|
||||||
|
"""Get application client id"""
|
||||||
|
if source == Application.MOBILE:
|
||||||
|
qs = Application.objects.by_source(source=source)
|
||||||
|
if qs.exists:
|
||||||
|
return qs.first().client_secret
|
||||||
|
else:
|
||||||
|
raise utils_exceptions.SerivceError(data={
|
||||||
|
'detail': _('Not found an application with this source')})
|
||||||
|
|
||||||
|
def prepare_request_data(self, validated_data: dict) -> dict:
|
||||||
|
"""Preparing request data"""
|
||||||
|
source = validated_data.get('source')
|
||||||
|
# Set OAuth2 request parameters
|
||||||
|
_request_data = {
|
||||||
|
'client_id': self.get_client_id(source)
|
||||||
|
}
|
||||||
|
# Fill client secret parameter by platform
|
||||||
|
if validated_data.get('source') == Application.MOBILE:
|
||||||
|
_request_data['client_secret'] = self.get_client_secret(source)
|
||||||
|
# Fill token parameter if transfer
|
||||||
|
if validated_data.get('token'):
|
||||||
|
_request_data['token'] = validated_data.get('token')
|
||||||
|
if _request_data:
|
||||||
|
return _request_data
|
||||||
|
else:
|
||||||
|
raise utils_exceptions.ServiceError()
|
||||||
|
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
|
class LoginByUsernameView(CsrfExemptMixin, OAuthLibMixin,
|
||||||
|
OAuth2ViewMixin, GenericAPIView):
|
||||||
|
"""
|
||||||
|
Implements an endpoint to provide access tokens
|
||||||
|
|
||||||
|
The endpoint is used in the following flows:
|
||||||
|
|
||||||
|
* Authorization code
|
||||||
|
* 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
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
# 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)
|
||||||
|
request_data.update({
|
||||||
|
'grant_type': 'password',
|
||||||
|
'username': serializer.validated_data.get('username'),
|
||||||
|
'password': serializer.validated_data.get('password'),
|
||||||
|
})
|
||||||
|
# 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_token_response(request._request)
|
||||||
|
response = Response(data=json.loads(body), status=status)
|
||||||
|
|
||||||
|
for k, v in headers.items():
|
||||||
|
response[k] = v
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
class LoginByEmailView(LoginByUsernameView):
|
||||||
|
"""
|
||||||
|
Implements an endpoint to provide access tokens
|
||||||
|
|
||||||
|
The endpoint is used in the following flows:
|
||||||
|
|
||||||
|
* Authorization code
|
||||||
|
* Password
|
||||||
|
* Client credentials
|
||||||
|
"""
|
||||||
|
serializer_class = serializers.LoginByEmailSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class SocialSignUpView(CsrfExemptMixin, OAuthLibMixin,
|
||||||
|
OAuth2ViewMixin, GenericAPIView):
|
||||||
|
"""
|
||||||
|
Implements an endpoint to convert a provider token to an access token
|
||||||
|
|
||||||
|
The endpoint is used in the following flows:
|
||||||
|
|
||||||
|
* Authorization code
|
||||||
|
* Client credentials
|
||||||
|
"""
|
||||||
|
server_class = SocialTokenServer
|
||||||
|
validator_class = oauth2_settings.OAUTH2_VALIDATOR_CLASS
|
||||||
|
oauthlib_backend_class = KeepRequestCore
|
||||||
|
permission_classes = (permissions.AllowAny,)
|
||||||
|
serializer_class = serializers.OAuth2Serialzier
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
"""Override POST method"""
|
||||||
|
# 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)
|
||||||
|
request_data.update({
|
||||||
|
'grant_type': settings.OAUTH2_SOCIAL_AUTH_GRANT_TYPE,
|
||||||
|
'backend': settings.OAUTH2_SOCIAL_AUTH_BACKEND_NAME
|
||||||
|
})
|
||||||
|
# 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_token_response(request._request)
|
||||||
|
response = Response(data=json.loads(body), status=status)
|
||||||
|
|
||||||
|
for k, v in headers.items():
|
||||||
|
response[k] = v
|
||||||
|
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
|
||||||
|
|
||||||
|
The endpoint is used in the following flows:
|
||||||
|
|
||||||
|
* Authorization code
|
||||||
|
* 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):
|
||||||
|
# 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_token_response(request._request)
|
||||||
|
response = Response(data=json.loads(body), status=status)
|
||||||
|
|
||||||
|
for k, v in headers.items():
|
||||||
|
response[k] = v
|
||||||
|
return response
|
||||||
|
|
|
||||||
|
|
@ -1,171 +1,2 @@
|
||||||
"""Views for application Account"""
|
"""Web views for application Account"""
|
||||||
import json
|
|
||||||
|
|
||||||
from braces.views import CsrfExemptMixin
|
|
||||||
from django.conf import settings
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
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.response import Response
|
|
||||||
from rest_framework_social_oauth2.oauth2_backends import KeepRequestCore
|
|
||||||
from rest_framework_social_oauth2.oauth2_endpoints import SocialTokenServer
|
|
||||||
|
|
||||||
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"""
|
|
||||||
|
|
||||||
def get_client_id(self, source) -> str:
|
|
||||||
"""Get application client id"""
|
|
||||||
qs = Application.objects.by_source(source=source)
|
|
||||||
if qs.exists():
|
|
||||||
return qs.first().client_id
|
|
||||||
else:
|
|
||||||
raise utils_exceptions.SerivceError(data={
|
|
||||||
'detail': _('Application is not found')})
|
|
||||||
|
|
||||||
def get_client_secret(self, source) -> str:
|
|
||||||
"""Get application client id"""
|
|
||||||
if source == Application.MOBILE:
|
|
||||||
qs = Application.objects.by_source(source=source)
|
|
||||||
if qs.exists:
|
|
||||||
return qs.first().client_secret
|
|
||||||
else:
|
|
||||||
raise utils_exceptions.SerivceError(data={
|
|
||||||
'detail': _('Not found an application with this source')})
|
|
||||||
|
|
||||||
def prepare_request_data(self, validated_data: dict) -> dict:
|
|
||||||
"""Preparing request data"""
|
|
||||||
source = validated_data.get('source')
|
|
||||||
# Set OAuth2 request parameters
|
|
||||||
_request_data = {
|
|
||||||
'client_id': self.get_client_id(source)
|
|
||||||
}
|
|
||||||
# Fill client secret parameter by platform
|
|
||||||
if validated_data.get('source') == Application.MOBILE:
|
|
||||||
_request_data['client_secret'] = self.get_client_secret(source)
|
|
||||||
# Fill token parameter if transfer
|
|
||||||
if validated_data.get('token'):
|
|
||||||
_request_data['token'] = validated_data.get('token')
|
|
||||||
if _request_data:
|
|
||||||
return _request_data
|
|
||||||
else:
|
|
||||||
raise utils_exceptions.SerivceError(data={
|
|
||||||
'detail': 'Unknown request data'})
|
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
|
||||||
class LoginView(CsrfExemptMixin, OAuthLibMixin,
|
|
||||||
OAuth2ViewMixin, GenericAPIView):
|
|
||||||
"""
|
|
||||||
Implements an endpoint to provide access tokens
|
|
||||||
|
|
||||||
The endpoint is used in the following flows:
|
|
||||||
|
|
||||||
* Authorization code
|
|
||||||
* 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
|
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
|
||||||
# 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)
|
|
||||||
request_data.update({
|
|
||||||
'grant_type': 'password',
|
|
||||||
'username': serializer.validated_data.get('username'),
|
|
||||||
'password': serializer.validated_data.get('password'),
|
|
||||||
})
|
|
||||||
# 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_token_response(request._request)
|
|
||||||
response = Response(data=json.loads(body), status=status)
|
|
||||||
|
|
||||||
for k, v in headers.items():
|
|
||||||
response[k] = v
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
class SocialSignUpView(CsrfExemptMixin, OAuthLibMixin,
|
|
||||||
OAuth2ViewMixin, GenericAPIView):
|
|
||||||
"""
|
|
||||||
Implements an endpoint to convert a provider token to an access token
|
|
||||||
|
|
||||||
The endpoint is used in the following flows:
|
|
||||||
|
|
||||||
* Authorization code
|
|
||||||
* Client credentials
|
|
||||||
"""
|
|
||||||
server_class = SocialTokenServer
|
|
||||||
validator_class = oauth2_settings.OAUTH2_VALIDATOR_CLASS
|
|
||||||
oauthlib_backend_class = KeepRequestCore
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
serializer_class = serializers.OAuth2Serialzier
|
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
|
||||||
"""Override POST method"""
|
|
||||||
# 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)
|
|
||||||
request_data.update({
|
|
||||||
'grant_type': settings.OAUTH2_SOCIAL_AUTH_GRANT_TYPE,
|
|
||||||
'backend': settings.OAUTH2_SOCIAL_AUTH_BACKEND_NAME
|
|
||||||
})
|
|
||||||
# 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_token_response(request._request)
|
|
||||||
response = Response(data=json.loads(body), status=status)
|
|
||||||
|
|
||||||
for k, v in headers.items():
|
|
||||||
response[k] = v
|
|
||||||
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
|
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,27 @@ from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import exceptions, status
|
from rest_framework import exceptions, status
|
||||||
|
|
||||||
|
|
||||||
class SerivceError(exceptions.APIException):
|
class ProjectBaseException(exceptions.APIException):
|
||||||
"""Service error."""
|
"""Base exception"""
|
||||||
status_code = status.HTTP_503_SERVICE_UNAVAILABLE
|
status_code = status.HTTP_400_BAD_REQUEST
|
||||||
default_detail = _('Service is temporarily unavailable')
|
default_detail = _('Bad request')
|
||||||
|
|
||||||
def __init__(self, data=None):
|
def __init__(self, data=None):
|
||||||
if data:
|
if data:
|
||||||
self.default_detail = {
|
self.default_detail = {
|
||||||
|
'detail': self.default_detail,
|
||||||
**data
|
**data
|
||||||
}
|
}
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceError(ProjectBaseException):
|
||||||
|
"""Service error."""
|
||||||
|
status_code = status.HTTP_503_SERVICE_UNAVAILABLE
|
||||||
|
default_detail = _('Service is temporarily unavailable')
|
||||||
|
|
||||||
|
|
||||||
|
class UserNotFoundError(ProjectBaseException):
|
||||||
|
"""The exception should be thrown when the user cannot get"""
|
||||||
|
status_code = status.HTTP_404_NOT_FOUND
|
||||||
|
default_detail = _('User not found')
|
||||||
|
|
|
||||||
|
|
@ -151,11 +151,6 @@ LOGOUT_URL = 'admin:logout'
|
||||||
|
|
||||||
LANGUAGE_CODE = 'ru'
|
LANGUAGE_CODE = 'ru'
|
||||||
|
|
||||||
# Facebook configuration
|
|
||||||
SOCIAL_AUTH_FACEBOOK_KEY = '386843648701452'
|
|
||||||
SOCIAL_AUTH_FACEBOOK_SECRET = 'a71cf0bf3980843a8f1ea74c6d805fd7'
|
|
||||||
|
|
||||||
|
|
||||||
TIME_ZONE = 'UTC'
|
TIME_ZONE = 'UTC'
|
||||||
|
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
|
|
@ -209,8 +204,9 @@ REST_FRAMEWORK = {
|
||||||
'DEFAULT_VERSION': (AVAILABLE_VERSIONS['current'],),
|
'DEFAULT_VERSION': (AVAILABLE_VERSIONS['current'],),
|
||||||
'ALLOWED_VERSIONS': AVAILABLE_VERSIONS.values(),
|
'ALLOWED_VERSIONS': AVAILABLE_VERSIONS.values(),
|
||||||
'DEFAULT_PERMISSION_CLASSES': (
|
'DEFAULT_PERMISSION_CLASSES': (
|
||||||
# 'rest_framework.permissions.IsAuthenticated',
|
'rest_framework.permissions.IsAuthenticated',
|
||||||
'oauth2_provider.contrib.rest_framework.permissions.IsAuthenticatedOrTokenHasScope'
|
# todo: oauth2 scope + drf permission
|
||||||
|
# 'oauth2_provider.contrib.rest_framework.permissions.IsAuthenticatedOrTokenHasScope',
|
||||||
),
|
),
|
||||||
# 'DATETIME_FORMAT': '%m-%d-%Y %H:%M:%S', # experiment
|
# 'DATETIME_FORMAT': '%m-%d-%Y %H:%M:%S', # experiment
|
||||||
# 'DATE_FORMAT': '%s.%f', # experiment
|
# 'DATE_FORMAT': '%s.%f', # experiment
|
||||||
|
|
@ -231,10 +227,11 @@ AUTHENTICATION_BACKENDS = (
|
||||||
'django.contrib.auth.backends.ModelBackend',
|
'django.contrib.auth.backends.ModelBackend',
|
||||||
)
|
)
|
||||||
|
|
||||||
OAUTH2_PROVIDER = {
|
# todo: not used until outh2 scopes permission is enabled
|
||||||
# this is the list of available scopes
|
# OAUTH2_PROVIDER = {
|
||||||
'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'groups': 'Access to your groups'}
|
# # this is the list of available scopes
|
||||||
}
|
# 'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'groups': 'Access to your groups'}
|
||||||
|
# }
|
||||||
|
|
||||||
# Override default OAuth2 namespace
|
# Override default OAuth2 namespace
|
||||||
DRFSO2_URL_NAMESPACE = 'oauth2'
|
DRFSO2_URL_NAMESPACE = 'oauth2'
|
||||||
|
|
@ -242,6 +239,10 @@ OAUTH2_SOCIAL_AUTH_BACKEND_NAME = 'facebook'
|
||||||
OAUTH2_SOCIAL_AUTH_GRANT_TYPE = 'convert_token'
|
OAUTH2_SOCIAL_AUTH_GRANT_TYPE = 'convert_token'
|
||||||
OAUTH2_PROVIDER_APPLICATION_MODEL = 'authorization.Application'
|
OAUTH2_PROVIDER_APPLICATION_MODEL = 'authorization.Application'
|
||||||
|
|
||||||
|
# Facebook configuration
|
||||||
|
SOCIAL_AUTH_FACEBOOK_KEY = '386843648701452'
|
||||||
|
SOCIAL_AUTH_FACEBOOK_SECRET = 'a71cf0bf3980843a8f1ea74c6d805fd7'
|
||||||
|
|
||||||
# SMS Settings
|
# SMS Settings
|
||||||
SMS_EXPIRATION = 5
|
SMS_EXPIRATION = 5
|
||||||
SMS_SEND_DELAY = 30
|
SMS_SEND_DELAY = 30
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user