Refactoring of authentication/permissions

This commit is contained in:
Tom Christie 2011-04-11 13:45:38 +01:00
parent 941742593c
commit cb9fb6ef2f
4 changed files with 50 additions and 27 deletions

View File

@ -10,26 +10,6 @@ from djangorestframework.utils import as_tuple
import base64
class AuthenticatorMixin(object):
"""Adds pluggable authentication behaviour."""
"""The set of authenticators to use."""
authenticators = None
def authenticate(self, request):
"""Attempt to authenticate the request, returning an authentication context or None.
An authentication context may be any object, although in many cases it will simply be a :class:`User` instance."""
# Attempt authentication against each authenticator in turn,
# and return None if no authenticators succeed in authenticating the request.
for authenticator in as_tuple(self.authenticators):
auth_context = authenticator(self).authenticate(request)
if auth_context:
return auth_context
return None
class BaseAuthenticator(object):
"""All authenticators should extend BaseAuthenticator."""

View File

@ -9,7 +9,7 @@ from django.http.multipartparser import LimitBytes
from StringIO import StringIO
class RequestMixin(object):
"""Mixin behaviour to deal with requests."""
"""Mixin class to provide request parsing behaviour."""
USE_FORM_OVERLOADING = True
METHOD_PARAM = "_method"
@ -214,3 +214,42 @@ class RequestMixin(object):
class AuthMixin(object):
"""Mixin class to provide authentication and permissions."""
authenticators = ()
permitters = ()
@property
def auth(self):
if not hasattr(self, '_auth'):
self._auth = self._authenticate()
return self._auth
# TODO?
#@property
#def user(self):
# if not has_attr(self, '_user'):
# auth = self.auth
# if isinstance(auth, User...):
# self._user = auth
# else:
# self._user = getattr(auth, 'user', None)
# return self._user
def check_permissions(self):
if not self.permissions:
return
auth = self.auth
for permitter_cls in self.permitters:
permitter = permission_cls(self)
permitter.permit(auth)
def _authenticate(self):
for authenticator_cls in self.authenticators:
authenticator = authenticator_cls(self)
auth = authenticator.authenticate(self.request)
if auth:
return auth
return None

View File

@ -6,7 +6,7 @@ from djangorestframework.emitters import EmitterMixin
from djangorestframework.authenticators import AuthenticatorMixin
from djangorestframework.validators import FormValidatorMixin
from djangorestframework.response import Response, ResponseException
from djangorestframework.request import RequestMixin
from djangorestframework.request import RequestMixin, AuthMixin
from djangorestframework import emitters, parsers, authenticators, status
@ -18,7 +18,7 @@ from djangorestframework import emitters, parsers, authenticators, status
__all__ = ['Resource']
class Resource(EmitterMixin, AuthenticatorMixin, FormValidatorMixin, RequestMixin, View):
class Resource(EmitterMixin, AuthMixin, FormValidatorMixin, RequestMixin, View):
"""Handles incoming requests and maps them to REST operations,
performing authentication, input deserialization, input validation, output serialization."""
@ -139,7 +139,7 @@ class Resource(EmitterMixin, AuthenticatorMixin, FormValidatorMixin, RequestMixi
# Typically the context will be a user, or None if this is an anonymous request,
# but it could potentially be more complex (eg the context of a request key which
# has been signed against a particular set of permissions)
auth_context = self.authenticate(request)
auth_context = self.auth
# If using a form POST with '_method'/'_content'/'_content_type' overrides, then alter
# self.method, self.content_type, self.CONTENT appropriately.
@ -173,6 +173,10 @@ class Resource(EmitterMixin, AuthenticatorMixin, FormValidatorMixin, RequestMixi
except ResponseException, exc:
response = exc.response
except:
import traceback
traceback.print_exc()
# Always add these headers.
#

View File

@ -8,7 +8,7 @@ class NoContent(object):
"""Used to indicate no body in http response.
(We cannot just use None, as that is a valid, serializable response object.)
TODO: On relflection I'm going to get rid of this and just not support serailized 'None' responses.
TODO: On reflection I'm going to get rid of this and just not support serialized 'None' responses.
"""
pass
@ -23,8 +23,8 @@ class Response(object):
@property
def status_text(self):
"""Return reason text corrosponding to our HTTP response status code.
Provided for convienience."""
"""Return reason text corresponding to our HTTP response status code.
Provided for convenience."""
return STATUS_CODE_TEXT.get(self.status, '')