mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-27 03:54:01 +03:00
Add a TokenAuthentication class in a sub-application
This commit is contained in:
parent
72bdd0fcec
commit
f3e65eab6b
|
@ -90,6 +90,7 @@ INSTALLED_APPS = (
|
||||||
# Uncomment the next line to enable admin documentation:
|
# Uncomment the next line to enable admin documentation:
|
||||||
# 'django.contrib.admindocs',
|
# 'django.contrib.admindocs',
|
||||||
'djangorestframework',
|
'djangorestframework',
|
||||||
|
'djangorestframework.tokenauth',
|
||||||
)
|
)
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
|
|
|
@ -8,6 +8,9 @@ from django.http import HttpResponse
|
||||||
from djangorestframework.views import APIView
|
from djangorestframework.views import APIView
|
||||||
from djangorestframework import permissions
|
from djangorestframework import permissions
|
||||||
|
|
||||||
|
from djangorestframework.tokenauth.models import Token
|
||||||
|
from djangorestframework.tokenauth.authentication import TokenAuthentication
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,6 +23,8 @@ class MockView(APIView):
|
||||||
def put(self, request):
|
def put(self, request):
|
||||||
return HttpResponse({'a': 1, 'b': 2, 'c': 3})
|
return HttpResponse({'a': 1, 'b': 2, 'c': 3})
|
||||||
|
|
||||||
|
MockView.authentication += (TokenAuthentication,)
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
(r'^$', MockView.as_view()),
|
(r'^$', MockView.as_view()),
|
||||||
)
|
)
|
||||||
|
@ -104,3 +109,40 @@ class SessionAuthTests(TestCase):
|
||||||
"""
|
"""
|
||||||
response = self.csrf_client.post('/', {'example': 'example'})
|
response = self.csrf_client.post('/', {'example': 'example'})
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
|
||||||
|
class TokenAuthTests(TestCase):
|
||||||
|
"""Token authentication"""
|
||||||
|
urls = 'djangorestframework.tests.authentication'
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.csrf_client = Client(enforce_csrf_checks=True)
|
||||||
|
self.username = 'john'
|
||||||
|
self.email = 'lennon@thebeatles.com'
|
||||||
|
self.password = 'password'
|
||||||
|
self.user = User.objects.create_user(self.username, self.email, self.password)
|
||||||
|
|
||||||
|
self.key = 'abcd1234'
|
||||||
|
self.token = Token.objects.create(key=self.key, user=self.user)
|
||||||
|
|
||||||
|
def test_post_form_passing_token_auth(self):
|
||||||
|
"""Ensure POSTing json over token auth with correct credentials passes and does not require CSRF"""
|
||||||
|
auth = self.key
|
||||||
|
response = self.csrf_client.post('/', {'example': 'example'}, HTTP_AUTHORIZATION=auth)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_post_json_passing_token_auth(self):
|
||||||
|
"""Ensure POSTing form over token auth with correct credentials passes and does not require CSRF"""
|
||||||
|
auth = self.key
|
||||||
|
response = self.csrf_client.post('/', json.dumps({'example': 'example'}), 'application/json', HTTP_AUTHORIZATION=auth)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_post_form_failing_token_auth(self):
|
||||||
|
"""Ensure POSTing form over token auth without correct credentials fails"""
|
||||||
|
response = self.csrf_client.post('/', {'example': 'example'})
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
def test_post_json_failing_token_auth(self):
|
||||||
|
"""Ensure POSTing json over token auth without correct credentials fails"""
|
||||||
|
response = self.csrf_client.post('/', json.dumps({'example': 'example'}), 'application/json')
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
0
djangorestframework/tokenauth/__init__.py
Normal file
0
djangorestframework/tokenauth/__init__.py
Normal file
33
djangorestframework/tokenauth/authentication.py
Normal file
33
djangorestframework/tokenauth/authentication.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
from djangorestframework.authentication import BaseAuthentication
|
||||||
|
from .models import Token
|
||||||
|
|
||||||
|
class TokenAuthentication(BaseAuthentication):
|
||||||
|
"""
|
||||||
|
Use a token model for authentication.
|
||||||
|
|
||||||
|
A custom token model may be used here, but must have the following minimum
|
||||||
|
properties:
|
||||||
|
|
||||||
|
* key -- The string identifying the token
|
||||||
|
* user -- The user to which the token belongs
|
||||||
|
* revoked -- The status of the token
|
||||||
|
|
||||||
|
The BaseToken class is available as an abstract model to be derived from.
|
||||||
|
|
||||||
|
The token key should be passed in as a string to the "Authorization" HTTP
|
||||||
|
header.
|
||||||
|
"""
|
||||||
|
model = Token
|
||||||
|
|
||||||
|
def authenticate(self, request):
|
||||||
|
key = request.META.get('HTTP_AUTHORIZATION', '').strip()
|
||||||
|
if not key:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
token = self.model.objects.get(key=key)
|
||||||
|
except self.model.DoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if token.user.is_active and not token.revoked:
|
||||||
|
return (token.user, token)
|
19
djangorestframework/tokenauth/models.py
Normal file
19
djangorestframework/tokenauth/models.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class BaseToken(models.Model):
|
||||||
|
"""
|
||||||
|
The base abstract authorization token model class.
|
||||||
|
"""
|
||||||
|
key = models.CharField(max_length=32, primary_key=True)
|
||||||
|
user = models.ForeignKey('auth.User')
|
||||||
|
revoked = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract=True
|
||||||
|
|
||||||
|
|
||||||
|
class Token(BaseToken):
|
||||||
|
"""
|
||||||
|
The default authorization token model class.
|
||||||
|
"""
|
||||||
|
pass
|
Loading…
Reference in New Issue
Block a user