diff options
Diffstat (limited to 'djangorestframework/permissions.py')
| -rw-r--r-- | djangorestframework/permissions.py | 124 | 
1 files changed, 124 insertions, 0 deletions
| diff --git a/djangorestframework/permissions.py b/djangorestframework/permissions.py new file mode 100644 index 00000000..1f6151f8 --- /dev/null +++ b/djangorestframework/permissions.py @@ -0,0 +1,124 @@ +""" +The :mod:`permissions` module bundles a set of  permission classes that are used  +for checking if a request passes a certain set of constraints. You can assign a permision  +class to your view by setting your View's :attr:`permissions` class attribute. +""" + +from django.core.cache import cache +from djangorestframework import status +from djangorestframework.response import ErrorResponse +import time + +__all__ = ( +    'BasePermission', +    'FullAnonAccess', +    'IsAuthenticated', +    'IsAdminUser', +    'IsUserOrIsAnonReadOnly', +    'PerUserThrottling' +) + + +_403_FORBIDDEN_RESPONSE = ErrorResponse( +    status.HTTP_403_FORBIDDEN, +    {'detail': 'You do not have permission to access this resource. ' + +               'You may need to login or otherwise authenticate the request.'}) + +_503_THROTTLED_RESPONSE = ErrorResponse( +    status.HTTP_503_SERVICE_UNAVAILABLE, +    {'detail': 'request was throttled'}) + + + +class BasePermission(object): +    """ +    A base class from which all permission classes should inherit. +    """ +    def __init__(self, view): +        """ +        Permission classes are always passed the current view on creation. +        """ +        self.view = view +     +    def check_permission(self, auth): +        """ +        Should simply return, or raise an :exc:`response.ErrorResponse`. +        """ +        pass + + +class FullAnonAccess(BasePermission): +    """ +    Allows full access. +    """ + +    def check_permission(self, user): +        pass + + +class IsAuthenticated(BasePermission): +    """ +    Allows access only to authenticated users. +    """ + +    def check_permission(self, user): +        if not user.is_authenticated(): +            raise _403_FORBIDDEN_RESPONSE  + + +class IsAdminUser(BasePermission): +    """ +    Allows access only to admin users. +    """ + +    def check_permission(self, user): +        if not user.is_admin(): +            raise _403_FORBIDDEN_RESPONSE + + +class IsUserOrIsAnonReadOnly(BasePermission): +    """ +    The request is authenticated as a user, or is a read-only request. +    """ + +    def check_permission(self, user):  +        if (not user.is_authenticated() and +            self.view.method != 'GET' and +            self.view.method != 'HEAD'): +            raise _403_FORBIDDEN_RESPONSE + + +class PerUserThrottling(BasePermission): +    """ +    Rate throttling of requests on a per-user basis. + +    The rate (requests / seconds) is set by a :attr:`throttle` attribute on the ``View`` class. +    The attribute is a two tuple of the form (number of requests, duration in seconds). + +    The user id will be used as a unique identifier if the user is authenticated. +    For anonymous requests, the IP address of the client will be used. + +    Previous request information used for throttling is stored in the cache. +    """ + +    def check_permission(self, user): +        (num_requests, duration) = getattr(self.view, 'throttle', (0, 0)) + +        if user.is_authenticated(): +            ident = str(auth) +        else: +            ident = self.view.request.META.get('REMOTE_ADDR', None) + +        key = 'throttle_%s' % ident +        history = cache.get(key, []) +        now = time.time() +         +        # Drop any requests from the history which have now passed the throttle duration +        while history and history[0] < now - duration: +            history.pop() + +        if len(history) >= num_requests: +            raise _503_THROTTLED_RESPONSE + +        history.insert(0, now) +        cache.set(key, history, duration) | 
