From 8f58ee489d34b200acfc2666816eb32e47c8cef5 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 10 May 2011 10:49:28 +0100 Subject: Getting the API into shape --- djangorestframework/permissions.py | 119 ++++++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 41 deletions(-) (limited to 'djangorestframework/permissions.py') diff --git a/djangorestframework/permissions.py b/djangorestframework/permissions.py index d98651e0..1b151558 100644 --- a/djangorestframework/permissions.py +++ b/djangorestframework/permissions.py @@ -1,66 +1,103 @@ 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.""" + """ + 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 has_permission(self, auth): - return True + def check_permission(self, auth): + """ + Should simply return, or raise an ErrorResponse. + """ + pass class FullAnonAccess(BasePermission): - """""" - def has_permission(self, auth): - return True + """ + Allows full access. + """ + + def check_permission(self, user): + pass + class IsAuthenticated(BasePermission): - """""" - def has_permission(self, auth): - return auth is not None and auth.is_authenticated() - -#class IsUser(BasePermission): -# """The request has authenticated as a user.""" -# def has_permission(self, auth): -# pass -# -#class IsAdminUser(): -# """The request has authenticated as an admin user.""" -# def has_permission(self, auth): -# pass -# -#class IsUserOrIsAnonReadOnly(BasePermission): -# """The request has authenticated as a user, or is a read-only request.""" -# def has_permission(self, auth): -# pass -# -#class OAuthTokenInScope(BasePermission): -# def has_permission(self, auth): -# pass -# -#class UserHasModelPermissions(BasePermission): -# def has_permission(self, auth): -# pass - + """ + Allows access only to authenticated users. + """ -class Throttling(BasePermission): - """Rate throttling of requests on a per-user basis. + def check_permission(self, user): + if not user.is_authenticated(): + raise _403_FORBIDDEN_RESPONSE - The rate is set by a 'throttle' attribute on the view class. +class IsAdminUser(): + """ + 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 is set by a 'throttle' attribute on the ``View`` class. The attribute is a two tuple of the form (number of requests, duration in seconds). - The user's id will be used as a unique identifier if the user is authenticated. + 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 has_permission(self, auth): + + def check_permission(self, user): (num_requests, duration) = getattr(self.view, 'throttle', (0, 0)) - if auth.is_authenticated(): + if user.is_authenticated(): ident = str(auth) else: ident = self.view.request.META.get('REMOTE_ADDR', None) @@ -74,7 +111,7 @@ class Throttling(BasePermission): history.pop() if len(history) >= num_requests: - raise ErrorResponse(status.HTTP_503_SERVICE_UNAVAILABLE, {'detail': 'request was throttled'}) + raise _503_THROTTLED_RESPONSE history.insert(0, now) - cache.set(key, history, duration) + cache.set(key, history, duration) -- cgit v1.2.3