diff --git a/rest_framework/authtoken/urls.py b/rest_framework/authtoken/urls.py index 2a3e81150..8bea46c00 100644 --- a/rest_framework/authtoken/urls.py +++ b/rest_framework/authtoken/urls.py @@ -13,9 +13,9 @@ your authentication settings include `TokenAuthentication`. ) """ from django.conf.urls.defaults import patterns, url -from rest_framework.authtoken.views import AuthTokenView +from rest_framework.authtoken.views import AuthTokenLoginView, AuthTokenLogoutView urlpatterns = patterns('rest_framework.authtoken.views', - url(r'^login/$', AuthTokenView.as_view(), name='token_login'), -# url(r'^logout/$', 'token_logout', name='token_logout'), + url(r'^login/$', AuthTokenLoginView.as_view(), name='token_login'), + url(r'^logout/$', AuthTokenLogoutView.as_view(), name='token_logout'), ) diff --git a/rest_framework/authtoken/views.py b/rest_framework/authtoken/views.py index e69de29bb..a52f0a77c 100644 --- a/rest_framework/authtoken/views.py +++ b/rest_framework/authtoken/views.py @@ -0,0 +1,19 @@ +from rest_framework.views import APIView +from rest_framework.generics import CreateAPIView +from rest_framework.authtoken.models import Token +from rest_framework.authtoken.serializers import AuthTokenSerializer +from django.http import HttpResponse + +class AuthTokenLoginView(CreateAPIView): + model = Token + serializer_class = AuthTokenSerializer + + +class AuthTokenLogoutView(APIView): + def post(self, request): + if request.user.is_authenticated() and request.auth: + request.auth.delete() + return HttpResponse("logged out") + else: + return HttpResponse("not logged in") + diff --git a/rest_framework/tests/authentication.py b/rest_framework/tests/authentication.py index 8ab4c4e40..d1bc23d9b 100644 --- a/rest_framework/tests/authentication.py +++ b/rest_framework/tests/authentication.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns +from django.conf.urls.defaults import patterns, include from django.contrib.auth.models import User from django.test import Client, TestCase @@ -27,6 +27,7 @@ MockView.authentication_classes += (TokenAuthentication,) urlpatterns = patterns('', (r'^$', MockView.as_view()), + (r'^auth-token/', include('rest_framework.authtoken.urls')), ) @@ -152,3 +153,46 @@ class TokenAuthTests(TestCase): self.token.delete() token = Token.objects.create(user=self.user) self.assertTrue(bool(token.key)) + + def test_token_login_json(self): + """Ensure token login view using JSON POST works.""" + client = Client(enforce_csrf_checks=True) + response = client.post('/auth-token/login/', + json.dumps({'username': self.username, 'password': self.password}), 'application/json') + self.assertEqual(response.status_code, 201) + self.assertEqual(json.loads(response.content)['token'], self.key) + + def test_token_login_json_bad_creds(self): + """Ensure token login view using JSON POST fails if bad credentials are used.""" + client = Client(enforce_csrf_checks=True) + response = client.post('/auth-token/login/', + json.dumps({'username': self.username, 'password': "badpass"}), 'application/json') + self.assertEqual(response.status_code, 400) + + def test_token_login_json_missing_fields(self): + """Ensure token login view using JSON POST fails if missing fields.""" + client = Client(enforce_csrf_checks=True) + response = client.post('/auth-token/login/', + json.dumps({'username': self.username}), 'application/json') + self.assertEqual(response.status_code, 400) + + def test_token_login_form(self): + """Ensure token login view using form POST works.""" + client = Client(enforce_csrf_checks=True) + response = client.post('/auth-token/login/', + {'username': self.username, 'password': self.password}) + self.assertEqual(response.status_code, 201) + self.assertEqual(json.loads(response.content)['token'], self.key) + + def test_token_logout(self): + """Ensure token logout view using JSON POST works.""" + # Use different User and Token as to isolate this test's effects on other unittests in class + username = "ringo" + user = User.objects.create_user(username, "starr@thebeatles.com", "pass") + token = Token.objects.create(user=user) + auth = "Token " + token.key + client = Client(enforce_csrf_checks=True) + response = client.post('/auth-token/logout/', HTTP_AUTHORIZATION=auth) + self.assertEqual(response.status_code, 200) + # Ensure token no longer exists + self.assertRaises(Token.DoesNotExist, lambda token: Token.objects.get(key=token.key), token)