django-rest-auth/dj_rest_auth/views.py

288 lines
10 KiB
Python
Raw Normal View History

2014-04-30 23:52:05 +04:00
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth import login as django_login
from django.contrib.auth import logout as django_logout
2015-11-24 00:52:59 +03:00
from django.core.exceptions import ObjectDoesNotExist
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.debug import sensitive_post_parameters
2014-04-30 23:52:05 +04:00
from rest_framework import status
from rest_framework.generics import GenericAPIView, RetrieveUpdateAPIView
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
2014-04-30 23:52:05 +04:00
from .app_settings import (JWTSerializer, LoginSerializer,
PasswordChangeSerializer,
PasswordResetConfirmSerializer,
PasswordResetSerializer, TokenSerializer,
2020-03-22 13:41:16 +03:00
UserDetailsSerializer, create_token)
2016-01-01 00:10:52 +03:00
from .models import TokenModel
from .utils import jwt_encode
sensitive_post_parameters_m = method_decorator(
sensitive_post_parameters(
'password', 'old_password', 'new_password1', 'new_password2'
)
)
2014-04-30 23:52:05 +04:00
2015-08-07 13:54:45 +03:00
class LoginView(GenericAPIView):
2014-04-30 23:52:05 +04:00
"""
Check the credentials and return the REST Token
if the credentials are valid and authenticated.
Calls Django Auth login method to register User ID
in Django session framework
Accept the following POST parameters: username, password
Return the REST Framework Token Object's key.
"""
2014-10-24 17:52:07 +04:00
permission_classes = (AllowAny,)
2014-04-30 23:52:05 +04:00
serializer_class = LoginSerializer
2016-01-01 00:10:52 +03:00
token_model = TokenModel
throttle_scope = 'dj_rest_auth'
@sensitive_post_parameters_m
def dispatch(self, *args, **kwargs):
return super(LoginView, self).dispatch(*args, **kwargs)
def process_login(self):
django_login(self.request, self.user)
def get_response_serializer(self):
if getattr(settings, 'REST_USE_JWT', False):
response_serializer = JWTSerializer
else:
response_serializer = TokenSerializer
return response_serializer
2014-04-30 23:52:05 +04:00
2014-10-02 13:18:23 +04:00
def login(self):
2015-01-09 14:05:14 +03:00
self.user = self.serializer.validated_data['user']
2016-03-01 14:51:01 +03:00
if getattr(settings, 'REST_USE_JWT', False):
self.access_token, self.refresh_token = jwt_encode(self.user)
else:
2016-12-22 01:08:56 +03:00
self.token = create_token(self.token_model, self.user,
self.serializer)
if getattr(settings, 'REST_SESSION_LOGIN', True):
self.process_login()
2014-10-02 13:18:23 +04:00
def get_response(self):
serializer_class = self.get_response_serializer()
if getattr(settings, 'REST_USE_JWT', False):
data = {
'user': self.user,
'access_token': self.access_token,
'refresh_token': self.refresh_token
}
2016-12-22 01:08:56 +03:00
serializer = serializer_class(instance=data,
context={'request': self.request})
else:
2016-12-22 01:08:56 +03:00
serializer = serializer_class(instance=self.token,
context={'request': self.request})
response = Response(serializer.data, status=status.HTTP_200_OK)
if getattr(settings, 'REST_USE_JWT', False):
2020-03-22 13:41:16 +03:00
cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None)
cookie_secure = getattr(settings, 'JWT_AUTH_SECURE', False)
cookie_samesite = getattr(settings, 'JWT_AUTH_HTTPONLY', True)
cookie_samesite = getattr(settings, 'JWT_AUTH_SAMESITE', 'Lax')
2020-03-19 21:37:35 +03:00
from rest_framework_simplejwt.settings import api_settings as jwt_settings
2020-03-22 13:41:16 +03:00
if cookie_name:
from datetime import datetime
2020-03-20 00:09:20 +03:00
expiration = (datetime.utcnow() + jwt_settings.ACCESS_TOKEN_LIFETIME)
2020-03-22 13:41:16 +03:00
response.set_cookie(
cookie_name,
self.access_token,
expires=expiration,
secure=cookie_secure,
httponly=True,
samesite=cookie_samesite
2020-03-22 13:41:16 +03:00
)
return response
2014-10-02 13:18:23 +04:00
def post(self, request, *args, **kwargs):
self.request = request
self.serializer = self.get_serializer(data=self.request.data,
context={'request': request})
2015-11-23 17:04:56 +03:00
self.serializer.is_valid(raise_exception=True)
2014-10-02 13:18:23 +04:00
self.login()
return self.get_response()
2014-04-30 23:52:05 +04:00
2015-08-07 13:54:45 +03:00
class LogoutView(APIView):
2014-04-30 23:52:05 +04:00
"""
Calls Django logout method and delete the Token object
assigned to the current User object.
Accepts/Returns nothing.
"""
2014-11-12 12:33:29 +03:00
permission_classes = (AllowAny,)
throttle_scope = 'dj_rest_auth'
2014-04-30 23:52:05 +04:00
2016-01-09 06:11:35 +03:00
def get(self, request, *args, **kwargs):
if getattr(settings, 'ACCOUNT_LOGOUT_ON_GET', False):
response = self.logout(request)
else:
response = self.http_method_not_allowed(request, *args, **kwargs)
2016-01-09 06:11:35 +03:00
return self.finalize_response(request, response, *args, **kwargs)
def post(self, request, *args, **kwargs):
2016-01-09 06:11:35 +03:00
return self.logout(request)
def logout(self, request):
2014-04-30 23:52:05 +04:00
try:
request.user.auth_token.delete()
2015-11-24 00:52:59 +03:00
except (AttributeError, ObjectDoesNotExist):
2014-04-30 23:52:05 +04:00
pass
if getattr(settings, 'REST_SESSION_LOGIN', True):
django_logout(request)
2014-04-30 23:52:05 +04:00
2017-06-30 14:23:56 +03:00
response = Response({"detail": _("Successfully logged out.")},
status=status.HTTP_200_OK)
2017-06-30 14:23:56 +03:00
if getattr(settings, 'REST_USE_JWT', False):
# NOTE: this import occurs here rather than at the top level
# because JWT support is optional, and if `REST_USE_JWT` isn't
# True we shouldn't need the dependency
from rest_framework_simplejwt.exceptions import TokenError
from rest_framework_simplejwt.tokens import RefreshToken
2020-03-22 13:52:26 +03:00
cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None)
2020-03-22 13:41:16 +03:00
if cookie_name:
response.delete_cookie(cookie_name)
elif 'rest_framework_simplejwt.token_blacklist' in settings.INSTALLED_APPS:
# add refresh token to blacklist
try:
token = RefreshToken(request.data['refresh'])
token.blacklist()
except KeyError:
response = Response({"detail": _("Refresh token was not included in request data.")},
status=status.HTTP_401_UNAUTHORIZED)
except (TokenError, AttributeError, TypeError) as error:
if hasattr(error, 'args'):
if 'Token is blacklisted' in error.args or 'Token is invalid or expired' in error.args:
response = Response({"detail": _(error.args[0])},
status=status.HTTP_401_UNAUTHORIZED)
else:
response = Response({"detail": _("An error has occurred.")},
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
else:
2020-04-02 17:07:23 +03:00
response = Response({"detail": _("An error has occurred.")},
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
else:
response = Response({
"detail": _("Neither cookies or blacklist are enabled, so the token has not been deleted server "
"side. Please make sure the token is deleted client side."
)}, status=status.HTTP_200_OK)
2017-06-30 14:23:56 +03:00
return response
2014-04-30 23:52:05 +04:00
2015-08-07 13:54:45 +03:00
class UserDetailsView(RetrieveUpdateAPIView):
2014-04-30 23:52:05 +04:00
"""
Reads and updates UserModel fields
Accepts GET, PUT, PATCH methods.
Default accepted fields: username, first_name, last_name
Default display fields: pk, username, email, first_name, last_name
Read-only fields: pk, email
2014-04-30 23:52:05 +04:00
Returns UserModel fields.
2014-04-30 23:52:05 +04:00
"""
2014-10-02 13:18:23 +04:00
serializer_class = UserDetailsSerializer
2014-10-24 17:52:07 +04:00
permission_classes = (IsAuthenticated,)
2014-04-30 23:52:05 +04:00
2014-10-02 13:18:23 +04:00
def get_object(self):
return self.request.user
2014-04-30 23:52:05 +04:00
def get_queryset(self):
"""
Adding this method since it is sometimes called when using
django-rest-swagger
"""
return get_user_model().objects.none()
2014-04-30 23:52:05 +04:00
2015-08-07 13:54:45 +03:00
class PasswordResetView(GenericAPIView):
2014-04-30 23:52:05 +04:00
"""
Calls Django Auth PasswordResetForm save method.
Accepts the following POST parameters: email
Returns the success/fail message.
"""
serializer_class = PasswordResetSerializer
2014-10-24 17:52:07 +04:00
permission_classes = (AllowAny,)
throttle_scope = 'dj_rest_auth'
2014-04-30 23:52:05 +04:00
def post(self, request, *args, **kwargs):
# Create a serializer with request.data
serializer = self.get_serializer(data=request.data)
2015-11-23 17:04:56 +03:00
serializer.is_valid(raise_exception=True)
2014-04-30 23:52:05 +04:00
serializer.save()
# Return the success message with OK HTTP status
2015-04-28 11:22:08 +03:00
return Response(
{"detail": _("Password reset e-mail has been sent.")},
2015-04-28 11:22:08 +03:00
status=status.HTTP_200_OK
)
2014-04-30 23:52:05 +04:00
2015-08-07 13:54:45 +03:00
class PasswordResetConfirmView(GenericAPIView):
2014-04-30 23:52:05 +04:00
"""
Password reset e-mail link is confirmed, therefore
this resets the user's password.
2014-04-30 23:52:05 +04:00
Accepts the following POST parameters: token, uid,
new_password1, new_password2
2014-04-30 23:52:05 +04:00
Returns the success/fail message.
"""
serializer_class = PasswordResetConfirmSerializer
2014-10-24 17:52:07 +04:00
permission_classes = (AllowAny,)
throttle_scope = 'dj_rest_auth'
2014-04-30 23:52:05 +04:00
@sensitive_post_parameters_m
def dispatch(self, *args, **kwargs):
return super(PasswordResetConfirmView, self).dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
2015-11-23 17:04:56 +03:00
serializer.is_valid(raise_exception=True)
serializer.save()
2016-12-22 01:08:56 +03:00
return Response(
{"detail": _("Password has been reset with the new password.")}
)
2014-04-30 23:52:05 +04:00
2015-08-07 13:54:45 +03:00
class PasswordChangeView(GenericAPIView):
2014-04-30 23:52:05 +04:00
"""
Calls Django Auth SetPasswordForm save method.
Accepts the following POST parameters: new_password1, new_password2
Returns the success/fail message.
"""
serializer_class = PasswordChangeSerializer
2014-10-24 17:52:07 +04:00
permission_classes = (IsAuthenticated,)
throttle_scope = 'dj_rest_auth'
2014-04-30 23:52:05 +04:00
@sensitive_post_parameters_m
def dispatch(self, *args, **kwargs):
return super(PasswordChangeView, self).dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
2015-11-23 17:04:56 +03:00
serializer.is_valid(raise_exception=True)
serializer.save()
return Response({"detail": _("New password has been saved.")})