diff --git a/docs/configuration.rst b/docs/configuration.rst index 59b301f..c277781 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -48,6 +48,8 @@ Configuration - **REST_USE_JWT** - Enable JWT Authentication instead of Token/Session based. This is built on top of django-rest-framework-jwt http://getblimp.github.io/django-rest-framework-jwt/, which must also be installed. (default: False) +- **REST_USE_TOKEN** - set it to False if you do not want to use tokens. This is the recommended setting for cookie-based/custom authorization. With this option there is no need to define ``rest_framework.authtoken`` in ``INSTALLED_APPS``. (default: True) + - **OLD_PASSWORD_FIELD_ENABLED** - set it to True if you want to have old password verification on password change enpoint (default: False) - **LOGOUT_ON_PASSWORD_CHANGE** - set to False if you want to keep the current user logged in after a password change diff --git a/rest_auth/registration/views.py b/rest_auth/registration/views.py index 0e0ab0d..1a275df 100644 --- a/rest_auth/registration/views.py +++ b/rest_auth/registration/views.py @@ -56,9 +56,12 @@ class RegisterView(CreateAPIView): 'token': self.token } return JWTSerializer(data).data - else: + + if getattr(settings, 'REST_USE_TOKEN', True): return TokenSerializer(user.auth_token).data + return None + def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) @@ -73,7 +76,7 @@ class RegisterView(CreateAPIView): user = serializer.save(self.request) if getattr(settings, 'REST_USE_JWT', False): self.token = jwt_encode(user) - else: + elif getattr(settings, 'REST_USE_TOKEN', True): create_token(self.token_model, user, serializer) complete_signup(self.request._request, user, diff --git a/rest_auth/tests/mixins.py b/rest_auth/tests/mixins.py index 30b3d58..558b0a8 100644 --- a/rest_auth/tests/mixins.py +++ b/rest_auth/tests/mixins.py @@ -50,12 +50,14 @@ class TestsMixin(object): if hasattr(self, 'token'): if getattr(settings, 'REST_USE_JWT', False): kwargs['HTTP_AUTHORIZATION'] = 'JWT %s' % self.token - else: + elif getattr(settings, 'REST_USE_TOKEN', True): kwargs['HTTP_AUTHORIZATION'] = 'Token %s' % self.token self.response = request_func(*args, **kwargs) - is_json = bool( - [x for x in self.response._headers['content-type'] if 'json' in x]) + is_json = bool([ + x for x in self.response._headers.get('content-type', []) + if 'json' in x + ]) self.response.json = {} if is_json and self.response.content: diff --git a/rest_auth/tests/test_api.py b/rest_auth/tests/test_api.py index 9c5fd9e..8590803 100644 --- a/rest_auth/tests/test_api.py +++ b/rest_auth/tests/test_api.py @@ -157,6 +157,16 @@ class APIBasicTests(TestsMixin, TestCase): self.assertEqual('token' in self.response.json.keys(), True) self.token = self.response.json['token'] + @override_settings(REST_USE_TOKEN=False) + def test_login_returns_session_cookie(self): + payload = { + "username": self.USERNAME, + "password": self.PASS + } + get_user_model().objects.create_user(self.USERNAME, '', self.PASS) + self.post(self.login_url, data=payload, status_code=200) + self.assertIsNotNone(self.response.cookies.get('sessionid')) + def test_login_by_email(self): # starting test without allauth app settings.INSTALLED_APPS.remove('allauth') @@ -391,6 +401,23 @@ class APIBasicTests(TestsMixin, TestCase): user = get_user_model().objects.get(pk=user.pk) self.assertEqual(user.email, self.response.json['email']) + @override_settings(REST_USE_TOKEN=False) + def test_user_details_with_session_cookie(self): + user = get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) + payload = { + "username": self.USERNAME, + "password": self.PASS + } + result = self.post(self.login_url, data=payload, status_code=200) + self.assertIsNone(result.data) + self.get(self.user_url, status_code=200) + + self.patch(self.user_url, data=self.BASIC_USER_DATA, status_code=200) + user = get_user_model().objects.get(pk=user.pk) + self.assertEqual(user.first_name, self.response.json['first_name']) + self.assertEqual(user.last_name, self.response.json['last_name']) + self.assertEqual(user.email, self.response.json['email']) + def test_registration(self): user_count = get_user_model().objects.all().count() @@ -434,6 +461,19 @@ class APIBasicTests(TestsMixin, TestCase): self._login() self._logout() + @override_settings(REST_USE_TOKEN=False) + def test_registration_without_token(self): + user_count = get_user_model().objects.all().count() + + self.post(self.register_url, data={}, status_code=400) + + result = self.post(self.register_url, data=self.REGISTRATION_DATA, status_code=201) + self.assertIsNone(result.data) + self.assertEqual(get_user_model().objects.all().count(), user_count + 1) + + self._login() + self._logout() + def test_registration_with_invalid_password(self): data = self.REGISTRATION_DATA.copy() data['password2'] = 'foobar' diff --git a/rest_auth/views.py b/rest_auth/views.py index 8efcdd5..834653f 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -51,19 +51,12 @@ class LoginView(GenericAPIView): 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 - def login(self): self.user = self.serializer.validated_data['user'] if getattr(settings, 'REST_USE_JWT', False): self.token = jwt_encode(self.user) - else: + elif getattr(settings, 'REST_USE_TOKEN', True): self.token = create_token(self.token_model, self.user, self.serializer) @@ -71,20 +64,24 @@ class LoginView(GenericAPIView): self.process_login() def get_response(self): - serializer_class = self.get_response_serializer() - if getattr(settings, 'REST_USE_JWT', False): - data = { - 'user': self.user, - 'token': self.token - } - serializer = serializer_class(instance=data, - context={'request': self.request}) + serializer = JWTSerializer( + instance={ + 'user': self.user, + 'token': self.token, + }, + context={'request': self.request}, + ) + data = serializer.data + elif getattr(settings, 'REST_USE_TOKEN', True): + serializer = TokenSerializer( + instance=self.token, + context={'request': self.request}, + ) + data = serializer.data else: - serializer = serializer_class(instance=self.token, - context={'request': self.request}) - - return Response(serializer.data, status=status.HTTP_200_OK) + data = None + return Response(data, status=status.HTTP_200_OK) def post(self, request, *args, **kwargs): self.request = request