mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-04 09:57:55 +03:00 
			
		
		
		
	Refactoring of authentication/permissions
This commit is contained in:
		
							parent
							
								
									941742593c
								
							
						
					
					
						commit
						cb9fb6ef2f
					
				| 
						 | 
					@ -10,26 +10,6 @@ from djangorestframework.utils import as_tuple
 | 
				
			||||||
import base64
 | 
					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):
 | 
					class BaseAuthenticator(object):
 | 
				
			||||||
    """All authenticators should extend BaseAuthenticator."""
 | 
					    """All authenticators should extend BaseAuthenticator."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,7 @@ from django.http.multipartparser import LimitBytes
 | 
				
			||||||
from StringIO import StringIO
 | 
					from StringIO import StringIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RequestMixin(object):
 | 
					class RequestMixin(object):
 | 
				
			||||||
    """Mixin behaviour to deal with requests."""
 | 
					    """Mixin class to provide request parsing behaviour."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    USE_FORM_OVERLOADING = True
 | 
					    USE_FORM_OVERLOADING = True
 | 
				
			||||||
    METHOD_PARAM = "_method"
 | 
					    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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,7 @@ from djangorestframework.emitters import EmitterMixin
 | 
				
			||||||
from djangorestframework.authenticators import AuthenticatorMixin
 | 
					from djangorestframework.authenticators import AuthenticatorMixin
 | 
				
			||||||
from djangorestframework.validators import FormValidatorMixin
 | 
					from djangorestframework.validators import FormValidatorMixin
 | 
				
			||||||
from djangorestframework.response import Response, ResponseException
 | 
					from djangorestframework.response import Response, ResponseException
 | 
				
			||||||
from djangorestframework.request import RequestMixin
 | 
					from djangorestframework.request import RequestMixin, AuthMixin
 | 
				
			||||||
from djangorestframework import emitters, parsers, authenticators, status
 | 
					from djangorestframework import emitters, parsers, authenticators, status
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@ from djangorestframework import emitters, parsers, authenticators, status
 | 
				
			||||||
__all__ = ['Resource']
 | 
					__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,
 | 
					    """Handles incoming requests and maps them to REST operations,
 | 
				
			||||||
    performing authentication, input deserialization, input validation, output serialization."""
 | 
					    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,
 | 
					            # 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
 | 
					            # but it could potentially be more complex (eg the context of a request key which
 | 
				
			||||||
            # has been signed against a particular set of permissions)
 | 
					            # 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
 | 
					            # If using a form POST with '_method'/'_content'/'_content_type' overrides, then alter
 | 
				
			||||||
            # self.method, self.content_type, self.CONTENT appropriately.
 | 
					            # self.method, self.content_type, self.CONTENT appropriately.
 | 
				
			||||||
| 
						 | 
					@ -174,6 +174,10 @@ class Resource(EmitterMixin, AuthenticatorMixin, FormValidatorMixin, RequestMixi
 | 
				
			||||||
        except ResponseException, exc:
 | 
					        except ResponseException, exc:
 | 
				
			||||||
            response = exc.response
 | 
					            response = exc.response
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            import traceback
 | 
				
			||||||
 | 
					            traceback.print_exc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Always add these headers.
 | 
					        # Always add these headers.
 | 
				
			||||||
        #
 | 
					        #
 | 
				
			||||||
        # TODO - this isn't actually the correct way to set the vary header,
 | 
					        # TODO - this isn't actually the correct way to set the vary header,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@ class NoContent(object):
 | 
				
			||||||
    """Used to indicate no body in http response.
 | 
					    """Used to indicate no body in http response.
 | 
				
			||||||
    (We cannot just use None, as that is a valid, serializable response object.)
 | 
					    (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
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,8 +23,8 @@ class Response(object):
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def status_text(self):
 | 
					    def status_text(self):
 | 
				
			||||||
        """Return reason text corrosponding to our HTTP response status code.
 | 
					        """Return reason text corresponding to our HTTP response status code.
 | 
				
			||||||
        Provided for convienience."""
 | 
					        Provided for convenience."""
 | 
				
			||||||
        return STATUS_CODE_TEXT.get(self.status, '')
 | 
					        return STATUS_CODE_TEXT.get(self.status, '')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user