I currently have a simple model defined, with a photoupload feature using django thumbnails plugin.
but when i try to upload it gives me the following error:
OSError at /admin/products/photo/add/
(13, 'Permission denied')
Now, i know this is seems to be a permission issue, so the first thing i checked were permissions on the directory and changed these to 777 (Just to Test), restarted the server and fcgi and it still gives the error.
Traceback
Traceback: File "/usr/lib/python2.6/dist-packages/django/core/handlers/base.py" in get_response
92. response = callback(request, *callback_args,
**callback_kwargs) File "/usr/lib/python2.6/dist-packages/django/contrib/admin/options.py" in wrapper
226. return self.admin_site.admin_view(view)(*args,
**kwargs) File "/usr/lib/python2.6/dist-packages/django/views/decorators/cache.py" in _wrapped_view_func
44. response = view_func(request, *args, **kwargs) File "/usr/lib/python2.6/dist-packages/django/contrib/admin/sites.py" in inner
186. return view(request, *args, **kwargs) File "/usr/lib/python2.6/dist-packages/django/db/transaction.py" in _commit_on_success
240. res = func(*args, **kw) File "/usr/lib/python2.6/dist-packages/django/contrib/admin/options.py" in add_view
734. self.save_model(request, new_object, form, change=False) File "/usr/lib/python2.6/dist-packages/django/contrib/admin/options.py" in save_model
557. obj.save() File "/usr/lib/python2.6/dist-packages/django/db/models/base.py" in save
410. self.save_base(force_insert=force_insert, force_update=force_update) File "/usr/lib/python2.6/dist-packages/django/db/models/base.py" in save_base
483. values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields if not isinstance(f, AutoField)] File "/usr/lib/python2.6/dist-packages/django/db/models/fields/files.py" in pre_save
252. file.save(file.name, file, save=False) File "/var/www/django_projects/gang/../gang/products/thumbs.py" in save
84. super(ImageWithThumbsFieldFile, self).save(name, content, save) File "/usr/lib/python2.6/dist-packages/django/db/models/fields/files.py" in save
91. self.name = self.storage.save(name, content) File "/usr/lib/python2.6/dist-packages/django/core/files/storage.py" in save
47. name = self._save(name, content) File "/usr/lib/python2.6/dist-packages/django/core/files/storage.py" in _save
146. os.makedirs(directory) File "/usr/lib/python2.6/os.py" in makedirs
150. makedirs(head, mode) File "/usr/lib/python2.6/os.py" in makedirs
150. makedirs(head, mode) File "/usr/lib/python2.6/os.py" in makedirs
150. makedirs(head, mode) File "/usr/lib/python2.6/os.py" in makedirs
157. mkdir(name, mode)
Exception Type: OSError at /admin/products/photo/add/ Exception Value: (13, 'Permission denied')
The user that the FCGI daemon is being run on definitely has access to read and write to that directory.
From settings.py
MEDIA_ROOT = '/var/www/sites/gang/http/media/'
MEDIA_ROOT_URL = '/media/'
-
Getting Help
-
el
-
es
-
fr
-
id
-
it
-
ja
-
ko
-
pl
-
pt-br
-
zh-hans
- Language: en
-
1.8
-
1.10
-
1.11
-
2.0
-
2.1
-
2.2
-
3.0
-
3.1
-
3.2
-
4.0
-
4.2
-
dev
-
Documentation version:
4.1
Built-in Views¶
Several of Django’s built-in views are documented in
Writing views as well as elsewhere in the documentation.
Serving files in development¶
-
static.
serve
(request, path, document_root, show_indexes=False)¶
There may be files other than your project’s static assets that, for
convenience, you’d like to have Django serve for you in local development.
The serve()
view can be used to serve any directory
you give it. (This view is not hardened for production use and should be
used only as a development aid; you should serve these files in production
using a real front-end web server).
The most likely example is user-uploaded content in MEDIA_ROOT
.
django.contrib.staticfiles
is intended for static assets and has no
built-in handling for user-uploaded files, but you can have Django serve your
MEDIA_ROOT
by appending something like this to your URLconf:
from django.conf import settings from django.urls import re_path from django.views.static import serve # ... the rest of your URLconf goes here ... if settings.DEBUG: urlpatterns += [ re_path(r'^media/(?P<path>.*)$', serve, { 'document_root': settings.MEDIA_ROOT, }), ]
Note, the snippet assumes your MEDIA_URL
has a value of
'media/'
. This will call the serve()
view,
passing in the path from the URLconf and the (required) document_root
parameter.
Since it can become a bit cumbersome to define this URL pattern, Django
ships with a small URL helper function static()
that takes as parameters the prefix such as MEDIA_URL
and a dotted
path to a view, such as 'django.views.static.serve'
. Any other function
parameter will be transparently passed to the view.
Error views¶
Django comes with a few views by default for handling HTTP errors. To override
these with your own custom views, see Customizing error views.
The 404 (page not found) view¶
-
defaults.
page_not_found
(request, exception, template_name=‘404.html’)¶
When you raise Http404
from within a view, Django loads a
special view devoted to handling 404 errors. By default, it’s the view
django.views.defaults.page_not_found()
, which either produces a “Not
Found” message or loads and renders the template 404.html
if you created it
in your root template directory.
The default 404 view will pass two variables to the template: request_path
,
which is the URL that resulted in the error, and exception
, which is a
useful representation of the exception that triggered the view (e.g. containing
any message passed to a specific Http404
instance).
Three things to note about 404 views:
- The 404 view is also called if Django doesn’t find a match after
checking every regular expression in the URLconf. - The 404 view is passed a
RequestContext
and
will have access to variables supplied by your template context
processors (e.g.MEDIA_URL
). - If
DEBUG
is set toTrue
(in your settings module), then
your 404 view will never be used, and your URLconf will be displayed
instead, with some debug information.
The 500 (server error) view¶
-
defaults.
server_error
(request, template_name=‘500.html’)¶
Similarly, Django executes special-case behavior in the case of runtime errors
in view code. If a view results in an exception, Django will, by default, call
the view django.views.defaults.server_error
, which either produces a
“Server Error” message or loads and renders the template 500.html
if you
created it in your root template directory.
The default 500 view passes no variables to the 500.html
template and is
rendered with an empty Context
to lessen the chance of additional errors.
If DEBUG
is set to True
(in your settings module), then
your 500 view will never be used, and the traceback will be displayed
instead, with some debug information.
The 403 (HTTP Forbidden) view¶
-
defaults.
permission_denied
(request, exception, template_name=‘403.html’)¶
In the same vein as the 404 and 500 views, Django has a view to handle 403
Forbidden errors. If a view results in a 403 exception then Django will, by
default, call the view django.views.defaults.permission_denied
.
This view loads and renders the template 403.html
in your root template
directory, or if this file does not exist, instead serves the text
“403 Forbidden”, as per RFC 7231#section-6.5.3 (the HTTP 1.1 Specification).
The template context contains exception
, which is the string
representation of the exception that triggered the view.
django.views.defaults.permission_denied
is triggered by a
PermissionDenied
exception. To deny access in a
view you can use code like this:
from django.core.exceptions import PermissionDenied def edit(request, pk): if not request.user.is_staff: raise PermissionDenied # ...
The 400 (bad request) view¶
-
defaults.
bad_request
(request, exception, template_name=‘400.html’)¶
When a SuspiciousOperation
is raised in Django,
it may be handled by a component of Django (for example resetting the session
data). If not specifically handled, Django will consider the current request a
‘bad request’ instead of a server error.
django.views.defaults.bad_request
, is otherwise very similar to the
server_error
view, but returns with the status code 400 indicating that
the error condition was the result of a client operation. By default, nothing
related to the exception that triggered the view is passed to the template
context, as the exception message might contain sensitive information like
filesystem paths.
bad_request
views are also only used when DEBUG
is False
.
Back to Top
Содержание
- Documentation
- Built-in Views¶
- Serving files in development¶
- Error views¶
- The 404 (page not found) view¶
- The 500 (server error) view¶
- The 403 (HTTP Forbidden) view¶
- The 400 (bad request) view¶
- Exceptions
- Exception handling in REST framework views
- Custom exception handling
- API Reference
- APIException
- Inspecting API exceptions
- ParseError
- AuthenticationFailed
- NotAuthenticated
- PermissionDenied
- NotFound
- MethodNotAllowed
- NotAcceptable
- UnsupportedMediaType
- Throttled
- ValidationError
- Generic Error Views
- rest_framework.exceptions.server_error
- rest_framework.exceptions.bad_request
- Third party packages
- DRF Standardized Errors
- django.core.exceptions PermissionDenied Example Code
- Example 1 from django-allauth
- Example 2 from django-axes
- Example 3 from django-cms
- Example 4 from django-downloadview
- Example 5 from django-filer
- Example 6 from django-guardian
- Example 7 from django-haystack
- Example 8 from django-import-export
- Example 9 from django-loginas
- Example 10 from django-rest-framework
- Example 11 from wagtail
Documentation
Built-in Views¶
Several of Django’s built-in views are documented in Writing views as well as elsewhere in the documentation.
Serving files in development¶
There may be files other than your project’s static assets that, for convenience, you’d like to have Django serve for you in local development. The serve() view can be used to serve any directory you give it. (This view is not hardened for production use and should be used only as a development aid; you should serve these files in production using a real front-end web server).
The most likely example is user-uploaded content in MEDIA_ROOT . django.contrib.staticfiles is intended for static assets and has no built-in handling for user-uploaded files, but you can have Django serve your MEDIA_ROOT by appending something like this to your URLconf:
Note, the snippet assumes your MEDIA_URL has a value of ‘media/’ . This will call the serve() view, passing in the path from the URLconf and the (required) document_root parameter.
Since it can become a bit cumbersome to define this URL pattern, Django ships with a small URL helper function static() that takes as parameters the prefix such as MEDIA_URL and a dotted path to a view, such as ‘django.views.static.serve’ . Any other function parameter will be transparently passed to the view.
Error views¶
Django comes with a few views by default for handling HTTP errors. To override these with your own custom views, see Customizing error views .
The 404 (page not found) view¶
When you raise Http404 from within a view, Django loads a special view devoted to handling 404 errors. By default, it’s the view django.views.defaults.page_not_found() , which either produces a “Not Found” message or loads and renders the template 404.html if you created it in your root template directory.
The default 404 view will pass two variables to the template: request_path , which is the URL that resulted in the error, and exception , which is a useful representation of the exception that triggered the view (e.g. containing any message passed to a specific Http404 instance).
Three things to note about 404 views:
- The 404 view is also called if Django doesn’t find a match after checking every regular expression in the URLconf.
- The 404 view is passed a RequestContext and will have access to variables supplied by your template context processors (e.g. MEDIA_URL ).
- If DEBUG is set to True (in your settings module), then your 404 view will never be used, and your URLconf will be displayed instead, with some debug information.
The 500 (server error) view¶
Similarly, Django executes special-case behavior in the case of runtime errors in view code. If a view results in an exception, Django will, by default, call the view django.views.defaults.server_error , which either produces a “Server Error” message or loads and renders the template 500.html if you created it in your root template directory.
The default 500 view passes no variables to the 500.html template and is rendered with an empty Context to lessen the chance of additional errors.
If DEBUG is set to True (in your settings module), then your 500 view will never be used, and the traceback will be displayed instead, with some debug information.
The 403 (HTTP Forbidden) view¶
In the same vein as the 404 and 500 views, Django has a view to handle 403 Forbidden errors. If a view results in a 403 exception then Django will, by default, call the view django.views.defaults.permission_denied .
This view loads and renders the template 403.html in your root template directory, or if this file does not exist, instead serves the text “403 Forbidden”, as per RFC 7231#section-6.5.3 (the HTTP 1.1 Specification). The template context contains exception , which is the string representation of the exception that triggered the view.
django.views.defaults.permission_denied is triggered by a PermissionDenied exception. To deny access in a view you can use code like this:
The 400 (bad request) view¶
When a SuspiciousOperation is raised in Django, it may be handled by a component of Django (for example resetting the session data). If not specifically handled, Django will consider the current request a ‘bad request’ instead of a server error.
django.views.defaults.bad_request , is otherwise very similar to the server_error view, but returns with the status code 400 indicating that the error condition was the result of a client operation. By default, nothing related to the exception that triggered the view is passed to the template context, as the exception message might contain sensitive information like filesystem paths.
bad_request views are also only used when DEBUG is False .
Источник
Exceptions
Exceptions… allow error handling to be organized cleanly in a central or high-level place within the program structure.
Exception handling in REST framework views
REST framework’s views handle various exceptions, and deal with returning appropriate error responses.
The handled exceptions are:
- Subclasses of APIException raised inside REST framework.
- Django’s Http404 exception.
- Django’s PermissionDenied exception.
In each case, REST framework will return a response with an appropriate status code and content-type. The body of the response will include any additional details regarding the nature of the error.
Most error responses will include a key detail in the body of the response.
For example, the following request:
Might receive an error response indicating that the DELETE method is not allowed on that resource:
Validation errors are handled slightly differently, and will include the field names as the keys in the response. If the validation error was not specific to a particular field then it will use the «non_field_errors» key, or whatever string value has been set for the NON_FIELD_ERRORS_KEY setting.
An example validation error might look like this:
Custom exception handling
You can implement custom exception handling by creating a handler function that converts exceptions raised in your API views into response objects. This allows you to control the style of error responses used by your API.
The function must take a pair of arguments, the first is the exception to be handled, and the second is a dictionary containing any extra context such as the view currently being handled. The exception handler function should either return a Response object, or return None if the exception cannot be handled. If the handler returns None then the exception will be re-raised and Django will return a standard HTTP 500 ‘server error’ response.
For example, you might want to ensure that all error responses include the HTTP status code in the body of the response, like so:
In order to alter the style of the response, you could write the following custom exception handler:
The context argument is not used by the default handler, but can be useful if the exception handler needs further information such as the view currently being handled, which can be accessed as context[‘view’] .
The exception handler must also be configured in your settings, using the EXCEPTION_HANDLER setting key. For example:
If not specified, the ‘EXCEPTION_HANDLER’ setting defaults to the standard exception handler provided by REST framework:
Note that the exception handler will only be called for responses generated by raised exceptions. It will not be used for any responses returned directly by the view, such as the HTTP_400_BAD_REQUEST responses that are returned by the generic views when serializer validation fails.
API Reference
APIException
Signature: APIException()
The base class for all exceptions raised inside an APIView class or @api_view .
To provide a custom exception, subclass APIException and set the .status_code , .default_detail , and default_code attributes on the class.
For example, if your API relies on a third party service that may sometimes be unreachable, you might want to implement an exception for the «503 Service Unavailable» HTTP response code. You could do this like so:
Inspecting API exceptions
There are a number of different properties available for inspecting the status of an API exception. You can use these to build custom exception handling for your project.
The available attributes and methods are:
- .detail — Return the textual description of the error.
- .get_codes() — Return the code identifier of the error.
- .get_full_details() — Return both the textual description and the code identifier.
In most cases the error detail will be a simple item:
In the case of validation errors the error detail will be either a list or dictionary of items:
ParseError
Signature: ParseError(detail=None, code=None)
Raised if the request contains malformed data when accessing request.data .
By default this exception results in a response with the HTTP status code «400 Bad Request».
AuthenticationFailed
Signature: AuthenticationFailed(detail=None, code=None)
Raised when an incoming request includes incorrect authentication.
By default this exception results in a response with the HTTP status code «401 Unauthenticated», but it may also result in a «403 Forbidden» response, depending on the authentication scheme in use. See the authentication documentation for more details.
NotAuthenticated
Signature: NotAuthenticated(detail=None, code=None)
Raised when an unauthenticated request fails the permission checks.
By default this exception results in a response with the HTTP status code «401 Unauthenticated», but it may also result in a «403 Forbidden» response, depending on the authentication scheme in use. See the authentication documentation for more details.
PermissionDenied
Signature: PermissionDenied(detail=None, code=None)
Raised when an authenticated request fails the permission checks.
By default this exception results in a response with the HTTP status code «403 Forbidden».
NotFound
Signature: NotFound(detail=None, code=None)
Raised when a resource does not exists at the given URL. This exception is equivalent to the standard Http404 Django exception.
By default this exception results in a response with the HTTP status code «404 Not Found».
MethodNotAllowed
Signature: MethodNotAllowed(method, detail=None, code=None)
Raised when an incoming request occurs that does not map to a handler method on the view.
By default this exception results in a response with the HTTP status code «405 Method Not Allowed».
NotAcceptable
Signature: NotAcceptable(detail=None, code=None)
Raised when an incoming request occurs with an Accept header that cannot be satisfied by any of the available renderers.
By default this exception results in a response with the HTTP status code «406 Not Acceptable».
Signature: UnsupportedMediaType(media_type, detail=None, code=None)
Raised if there are no parsers that can handle the content type of the request data when accessing request.data .
By default this exception results in a response with the HTTP status code «415 Unsupported Media Type».
Throttled
Signature: Throttled(wait=None, detail=None, code=None)
Raised when an incoming request fails the throttling checks.
By default this exception results in a response with the HTTP status code «429 Too Many Requests».
ValidationError
Signature: ValidationError(detail, code=None)
The ValidationError exception is slightly different from the other APIException classes:
- The detail argument is mandatory, not optional.
- The detail argument may be a list or dictionary of error details, and may also be a nested data structure. By using a dictionary, you can specify field-level errors while performing object-level validation in the validate() method of a serializer. For example. raise serializers.ValidationError(<‘name’: ‘Please enter a valid name.’>)
- By convention you should import the serializers module and use a fully qualified ValidationError style, in order to differentiate it from Django’s built-in validation error. For example. raise serializers.ValidationError(‘This field must be an integer value.’)
The ValidationError class should be used for serializer and field validation, and by validator classes. It is also raised when calling serializer.is_valid with the raise_exception keyword argument:
The generic views use the raise_exception=True flag, which means that you can override the style of validation error responses globally in your API. To do so, use a custom exception handler, as described above.
By default this exception results in a response with the HTTP status code «400 Bad Request».
Generic Error Views
Django REST Framework provides two error views suitable for providing generic JSON 500 Server Error and 400 Bad Request responses. (Django’s default error views provide HTML responses, which may not be appropriate for an API-only application.)
rest_framework.exceptions.server_error
Returns a response with status code 500 and application/json content type.
Set as handler500 :
rest_framework.exceptions.bad_request
Returns a response with status code 400 and application/json content type.
Set as handler400 :
Third party packages
The following third-party packages are also available.
DRF Standardized Errors
The drf-standardized-errors package provides an exception handler that generates the same format for all 4xx and 5xx responses. It is a drop-in replacement for the default exception handler and allows customizing the error response format without rewriting the whole exception handler. The standardized error response format is easier to document and easier to handle by API consumers.
Источник
django.core.exceptions PermissionDenied Example Code
PermissionDenied is a class within the django.core.exceptions module of the Django project.
Example 1 from django-allauth
django-allauth (project website) is a Django library for easily adding local and social authentication flows to Django projects. It is open source under the MIT License.
Example 2 from django-axes
django-axes (project documentation and PyPI package information is a code library for Django projects to track failed login attempts against a web application. The goal of the project is to make it easier for you to stop people and scripts from hacking your Django-powered website.
The code for django-axes is open source under the MIT license and maintained by the group of developers known as Jazzband.
Example 3 from django-cms
django-cms (project website) is a Python-based content management system (CMS) library for use with Django web apps that is open sourced under the BSD 3-Clause «New» license.
Example 4 from django-downloadview
django-downloadview (project documentation and PyPI package information) is a Django extension for serving downloads through your web application. While typically you would use a web server to handle static content, sometimes you need to control file access, such as requiring a user to register before downloading a PDF. In that situations, django-downloadview is a handy library to avoid boilerplate code for common scenarios.
Example 5 from django-filer
django-filer (project documentation) is a file management library for uploading and organizing files and images in Django’s admin interface. The project’s code is available under the BSD 3-Clause «New» or «Revised» open source license.
Example 6 from django-guardian
django-guardian (project documentation and PyPI page) provides per-object permissions in Django projects by enhancing the existing authentication backend. The project’s code is open source under the MIT license.
Example 7 from django-haystack
django-haystack (project website and PyPI page) is a search abstraction layer that separates the Python search code in a Django web application from the search engine implementation that it runs on, such as Apache Solr, Elasticsearch or Whoosh.
The django-haystack project is open source under the BSD license.
Example 8 from django-import-export
django-import-export (documentation and PyPI page) is a Django code library for importing and exporting data from the Django Admin. The tool supports many export and import formats such as CSV, JSON and YAML. django-import-export is open source under the BSD 2-Clause «Simplified» License.
Example 9 from django-loginas
django-loginas (PyPI package information) is Django code library for admins to log into an application as another user, typically for debugging purposes.
django-loginas is open source under the BSD 3-Clause «New» or «Revised» License.
Example 10 from django-rest-framework
Django REST Framework (project homepage and documentation, PyPI package information and more resources on Full Stack Python), often abbreviated as «DRF», is a popular Django extension for building web APIs. The project has fantastic documentation and a wonderful quickstart that serve as examples of how to make it easier for newcomers to get started.
The project is open sourced under the Encode OSS Ltd. license.
Example 11 from wagtail
wagtail (project website) is a fantastic Django-based CMS with code that is open source under the BSD 3-Clause «New» or «Revised» License.
Источник
permissions.py
Authentication or identification by itself is not usually sufficient to gain access to information or code. For that, the entity requesting access must have authorization.
— Apple Developer Documentation
Together with authentication and throttling, permissions determine whether a request should be granted or denied access.
Permission checks are always run at the very start of the view, before any other code is allowed to proceed. Permission checks will typically use the authentication information in the request.user
and request.auth
properties to determine if the incoming request should be permitted.
Permissions are used to grant or deny access for different classes of users to different parts of the API.
The simplest style of permission would be to allow access to any authenticated user, and deny access to any unauthenticated user. This corresponds to the IsAuthenticated
class in REST framework.
A slightly less strict style of permission would be to allow full access to authenticated users, but allow read-only access to unauthenticated users. This corresponds to the IsAuthenticatedOrReadOnly
class in REST framework.
How permissions are determined
Permissions in REST framework are always defined as a list of permission classes.
Before running the main body of the view each permission in the list is checked.
If any permission check fails, an exceptions.PermissionDenied
or exceptions.NotAuthenticated
exception will be raised, and the main body of the view will not run.
When the permission checks fail, either a «403 Forbidden» or a «401 Unauthorized» response will be returned, according to the following rules:
- The request was successfully authenticated, but permission was denied. — An HTTP 403 Forbidden response will be returned.
- The request was not successfully authenticated, and the highest priority authentication class does not use
WWW-Authenticate
headers. — An HTTP 403 Forbidden response will be returned. - The request was not successfully authenticated, and the highest priority authentication class does use
WWW-Authenticate
headers. — An HTTP 401 Unauthorized response, with an appropriateWWW-Authenticate
header will be returned.
Object level permissions
REST framework permissions also support object-level permissioning. Object level permissions are used to determine if a user should be allowed to act on a particular object, which will typically be a model instance.
Object level permissions are run by REST framework’s generic views when .get_object()
is called.
As with view level permissions, an exceptions.PermissionDenied
exception will be raised if the user is not allowed to act on the given object.
If you’re writing your own views and want to enforce object level permissions,
or if you override the get_object
method on a generic view, then you’ll need to explicitly call the .check_object_permissions(request, obj)
method on the view at the point at which you’ve retrieved the object.
This will either raise a PermissionDenied
or NotAuthenticated
exception, or simply return if the view has the appropriate permissions.
For example:
def get_object(self):
obj = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"])
self.check_object_permissions(self.request, obj)
return obj
Note: With the exception of DjangoObjectPermissions
, the provided
permission classes in rest_framework.permissions
do not implement the
methods necessary to check object permissions.
If you wish to use the provided permission classes in order to check object
permissions, you must subclass them and implement the
has_object_permission()
method described in the Custom
permissions section (below).
Limitations of object level permissions
For performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects.
Often when you’re using object level permissions you’ll also want to filter the queryset appropriately, to ensure that users only have visibility onto instances that they are permitted to view.
Because the get_object()
method is not called, object level permissions from the has_object_permission()
method are not applied when creating objects. In order to restrict object creation you need to implement the permission check either in your Serializer class or override the perform_create()
method of your ViewSet class.
Setting the permission policy
The default permission policy may be set globally, using the DEFAULT_PERMISSION_CLASSES
setting. For example.
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
If not specified, this setting defaults to allowing unrestricted access:
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
]
You can also set the authentication policy on a per-view, or per-viewset basis,
using the APIView
class-based views.
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
Or, if you’re using the @api_view
decorator with function based views.
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def example_view(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
Note: when you set new permission classes via the class attribute or decorators you’re telling the view to ignore the default list set in the settings.py file.
Provided they inherit from rest_framework.permissions.BasePermission
, permissions can be composed using standard Python bitwise operators. For example, IsAuthenticatedOrReadOnly
could be written:
from rest_framework.permissions import BasePermission, IsAuthenticated, SAFE_METHODS
from rest_framework.response import Response
from rest_framework.views import APIView
class ReadOnly(BasePermission):
def has_permission(self, request, view):
return request.method in SAFE_METHODS
class ExampleView(APIView):
permission_classes = [IsAuthenticated|ReadOnly]
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
Note: it supports & (and), | (or) and ~ (not).
API Reference
AllowAny
The AllowAny
permission class will allow unrestricted access, regardless of if the request was authenticated or unauthenticated.
This permission is not strictly required, since you can achieve the same result by using an empty list or tuple for the permissions setting, but you may find it useful to specify this class because it makes the intention explicit.
IsAuthenticated
The IsAuthenticated
permission class will deny permission to any unauthenticated user, and allow permission otherwise.
This permission is suitable if you want your API to only be accessible to registered users.
IsAdminUser
The IsAdminUser
permission class will deny permission to any user, unless user.is_staff
is True
in which case permission will be allowed.
This permission is suitable if you want your API to only be accessible to a subset of trusted administrators.
IsAuthenticatedOrReadOnly
The IsAuthenticatedOrReadOnly
will allow authenticated users to perform any request. Requests for unauthorised users will only be permitted if the request method is one of the «safe» methods; GET
, HEAD
or OPTIONS
.
This permission is suitable if you want to your API to allow read permissions to anonymous users, and only allow write permissions to authenticated users.
DjangoModelPermissions
This permission class ties into Django’s standard django.contrib.auth
model permissions. This permission must only be applied to views that have a .queryset
property or get_queryset()
method. Authorization will only be granted if the user is authenticated and has the relevant model permissions assigned. The appropriate model is determined by checking get_queryset().model
or queryset.model
.
POST
requests require the user to have theadd
permission on the model.PUT
andPATCH
requests require the user to have thechange
permission on the model.DELETE
requests require the user to have thedelete
permission on the model.
The default behaviour can also be overridden to support custom model permissions. For example, you might want to include a view
model permission for GET
requests.
To use custom model permissions, override DjangoModelPermissions
and set the .perms_map
property. Refer to the source code for details.
DjangoModelPermissionsOrAnonReadOnly
Similar to DjangoModelPermissions
, but also allows unauthenticated users to have read-only access to the API.
DjangoObjectPermissions
This permission class ties into Django’s standard object permissions framework that allows per-object permissions on models. In order to use this permission class, you’ll also need to add a permission backend that supports object-level permissions, such as django-guardian.
As with DjangoModelPermissions
, this permission must only be applied to views that have a .queryset
property or .get_queryset()
method. Authorization will only be granted if the user is authenticated and has the relevant per-object permissions and relevant model permissions assigned.
POST
requests require the user to have theadd
permission on the model instance.PUT
andPATCH
requests require the user to have thechange
permission on the model instance.DELETE
requests require the user to have thedelete
permission on the model instance.
Note that DjangoObjectPermissions
does not require the django-guardian
package, and should support other object-level backends equally well.
As with DjangoModelPermissions
you can use custom model permissions by overriding DjangoObjectPermissions
and setting the .perms_map
property. Refer to the source code for details.
Note: If you need object level view
permissions for GET
, HEAD
and OPTIONS
requests and are using django-guardian for your object-level permissions backend, you’ll want to consider using the DjangoObjectPermissionsFilter
class provided by the djangorestframework-guardian
package. It ensures that list endpoints only return results including objects for which the user has appropriate view permissions.
Custom permissions
To implement a custom permission, override BasePermission
and implement either, or both, of the following methods:
.has_permission(self, request, view)
.has_object_permission(self, request, view, obj)
The methods should return True
if the request should be granted access, and False
otherwise.
If you need to test if a request is a read operation or a write operation, you should check the request method against the constant SAFE_METHODS
, which is a tuple containing 'GET'
, 'OPTIONS'
and 'HEAD'
. For example:
if request.method in permissions.SAFE_METHODS:
# Check permissions for read-only request
else:
# Check permissions for write request
Note: The instance-level has_object_permission
method will only be called if the view-level has_permission
checks have already passed. Also note that in order for the instance-level checks to run, the view code should explicitly call .check_object_permissions(request, obj)
. If you are using the generic views then this will be handled for you by default. (Function-based views will need to check object permissions explicitly, raising PermissionDenied
on failure.)
Custom permissions will raise a PermissionDenied
exception if the test fails. To change the error message associated with the exception, implement a message
attribute directly on your custom permission. Otherwise the default_detail
attribute from PermissionDenied
will be used. Similarly, to change the code identifier associated with the exception, implement a code
attribute directly on your custom permission — otherwise the default_code
attribute from PermissionDenied
will be used.
from rest_framework import permissions
class CustomerAccessPermission(permissions.BasePermission):
message = 'Adding customers not allowed.'
def has_permission(self, request, view):
...
Examples
The following is an example of a permission class that checks the incoming request’s IP address against a blocklist, and denies the request if the IP has been blocked.
from rest_framework import permissions
class BlocklistPermission(permissions.BasePermission):
"""
Global permission check for blocked IPs.
"""
def has_permission(self, request, view):
ip_addr = request.META['REMOTE_ADDR']
blocked = Blocklist.objects.filter(ip_addr=ip_addr).exists()
return not blocked
As well as global permissions, that are run against all incoming requests, you can also create object-level permissions, that are only run against operations that affect a particular object instance. For example:
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Object-level permission to only allow owners of an object to edit it.
Assumes the model instance has an `owner` attribute.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Instance must have an attribute named `owner`.
return obj.owner == request.user
Note that the generic views will check the appropriate object level permissions, but if you’re writing your own custom views, you’ll need to make sure you check the object level permission checks yourself. You can do so by calling self.check_object_permissions(request, obj)
from the view once you have the object instance. This call will raise an appropriate APIException
if any object-level permission checks fail, and will otherwise simply return.
Also note that the generic views will only check the object-level permissions for views that retrieve a single model instance. If you require object-level filtering of list views, you’ll need to filter the queryset separately. See the filtering documentation for more details.
Overview of access restriction methods
REST framework offers three different methods to customize access restrictions on a case-by-case basis. These apply in different scenarios and have different effects and limitations.
queryset
/get_queryset()
: Limits the general visibility of existing objects from the database. The queryset limits which objects will be listed and which objects can be modified or deleted. Theget_queryset()
method can apply different querysets based on the current action.permission_classes
/get_permissions()
: General permission checks based on the current action, request and targeted object. Object level permissions can only be applied to retrieve, modify and deletion actions. Permission checks for list and create will be applied to the entire object type. (In case of list: subject to restrictions in the queryset.)serializer_class
/get_serializer()
: Instance level restrictions that apply to all objects on input and output. The serializer may have access to the request context. Theget_serializer()
method can apply different serializers based on the current action.
The following table lists the access restriction methods and the level of control they offer over which actions.
queryset |
permission_classes |
serializer_class |
|
---|---|---|---|
Action: list | global | global | object-level* |
Action: create | no | global | object-level |
Action: retrieve | global | object-level | object-level |
Action: update | global | object-level | object-level |
Action: partial_update | global | object-level | object-level |
Action: destroy | global | object-level | no |
Can reference action in decision | no** | yes | no** |
Can reference request in decision | no** | yes | yes |
* A Serializer class should not raise PermissionDenied in a list action, or the entire list would not be returned.
** The get_*()
methods have access to the current view and can return different Serializer or QuerySet instances based on the request or action.
Third party packages
The following third party packages are also available.
DRF — Access Policy
The Django REST — Access Policy package provides a way to define complex access rules in declarative policy classes that are attached to view sets or function-based views. The policies are defined in JSON in a format similar to AWS’ Identity & Access Management policies.
Composed Permissions
The Composed Permissions package provides a simple way to define complex and multi-depth (with logic operators) permission objects, using small and reusable components.
REST Condition
The REST Condition package is another extension for building complex permissions in a simple and convenient way. The extension allows you to combine permissions with logical operators.
DRY Rest Permissions
The DRY Rest Permissions package provides the ability to define different permissions for individual default and custom actions. This package is made for apps with permissions that are derived from relationships defined in the app’s data model. It also supports permission checks being returned to a client app through the API’s serializer. Additionally it supports adding permissions to the default and custom list actions to restrict the data they retrieve per user.
Django Rest Framework Roles
The Django Rest Framework Roles package makes it easier to parameterize your API over multiple types of users.
Django REST Framework API Key
The Django REST Framework API Key package provides permissions classes, models and helpers to add API key authorization to your API. It can be used to authorize internal or third-party backends and services (i.e. machines) which do not have a user account. API keys are stored securely using Django’s password hashing infrastructure, and they can be viewed, edited and revoked at anytime in the Django admin.
Django Rest Framework Role Filters
The Django Rest Framework Role Filters package provides simple filtering over multiple types of roles.
Django Rest Framework PSQ
The Django Rest Framework PSQ package is an extension that gives support for having action-based permission_classes, serializer_class, and queryset dependent on permission-based rules.
Разрешения¶
Аутентификация или идентификация сами по себе обычно недостаточны для получения доступа к информации или коду. Для этого субъект, запрашивающий доступ, должен иметь авторизацию.
‒ Apple Developer Documentation
Вместе с authentication и :doc:`throttling <throttling>`** , разрешения определяют, должен ли запрос быть удовлетворен или в доступе должно быть отказано.
Проверка разрешений всегда выполняется в самом начале представления, до того, как будет разрешено выполнение любого другого кода. Проверка разрешений обычно использует информацию об аутентификации в свойствах request.user
и request.auth
, чтобы определить, должен ли быть разрешен входящий запрос.
Разрешения используются для предоставления или запрета доступа различных классов пользователей к различным частям API.
Самый простой стиль разрешения — разрешить доступ любому аутентифицированному пользователю и запретить доступ любому неаутентифицированному пользователю. Это соответствует классу IsAuthenticated
в REST framework.
Чуть менее строгий стиль разрешения — разрешить полный доступ для аутентифицированных пользователей, но разрешить доступ только для чтения для неаутентифицированных пользователей. Это соответствует классу IsAuthenticatedOrReadOnly
в REST framework.
Как определяются разрешения¶
Разрешения в REST-фреймворке всегда определяются как список классов разрешений.
Перед запуском основной части представления проверяется каждое разрешение в списке. Если проверка какого-либо разрешения не прошла, будет вызвано исключение exceptions.PermissionDenied
или exceptions.NotAuthenticated
, и основное тело представления не будет запущено.
При неудачной проверке разрешений возвращается либо ответ «403 Forbidden», либо ответ «401 Unauthorized», в соответствии со следующими правилами:
-
Запрос был успешно аутентифицирован, но в разрешении было отказано. — Будет возвращен ответ HTTP 403 Forbidden.
-
Запрос не был успешно аутентифицирован, а класс аутентификации с наивысшим приоритетом не использует заголовки
WWW-Authenticate
. — Будет возвращен ответ HTTP 403 Forbidden. -
Запрос не был успешно аутентифицирован, а класс аутентификации с наивысшим приоритетом должен использовать заголовки
WWW-Authenticate
. — Будет возвращен ответ HTTP 401 Unauthorized с соответствующим заголовком «WWW-Authenticate«.
Разрешения на уровне объекта¶
Разрешения фреймворка REST также поддерживают разрешения на уровне объектов. Разрешения на уровне объекта используются для определения того, разрешено ли пользователю действовать с определенным объектом, который обычно является экземпляром модели.
Разрешения на уровне объектов выполняются общими представлениями REST framework при вызове .get_object()
. Как и в случае с разрешениями на уровне представления, исключение exceptions.PermissionDenied
будет вызвано, если пользователю не разрешено действовать с данным объектом.
Если вы пишете собственные представления и хотите обеспечить разрешения на уровне объектов, или если вы переопределите метод get_object
в общем представлении, то вам нужно будет явно вызвать метод .check_object_permissions(request, obj)
в представлении в тот момент, когда вы извлекли объект.
Это либо вызовет исключение PermissionDenied
или NotAuthenticated
, либо просто вернется, если представление имеет соответствующие разрешения.
Например:
def get_object(self): obj = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"]) self.check_object_permissions(self.request, obj) return obj
Примечание : За исключением DjangoObjectPermissions
, предоставленные классы разрешений в rest_framework.permissions
не реализуют методы, необходимые для проверки разрешений объектов.
Если вы хотите использовать предоставленные классы разрешений для проверки разрешений объектов, вы должны подклассифицировать их и реализовать метод has_object_permission()
, описанный в разделе ** *Custom permissions* (ниже).
Ограничения разрешений на уровне объекта¶
По причинам производительности общие представления не будут автоматически применять разрешения на уровне объекта к каждому экземпляру в наборе запросов при возврате списка объектов.
Часто, когда вы используете разрешения на уровне объекта, вы также хотите filter the queryset соответствующим образом, чтобы гарантировать, что пользователи имеют видимость только тех экземпляров, которые им разрешено просматривать.
Поскольку метод get_object()
не вызывается, разрешения объектного уровня из метода has_object_permission()
не применяются при создании объектов. Чтобы ограничить создание объектов, вам необходимо реализовать проверку прав либо в классе Serializer, либо переопределить метод perform_create()
> вашего класса ViewSet.
Настройка политики разрешений¶
Политика разрешений по умолчанию может быть установлена глобально, с помощью параметра DEFAULT_PERMISSION_CLASSES
. Например.
REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ] }
Если этот параметр не указан, то по умолчанию он разрешает неограниченный доступ:
'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.AllowAny', ]
Вы также можете установить политику аутентификации на основе каждого представления или каждого набора представлений, используя APIView
представления на основе класса.
from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView class ExampleView(APIView): permission_classes = [IsAuthenticated] def get(self, request, format=None): content = { 'status': 'request was permitted' } return Response(content)
Или, если вы используете декоратор @api_view
с представлениями, основанными на функциях.
from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @api_view(['GET']) @permission_classes([IsAuthenticated]) def example_view(request, format=None): content = { 'status': 'request was permitted' } return Response(content)
Примечание: когда вы устанавливаете новые классы разрешений с помощью атрибута class или декораторов, вы говорите представлению игнорировать список по умолчанию, установленный в файле settings.py.
Если они наследуются от rest_framework.permissions.BasePermission
, разрешения могут быть составлены с помощью стандартных побитовых операторов Python. Например, IsAuthenticatedOrReadOnly
можно записать:
from rest_framework.permissions import BasePermission, IsAuthenticated, SAFE_METHODS from rest_framework.response import Response from rest_framework.views import APIView class ReadOnly(BasePermission): def has_permission(self, request, view): return request.method in SAFE_METHODS class ExampleView(APIView): permission_classes = [IsAuthenticated|ReadOnly] def get(self, request, format=None): content = { 'status': 'request was permitted' } return Response(content)
Примечание: он поддерживает & (и), | (или) и ~ (не).
Справочник по API¶
AllowAny¶
Класс разрешения AllowAny
разрешает неограниченный доступ, независимо от того, был ли запрос аутентифицирован или неаутентифицирован.
Это разрешение не является строго обязательным, поскольку вы можете достичь того же результата, используя пустой список или кортеж для установки разрешений, но вы можете посчитать полезным указать этот класс, поскольку он делает намерение явным.
IsAuthenticated¶
Класс разрешения IsAuthenticated
будет запрещать разрешение любому неаутентифицированному пользователю, и разрешать в противном случае.
Это разрешение подходит, если вы хотите, чтобы ваш API был доступен только зарегистрированным пользователям.
IsAdminUser¶
Класс разрешения IsAdminUser
будет запрещать разрешение любому пользователю, если только user.is_staff
не является True
, в этом случае разрешение будет разрешено.
Это разрешение подходит, если вы хотите, чтобы ваш API был доступен только подгруппе доверенных администраторов.
IsAuthenticatedOrReadOnly¶
IsAuthenticatedOrReadOnly
позволит аутентифицированным пользователям выполнить любой запрос. Запросы неавторизованных пользователей будут разрешены, только если метод запроса является одним из «безопасных» методов; GET
, HEAD
или OPTIONS
.
Это разрешение подходит, если вы хотите, чтобы ваш API разрешал права на чтение анонимным пользователям и разрешал права на запись только аутентифицированным пользователям.
DjangoModelPermissions¶
Этот класс разрешений связан со стандартом Django django.contrib.auth
model permissions. Это разрешение должно применяться только к представлениям, имеющим .queryset
свойство или get_queryset()
метод. Разрешение будет предоставлено только в том случае, если пользователь аутентифицирован и имеет соответствующие разрешения модели.
-
Запросы
POST
требуют, чтобы пользователь имел разрешениеadd
на модель. -
Запросы
PUT
иPATCH
требуют, чтобы пользователь имел разрешениеchange
на модель. -
Запросы
DELETE
требуют, чтобы пользователь имел разрешениеdelete
на модель.
Поведение по умолчанию также можно переопределить для поддержки пользовательских разрешений модели. Например, вы можете включить разрешение модели view
для запросов GET
.
Чтобы использовать пользовательские разрешения модели, переопределите DjangoModelPermissions
и установите свойство .perms_map
. Подробности см. в исходном коде.
DjangoModelPermissionsOrAnonReadOnly¶
Аналогично DjangoModelPermissions
, но также позволяет неаутентифицированным пользователям иметь доступ к API только для чтения.
DjangoObjectPermissions¶
Этот класс разрешений связан со стандартом Django object permissions framework, который позволяет устанавливать разрешения на модели на уровне объекта. Чтобы использовать этот класс разрешений, вам также необходимо добавить бэкенд разрешений, который поддерживает разрешения на уровне объекта, такие как django-guardian.
Как и DjangoModelPermissions
, это разрешение должно применяться только к представлениям, имеющим .queryset
свойство или .get_queryset()
метод. Разрешение будет предоставлено только в том случае, если пользователь аутентифицирован и имеет соответствующие разрешения на объект и соответствующие разрешения на модель.
-
Запросы
POST
требуют, чтобы пользователь имел разрешениеadd
на экземпляр модели. -
Запросы
PUT
иPATCH
требуют, чтобы пользователь имел разрешениеchange
на экземпляр модели. -
Запросы
DELETE
требуют, чтобы пользователь имел разрешениеdelete
на экземпляр модели.
Обратите внимание, что DjangoObjectPermissions
**не требует пакета django-guardian
, и должен одинаково хорошо поддерживать другие бэкенды объектного уровня.
Как и в случае с DjangoModelPermissions
, вы можете использовать пользовательские разрешения модели, переопределив DjangoObjectPermissions
и установив свойство .perms_map
. Подробности см. в исходном коде.
Примечание : Если вам нужны разрешения на уровне объектов view
для GET
, HEAD
и OPTIONS
запросов и вы используете django-guardian для бэкенда разрешений на уровне объектов, вам стоит рассмотреть возможность использования класса DjangoObjectPermissionsFilter
, предоставляемого ** «djangorestframework-guardian:doc:` package <https://github.com/rpkilby/django-rest-framework-guardian>`. Он гарантирует, что конечные точки списка возвращают только результаты, включающие объекты, для которых пользователь имеет соответствующие разрешения на просмотр.
Пользовательские разрешения¶
Чтобы реализовать пользовательское разрешение, переопределите BasePermission
и реализуйте один или оба из следующих методов:
-
.has_permission(self, request, view)
-
.has_object_permission(self, request, view, obj)
Методы должны возвращать True
, если запрос должен получить доступ, и False
в противном случае.
Если вам нужно проверить, является ли запрос операцией чтения или записи, вы должны проверить метод запроса на соответствие константе SAFE_METHODS``** , которая является кортежем, содержащим ``'GET'
, 'OPTIONS'
и 'HEAD'
. Например:
if request.method in permissions.SAFE_METHODS: # Check permissions for read-only request else: # Check permissions for write request
Примечание : Метод has_object_permission
уровня экземпляра будет вызван только в том случае, если проверки has_permission
уровня представления уже прошли. Также обратите внимание, что для того, чтобы проверки на уровне экземпляра были выполнены, код представления должен явно вызвать .check_object_permissions(request, obj)
. Если вы используете общие представления, то это будет сделано за вас по умолчанию. (Представления, основанные на функциях, должны будут проверять разрешения объектов явно, вызывая PermissionDenied
в случае неудачи).
Пользовательские разрешения будут вызывать исключение PermissionDenied
, если тест не пройден. Чтобы изменить сообщение об ошибке, связанное с исключением, реализуйте атрибут message
непосредственно на вашем пользовательском разрешении. В противном случае будет использован атрибут default_detail
из PermissionDenied
. Аналогично, чтобы изменить идентификатор кода, связанный с исключением, реализуйте атрибут code
непосредственно на вашем пользовательском разрешении — иначе будет использоваться атрибут default_code
из PermissionDenied
.
from rest_framework import permissions class CustomerAccessPermission(permissions.BasePermission): message = 'Adding customers not allowed.' def has_permission(self, request, view): ...
Примеры¶
Ниже приведен пример класса разрешения, который проверяет IP-адрес входящего запроса по списку блокировки и отклоняет запрос, если IP-адрес был заблокирован.
from rest_framework import permissions class BlocklistPermission(permissions.BasePermission): """ Global permission check for blocked IPs. """ def has_permission(self, request, view): ip_addr = request.META['REMOTE_ADDR'] blocked = Blocklist.objects.filter(ip_addr=ip_addr).exists() return not blocked
Помимо глобальных разрешений, которые выполняются для всех входящих запросов, вы также можете создавать разрешения на уровне объекта, которые выполняются только для операций, затрагивающих конкретный экземпляр объекта. Например:
class IsOwnerOrReadOnly(permissions.BasePermission): """ Object-level permission to only allow owners of an object to edit it. Assumes the model instance has an `owner` attribute. """ def has_object_permission(self, request, view, obj): # Read permissions are allowed to any request, # so we'll always allow GET, HEAD or OPTIONS requests. if request.method in permissions.SAFE_METHODS: return True # Instance must have an attribute named `owner`. return obj.owner == request.user
Обратите внимание, что общие представления будут проверять соответствующие разрешения на уровне объекта, но если вы пишете свои собственные пользовательские представления, вам нужно будет убедиться, что вы сами проверяете разрешения на уровне объекта. Вы можете сделать это, вызвав self.check_object_permissions(request, obj)
из представления, когда у вас есть экземпляр объекта. Этот вызов вызовет соответствующее сообщение APIException
, если проверка разрешений на уровне объекта завершится неудачей, а в противном случае просто вернется.
Также обратите внимание, что общие представления будут проверять разрешения на уровне объекта только для представлений, которые получают один экземпляр модели. Если вам требуется фильтрация на уровне объектов для списковых представлений, вам придется фильтровать набор запросов отдельно. Более подробную информацию см. в filtering documentation.
Обзор методов ограничения доступа¶
Структура REST предлагает три различных метода настройки ограничений доступа в каждом конкретном случае. Они применяются в разных сценариях и имеют различные эффекты и ограничения.
-
queryset
/**get_queryset()
: Ограничивает общую видимость существующих объектов из базы данных. Кверисет ограничивает, какие объекты будут отображаться в списке и какие объекты могут быть изменены или удалены. Методget_queryset()
> может применять различные кверисеты в зависимости от текущего действия. -
permission_classes
/get_permissions(): Общая проверка прав доступа, основанная на текущем действии, запросе и целевом объекте. Разрешения на уровне объекта могут быть применены только к действиям получения, изменения и удаления. Проверки разрешений для list и create будут применены ко всему типу объекта. (В случае списка: с учетом ограничений в наборе запросов). -
serializer_class
/**get_serializer()
: Ограничения на уровне экземпляра, которые применяются ко всем объектам на входе и выходе. Сериализатор может иметь доступ к контексту запроса. Методget_serializer()
> может применять различные сериализаторы в зависимости от текущего действия.
В следующей таблице перечислены методы ограничения доступа и уровень контроля, который они обеспечивают, над какими действиями.
Пакеты сторонних производителей¶
Также доступны следующие пакеты сторонних производителей.
DRF — Политика доступа¶
Пакет Django REST — Access Policy предоставляет способ определения сложных правил доступа в декларативных классах политик, которые прикрепляются к наборам представлений или представлениям на основе функций. Политики определяются в JSON в формате, аналогичном политикам AWS Identity & Access Management.
Составленные разрешения¶
Пакет Composed Permissions предоставляет простой способ определения сложных и многоглубинных (с логическими операторами) объектов разрешения, используя небольшие и многократно используемые компоненты.
Пакет REST Condition — это еще одно расширение для построения сложных разрешений простым и удобным способом. Расширение позволяет комбинировать разрешения с логическими операторами.
DRY Rest Permissions¶
Пакет DRY Rest Permissions предоставляет возможность определять различные разрешения для отдельных действий по умолчанию и пользовательских действий. Этот пакет предназначен для приложений с разрешениями, которые являются производными от отношений, определенных в модели данных приложения. Он также поддерживает проверку разрешений, возвращаемую клиентскому приложению через сериализатор API. Кроме того, он поддерживает добавление разрешений к действиям списка по умолчанию и пользовательским действиям списка для ограничения данных, которые они извлекают для каждого пользователя.
Роли Django Rest Framework¶
Пакет Django Rest Framework Roles облегчает параметризацию API для нескольких типов пользователей.
Django REST Framework API Key¶
Пакет Django REST Framework API Key предоставляет классы разрешений, модели и помощники для добавления авторизации по ключу API в ваш API. Он может быть использован для авторизации внутренних или сторонних бэкендов и сервисов (т.е. машин* ), которые не имеют учетной записи пользователя. API ключи хранятся в безопасном месте с использованием инфраструктуры хэширования паролей Django, и их можно просматривать, редактировать и отзывать в любое время в админке Django.
Ролевые фильтры Django Rest Framework¶
Пакет Django Rest Framework Role Filters обеспечивает простую фильтрацию по нескольким типам ролей.
Django Rest Framework PSQ¶
Пакет Django Rest Framework PSQ — это расширение, которое обеспечивает поддержку того, чтобы основанные на действиях классы_разрешений , сериализатор_классов , и queryset зависели от правил, основанных на разрешениях.
Вернуться на верх
source |
---|
permissions.py |
Authentication or identification by itself is not usually sufficient to gain access to information or code. For that, the entity requesting access must have authorization.
— Apple Developer Documentation
Together with authentication and throttling, permissions determine whether a request should be granted or denied access.
Permission checks are always run at the very start of the view, before any other code is allowed to proceed. Permission checks will typically use the authentication information in the request.user
and request.auth
properties to determine if the incoming request should be permitted.
Permissions are used to grant or deny access for different classes of users to different parts of the API.
The simplest style of permission would be to allow access to any authenticated user, and deny access to any unauthenticated user. This corresponds to the IsAuthenticated
class in REST framework.
A slightly less strict style of permission would be to allow full access to authenticated users, but allow read-only access to unauthenticated users. This corresponds to the IsAuthenticatedOrReadOnly
class in REST framework.
How permissions are determined
Permissions in REST framework are always defined as a list of permission classes.
Before running the main body of the view each permission in the list is checked.
If any permission check fails, an exceptions.PermissionDenied
or exceptions.NotAuthenticated
exception will be raised, and the main body of the view will not run.
When the permission checks fail, either a «403 Forbidden» or a «401 Unauthorized» response will be returned, according to the following rules:
- The request was successfully authenticated, but permission was denied. — An HTTP 403 Forbidden response will be returned.
- The request was not successfully authenticated, and the highest priority authentication class does not use
WWW-Authenticate
headers. — An HTTP 403 Forbidden response will be returned. - The request was not successfully authenticated, and the highest priority authentication class does use
WWW-Authenticate
headers. — An HTTP 401 Unauthorized response, with an appropriateWWW-Authenticate
header will be returned.
Object level permissions
REST framework permissions also support object-level permissioning. Object level permissions are used to determine if a user should be allowed to act on a particular object, which will typically be a model instance.
Object level permissions are run by REST framework’s generic views when .get_object()
is called.
As with view level permissions, an exceptions.PermissionDenied
exception will be raised if the user is not allowed to act on the given object.
If you’re writing your own views and want to enforce object level permissions,
or if you override the get_object
method on a generic view, then you’ll need to explicitly call the .check_object_permissions(request, obj)
method on the view at the point at which you’ve retrieved the object.
This will either raise a PermissionDenied
or NotAuthenticated
exception, or simply return if the view has the appropriate permissions.
For example:
def get_object(self):
obj = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"])
self.check_object_permissions(self.request, obj)
return obj
Note: With the exception of DjangoObjectPermissions
, the provided
permission classes in rest_framework.permissions
do not implement the
methods necessary to check object permissions.
If you wish to use the provided permission classes in order to check object
permissions, you must subclass them and implement the
has_object_permission()
method described in the Custom
permissions section (below).
Limitations of object level permissions
For performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects.
Often when you’re using object level permissions you’ll also want to filter the queryset appropriately, to ensure that users only have visibility onto instances that they are permitted to view.
Because the get_object()
method is not called, object level permissions from the has_object_permission()
method are not applied when creating objects. In order to restrict object creation you need to implement the permission check either in your Serializer class or override the perform_create()
method of your ViewSet class.
Setting the permission policy
The default permission policy may be set globally, using the DEFAULT_PERMISSION_CLASSES
setting. For example.
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
If not specified, this setting defaults to allowing unrestricted access:
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
]
You can also set the authentication policy on a per-view, or per-viewset basis,
using the APIView
class-based views.
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
Or, if you’re using the @api_view
decorator with function based views.
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def example_view(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
Note: when you set new permission classes via the class attribute or decorators you’re telling the view to ignore the default list set in the settings.py file.
Provided they inherit from rest_framework.permissions.BasePermission
, permissions can be composed using standard Python bitwise operators. For example, IsAuthenticatedOrReadOnly
could be written:
from rest_framework.permissions import BasePermission, IsAuthenticated, SAFE_METHODS
from rest_framework.response import Response
from rest_framework.views import APIView
class ReadOnly(BasePermission):
def has_permission(self, request, view):
return request.method in SAFE_METHODS
class ExampleView(APIView):
permission_classes = [IsAuthenticated|ReadOnly]
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
Note: it supports & (and), | (or) and ~ (not).
API Reference
AllowAny
The AllowAny
permission class will allow unrestricted access, regardless of if the request was authenticated or unauthenticated.
This permission is not strictly required, since you can achieve the same result by using an empty list or tuple for the permissions setting, but you may find it useful to specify this class because it makes the intention explicit.
IsAuthenticated
The IsAuthenticated
permission class will deny permission to any unauthenticated user, and allow permission otherwise.
This permission is suitable if you want your API to only be accessible to registered users.
IsAdminUser
The IsAdminUser
permission class will deny permission to any user, unless user.is_staff
is True
in which case permission will be allowed.
This permission is suitable if you want your API to only be accessible to a subset of trusted administrators.
IsAuthenticatedOrReadOnly
The IsAuthenticatedOrReadOnly
will allow authenticated users to perform any request. Requests for unauthorised users will only be permitted if the request method is one of the «safe» methods; GET
, HEAD
or OPTIONS
.
This permission is suitable if you want to your API to allow read permissions to anonymous users, and only allow write permissions to authenticated users.
DjangoModelPermissions
This permission class ties into Django’s standard django.contrib.auth
model permissions. This permission must only be applied to views that have a .queryset
property or get_queryset()
method. Authorization will only be granted if the user is authenticated and has the relevant model permissions assigned. The appropriate model is determined by checking get_queryset().model
or queryset.model
.
GET
requests require the user to have theview
orchange
permission on the modelPOST
requests require the user to have theadd
permission on the model.PUT
andPATCH
requests require the user to have thechange
permission on the model.DELETE
requests require the user to have thedelete
permission on the model.
The default behaviour can also be overridden to support custom model permissions.
To use custom model permissions, override DjangoModelPermissions
and set the .perms_map
property. Refer to the source code for details.
DjangoModelPermissionsOrAnonReadOnly
Similar to DjangoModelPermissions
, but also allows unauthenticated users to have read-only access to the API.
## DjangoObjectPermissions
This permission class ties into Django’s standard object permissions framework that allows per-object permissions on models. In order to use this permission class, you’ll also need to add a permission backend that supports object-level permissions, such as django-guardian.
As with DjangoModelPermissions
, this permission must only be applied to views that have a .queryset
property or .get_queryset()
method. Authorization will only be granted if the user is authenticated and has the relevant per-object permissions and relevant model permissions assigned.
POST
requests require the user to have theadd
permission on the model instance.PUT
andPATCH
requests require the user to have thechange
permission on the model instance.DELETE
requests require the user to have thedelete
permission on the model instance.
Note that DjangoObjectPermissions
does not require the django-guardian
package, and should support other object-level backends equally well.
As with DjangoModelPermissions
you can use custom model permissions by overriding DjangoObjectPermissions
and setting the .perms_map
property. Refer to the source code for details.
Note: If you need object level view
permissions for GET
, HEAD
and OPTIONS
requests and are using django-guardian for your object-level permissions backend, you’ll want to consider using the DjangoObjectPermissionsFilter
class provided by the djangorestframework-guardian2
package. It ensures that list endpoints only return results including objects for which the user has appropriate view permissions.
Custom permissions
To implement a custom permission, override BasePermission
and implement either, or both, of the following methods:
.has_permission(self, request, view)
.has_object_permission(self, request, view, obj)
The methods should return True
if the request should be granted access, and False
otherwise.
If you need to test if a request is a read operation or a write operation, you should check the request method against the constant SAFE_METHODS
, which is a tuple containing 'GET'
, 'OPTIONS'
and 'HEAD'
. For example:
if request.method in permissions.SAFE_METHODS:
# Check permissions for read-only request
else:
# Check permissions for write request
Note: The instance-level has_object_permission
method will only be called if the view-level has_permission
checks have already passed. Also note that in order for the instance-level checks to run, the view code should explicitly call .check_object_permissions(request, obj)
. If you are using the generic views then this will be handled for you by default. (Function-based views will need to check object permissions explicitly, raising PermissionDenied
on failure.)
Custom permissions will raise a PermissionDenied
exception if the test fails. To change the error message associated with the exception, implement a message
attribute directly on your custom permission. Otherwise the default_detail
attribute from PermissionDenied
will be used. Similarly, to change the code identifier associated with the exception, implement a code
attribute directly on your custom permission — otherwise the default_code
attribute from PermissionDenied
will be used.
from rest_framework import permissions
class CustomerAccessPermission(permissions.BasePermission):
message = 'Adding customers not allowed.'
def has_permission(self, request, view):
...
Examples
The following is an example of a permission class that checks the incoming request’s IP address against a blocklist, and denies the request if the IP has been blocked.
from rest_framework import permissions
class BlocklistPermission(permissions.BasePermission):
"""
Global permission check for blocked IPs.
"""
def has_permission(self, request, view):
ip_addr = request.META['REMOTE_ADDR']
blocked = Blocklist.objects.filter(ip_addr=ip_addr).exists()
return not blocked
As well as global permissions, that are run against all incoming requests, you can also create object-level permissions, that are only run against operations that affect a particular object instance. For example:
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Object-level permission to only allow owners of an object to edit it.
Assumes the model instance has an `owner` attribute.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Instance must have an attribute named `owner`.
return obj.owner == request.user
Note that the generic views will check the appropriate object level permissions, but if you’re writing your own custom views, you’ll need to make sure you check the object level permission checks yourself. You can do so by calling self.check_object_permissions(request, obj)
from the view once you have the object instance. This call will raise an appropriate APIException
if any object-level permission checks fail, and will otherwise simply return.
Also note that the generic views will only check the object-level permissions for views that retrieve a single model instance. If you require object-level filtering of list views, you’ll need to filter the queryset separately. See the filtering documentation for more details.
Overview of access restriction methods
REST framework offers three different methods to customize access restrictions on a case-by-case basis. These apply in different scenarios and have different effects and limitations.
queryset
/get_queryset()
: Limits the general visibility of existing objects from the database. The queryset limits which objects will be listed and which objects can be modified or deleted. Theget_queryset()
method can apply different querysets based on the current action.permission_classes
/get_permissions()
: General permission checks based on the current action, request and targeted object. Object level permissions can only be applied to retrieve, modify and deletion actions. Permission checks for list and create will be applied to the entire object type. (In case of list: subject to restrictions in the queryset.)serializer_class
/get_serializer()
: Instance level restrictions that apply to all objects on input and output. The serializer may have access to the request context. Theget_serializer()
method can apply different serializers based on the current action.
The following table lists the access restriction methods and the level of control they offer over which actions.
queryset |
permission_classes |
serializer_class |
|
---|---|---|---|
Action: list | global | global | object-level* |
Action: create | no | global | object-level |
Action: retrieve | global | object-level | object-level |
Action: update | global | object-level | object-level |
Action: partial_update | global | object-level | object-level |
Action: destroy | global | object-level | no |
Can reference action in decision | no** | yes | no** |
Can reference request in decision | no** | yes | yes |
* A Serializer class should not raise PermissionDenied in a list action, or the entire list would not be returned.
** The get_*()
methods have access to the current view and can return different Serializer or QuerySet instances based on the request or action.
Third party packages
The following third party packages are also available.
DRF — Access Policy
The Django REST — Access Policy package provides a way to define complex access rules in declarative policy classes that are attached to view sets or function-based views. The policies are defined in JSON in a format similar to AWS’ Identity & Access Management policies.
Composed Permissions
The Composed Permissions package provides a simple way to define complex and multi-depth (with logic operators) permission objects, using small and reusable components.
REST Condition
The REST Condition package is another extension for building complex permissions in a simple and convenient way. The extension allows you to combine permissions with logical operators.
DRY Rest Permissions
The DRY Rest Permissions package provides the ability to define different permissions for individual default and custom actions. This package is made for apps with permissions that are derived from relationships defined in the app’s data model. It also supports permission checks being returned to a client app through the API’s serializer. Additionally it supports adding permissions to the default and custom list actions to restrict the data they retrieve per user.
Django Rest Framework Roles
The Django Rest Framework Roles package makes it easier to parameterize your API over multiple types of users.
Rest Framework Roles
The Rest Framework Roles makes it super easy to protect views based on roles. Most importantly allows you to decouple accessibility logic from models and views in a clean human-readable way.
Django REST Framework API Key
The Django REST Framework API Key package provides permissions classes, models and helpers to add API key authorization to your API. It can be used to authorize internal or third-party backends and services (i.e. machines) which do not have a user account. API keys are stored securely using Django’s password hashing infrastructure, and they can be viewed, edited and revoked at anytime in the Django admin.
Django Rest Framework Role Filters
The Django Rest Framework Role Filters package provides simple filtering over multiple types of roles.
Django Rest Framework PSQ
The Django Rest Framework PSQ package is an extension that gives support for having action-based permission_classes, serializer_class, and queryset dependent on permission-based rules.