mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-02 20:54:42 +03:00
Merge pull request #399 from robromano/master
Added login view for users of TokenAuthentication
This commit is contained in:
commit
b9e5c9484a
|
@ -112,6 +112,18 @@ If you've already created some User`'s, you can run a script like this.
|
||||||
for user in User.objects.all():
|
for user in User.objects.all():
|
||||||
Token.objects.get_or_create(user=user)
|
Token.objects.get_or_create(user=user)
|
||||||
|
|
||||||
|
When using TokenAuthentication, it may be useful to add a login view for clients to retrieve the token.
|
||||||
|
|
||||||
|
REST framework provides a built-in login view for clients to retrieve the token called `rest_framework.authtoken.obtain_auth_token`. To use it, add a pattern to include the token login view for clients as follows:
|
||||||
|
|
||||||
|
urlpatterns += patterns('',
|
||||||
|
url(r'^api-token-auth/', 'rest_framework.authtoken.obtain_auth_token')
|
||||||
|
)
|
||||||
|
|
||||||
|
The `r'^api-token-auth/'` part of pattern can actually be whatever URL you want to use. The authtoken login view will render a JSON response when a valid `username` and `password` fields are POST'ed to the view using forms or JSON:
|
||||||
|
|
||||||
|
{ 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }
|
||||||
|
|
||||||
## OAuthAuthentication
|
## OAuthAuthentication
|
||||||
|
|
||||||
This policy uses the [OAuth 2.0][oauth] protocol to authenticate requests. OAuth is appropriate for server-server setups, such as when you want to allow a third-party service to access your API on a user's behalf.
|
This policy uses the [OAuth 2.0][oauth] protocol to authenticate requests. OAuth is appropriate for server-server setups, such as when you want to allow a third-party service to access your API on a user's behalf.
|
||||||
|
|
|
@ -60,6 +60,7 @@ The following people have helped make REST framework great.
|
||||||
* Ben Konrath - [benkonrath]
|
* Ben Konrath - [benkonrath]
|
||||||
* Marc Aymerich - [glic3rinu]
|
* Marc Aymerich - [glic3rinu]
|
||||||
* Ludwig Kraatz - [ludwigkraatz]
|
* Ludwig Kraatz - [ludwigkraatz]
|
||||||
|
* Rob Romano - [robromano]
|
||||||
* Eugene Mechanism - [mechanism]
|
* Eugene Mechanism - [mechanism]
|
||||||
|
|
||||||
Many thanks to everyone who's contributed to the project.
|
Many thanks to everyone who's contributed to the project.
|
||||||
|
@ -156,4 +157,6 @@ To contact the author directly:
|
||||||
[benkonrath]: https://github.com/benkonrath
|
[benkonrath]: https://github.com/benkonrath
|
||||||
[glic3rinu]: https://github.com/glic3rinu
|
[glic3rinu]: https://github.com/glic3rinu
|
||||||
[ludwigkraatz]: https://github.com/ludwigkraatz
|
[ludwigkraatz]: https://github.com/ludwigkraatz
|
||||||
|
[robromano]: https://github.com/robromano
|
||||||
[mechanism]: https://github.com/mechanism
|
[mechanism]: https://github.com/mechanism
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
>
|
>
|
||||||
> — Eric S. Raymond, [The Cathedral and the Bazaar][cite].
|
> — Eric S. Raymond, [The Cathedral and the Bazaar][cite].
|
||||||
|
|
||||||
|
* Add convenience login view to get tokens when using `TokenAuthentication`
|
||||||
|
|
||||||
## 2.1.3
|
## 2.1.3
|
||||||
|
|
||||||
**Date**: 16th Nov 2012
|
**Date**: 16th Nov 2012
|
||||||
|
|
24
rest_framework/authtoken/serializers.py
Normal file
24
rest_framework/authtoken/serializers.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
from django.contrib.auth import authenticate
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
class AuthTokenSerializer(serializers.Serializer):
|
||||||
|
username = serializers.CharField()
|
||||||
|
password = serializers.CharField()
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
username = attrs.get('username')
|
||||||
|
password = attrs.get('password')
|
||||||
|
|
||||||
|
if username and password:
|
||||||
|
user = authenticate(username=username, password=password)
|
||||||
|
|
||||||
|
if user:
|
||||||
|
if not user.is_active:
|
||||||
|
raise serializers.ValidationError('User account is disabled.')
|
||||||
|
attrs['user'] = user
|
||||||
|
return attrs
|
||||||
|
else:
|
||||||
|
raise serializers.ValidationError('Unable to login with provided credentials.')
|
||||||
|
else:
|
||||||
|
raise serializers.ValidationError('Must include "username" and "password"')
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
from rest_framework import status
|
||||||
|
from rest_framework import parsers
|
||||||
|
from rest_framework import renderers
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.authtoken.models import Token
|
||||||
|
from rest_framework.authtoken.serializers import AuthTokenSerializer
|
||||||
|
|
||||||
|
class ObtainAuthToken(APIView):
|
||||||
|
throttle_classes = ()
|
||||||
|
permission_classes = ()
|
||||||
|
parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,)
|
||||||
|
renderer_classes = (renderers.JSONRenderer,)
|
||||||
|
model = Token
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
serializer = AuthTokenSerializer(data=request.DATA)
|
||||||
|
if serializer.is_valid():
|
||||||
|
token, created = Token.objects.get_or_create(user=serializer.object['user'])
|
||||||
|
return Response({'token': token.key})
|
||||||
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
|
obtain_auth_token = ObtainAuthToken.as_view()
|
|
@ -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.contrib.auth.models import User
|
||||||
from django.test import Client, TestCase
|
from django.test import Client, TestCase
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ MockView.authentication_classes += (TokenAuthentication,)
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
(r'^$', MockView.as_view()),
|
(r'^$', MockView.as_view()),
|
||||||
|
(r'^auth-token/', 'rest_framework.authtoken.views.obtain_auth_token'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,3 +153,33 @@ class TokenAuthTests(TestCase):
|
||||||
self.token.delete()
|
self.token.delete()
|
||||||
token = Token.objects.create(user=self.user)
|
token = Token.objects.create(user=self.user)
|
||||||
self.assertTrue(bool(token.key))
|
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, 200)
|
||||||
|
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, 200)
|
||||||
|
self.assertEqual(json.loads(response.content)['token'], self.key)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user