django-rest-framework/api-guide/permissions.html

425 lines
30 KiB
HTML
Raw Normal View History

2013-11-17 22:26:41 +04:00
<!DOCTYPE html>
<html lang="en">
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
2013-12-23 16:37:56 +04:00
<title>Permissions - Django REST framework</title>
2013-11-17 22:26:41 +04:00
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
2013-11-18 19:50:29 +04:00
<link rel="canonical" href="http://django-rest-framework.org/api-guide/permissions"/>
2013-11-17 22:26:41 +04:00
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Django, API, REST, Permissions, API Reference, Custom permissions, Third party packages">
<meta name="author" content="Tom Christie">
<!-- Le styles -->
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-18852272-2']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body onload="prettyPrint()" class="permissions-page">
<div class="wrapper">
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container-fluid">
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
2013-11-18 19:50:29 +04:00
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/throttling">Next <i class="icon-arrow-right icon-white"></i></a>
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/authentication"><i class="icon-arrow-left icon-white"></i> Previous</a>
2013-11-17 22:26:41 +04:00
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
<div class="nav-collapse collapse">
<ul class="nav">
<li><a href="http://django-rest-framework.org">Home</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
<ul class="dropdown-menu">
2013-11-18 19:50:29 +04:00
<li><a href="http://django-rest-framework.org/tutorial/quickstart">Quickstart</a></li>
<li><a href="http://django-rest-framework.org/tutorial/1-serialization">1 - Serialization</a></li>
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses">2 - Requests and responses</a></li>
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views">3 - Class based views</a></li>
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions">4 - Authentication and permissions</a></li>
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis">5 - Relationships and hyperlinked APIs</a></li>
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers">6 - Viewsets and routers</a></li>
2013-11-17 22:26:41 +04:00
</ul>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
<ul class="dropdown-menu">
2013-11-18 19:50:29 +04:00
<li><a href="http://django-rest-framework.org/api-guide/requests">Requests</a></li>
<li><a href="http://django-rest-framework.org/api-guide/responses">Responses</a></li>
<li><a href="http://django-rest-framework.org/api-guide/views">Views</a></li>
<li><a href="http://django-rest-framework.org/api-guide/generic-views">Generic views</a></li>
<li><a href="http://django-rest-framework.org/api-guide/viewsets">Viewsets</a></li>
<li><a href="http://django-rest-framework.org/api-guide/routers">Routers</a></li>
<li><a href="http://django-rest-framework.org/api-guide/parsers">Parsers</a></li>
<li><a href="http://django-rest-framework.org/api-guide/renderers">Renderers</a></li>
<li><a href="http://django-rest-framework.org/api-guide/serializers">Serializers</a></li>
<li><a href="http://django-rest-framework.org/api-guide/fields">Serializer fields</a></li>
<li><a href="http://django-rest-framework.org/api-guide/relations">Serializer relations</a></li>
<li><a href="http://django-rest-framework.org/api-guide/authentication">Authentication</a></li>
<li><a href="http://django-rest-framework.org/api-guide/permissions">Permissions</a></li>
<li><a href="http://django-rest-framework.org/api-guide/throttling">Throttling</a></li>
<li><a href="http://django-rest-framework.org/api-guide/filtering">Filtering</a></li>
<li><a href="http://django-rest-framework.org/api-guide/pagination">Pagination</a></li>
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation">Content negotiation</a></li>
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes">Format suffixes</a></li>
<li><a href="http://django-rest-framework.org/api-guide/reverse">Returning URLs</a></li>
<li><a href="http://django-rest-framework.org/api-guide/exceptions">Exceptions</a></li>
<li><a href="http://django-rest-framework.org/api-guide/status-codes">Status codes</a></li>
<li><a href="http://django-rest-framework.org/api-guide/testing">Testing</a></li>
<li><a href="http://django-rest-framework.org/api-guide/settings">Settings</a></li>
2013-11-17 22:26:41 +04:00
</ul>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
<ul class="dropdown-menu">
2013-11-18 19:50:29 +04:00
<li><a href="http://django-rest-framework.org/topics/documenting-your-api">Documenting your API</a></li>
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors">AJAX, CSRF & CORS</a></li>
<li><a href="http://django-rest-framework.org/topics/browser-enhancements">Browser enhancements</a></li>
<li><a href="http://django-rest-framework.org/topics/browsable-api">The Browsable API</a></li>
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas">REST, Hypermedia & HATEOAS</a></li>
2013-12-04 19:00:19 +04:00
<li><a href="http://django-rest-framework.org/topics/contributing">Contributing to REST framework</a></li>
2013-11-18 19:50:29 +04:00
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement">2.0 Announcement</a></li>
<li><a href="http://django-rest-framework.org/topics/2.2-announcement">2.2 Announcement</a></li>
<li><a href="http://django-rest-framework.org/topics/2.3-announcement">2.3 Announcement</a></li>
<li><a href="http://django-rest-framework.org/topics/release-notes">Release Notes</a></li>
<li><a href="http://django-rest-framework.org/topics/credits">Credits</a></li>
2013-11-17 22:26:41 +04:00
</ul>
</li>
</ul>
<ul class="nav pull-right">
<!-- TODO
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Version: 2.0.0 <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="#">Trunk</a></li>
<li><a href="#">2.0.0</a></li>
</ul>
</li>
-->
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
</div>
<div class="body-content">
<div class="container-fluid">
<!-- Search Modal -->
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 id="myModalLabel">Documentation search</h3>
</div>
<div class="modal-body">
<!-- Custom google search -->
<script>
(function() {
var cx = '015016005043623903336:rxraeohqk6w';
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
'//www.google.com/cse/cse.js?cx=' + cx;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);
})();
</script>
<gcse:search></gcse:search>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
</div>
</div>
<div class="row-fluid">
<div class="span3">
<!-- TODO
<p style="margin-top: -12px">
<a class="btn btn-mini btn-primary" style="width: 60px">&laquo; previous</a>
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next &raquo;</a>
</p>
-->
<div id="table-of-contents">
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
<li class="main"><a href="#permissions">Permissions</a></li>
<li><a href="#how-permissions-are-determined">How permissions are determined</a></li>
<li><a href="#object-level-permissions">Object level permissions</a></li>
<li><a href="#setting-the-permission-policy">Setting the permission policy</a></li>
<li class="main"><a href="#api-reference">API Reference</a></li>
<li><a href="#allowany">AllowAny</a></li>
<li><a href="#isauthenticated">IsAuthenticated</a></li>
<li><a href="#isadminuser">IsAdminUser</a></li>
<li><a href="#isauthenticatedorreadonly">IsAuthenticatedOrReadOnly</a></li>
<li><a href="#djangomodelpermissions">DjangoModelPermissions</a></li>
<li><a href="#djangomodelpermissionsoranonreadonly">DjangoModelPermissionsOrAnonReadOnly</a></li>
<li><a href="#tokenhasreadwritescope">TokenHasReadWriteScope</a></li>
<li class="main"><a href="#custom-permissions">Custom permissions</a></li>
<li><a href="#examples">Examples</a></li>
<li class="main"><a href="#third-party-packages">Third party packages</a></li>
<li><a href="#drf-any-permissions">DRF Any Permissions</a></li>
<li><a href="#composed-permissions">Composed Permissions</a></li>
<li><a href="#rest-condition">REST Condition</a></li>
2013-11-17 22:26:41 +04:00
<div>
<hr>
2013-12-09 12:47:06 +04:00
<p><strong>The team behind REST framework is launching a new API service.</strong></p>
2013-11-17 22:26:41 +04:00
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
<!-- Begin MailChimp Signup Form -->
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
<style type="text/css">
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
</style>
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&amp;id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
<!-- <label for="mce-EMAIL">Keep me posted!</label>
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
</form>
</div>
</style></div>
</ul>
<!--End mc_embed_signup-->
</div>
</div>
<div id="main-content" class="span9">
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/permissions.py"><span class="label label-info">permissions.py</span></a></p>
<h1 id="permissions">Permissions</h1>
<blockquote>
<p>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.</p>
<p>&mdash; <a href="https://developer.apple.com/library/mac/#documentation/security/Conceptual/AuthenticationAndAuthorizationGuide/Authorization/Authorization.html">Apple Developer Documentation</a></p>
</blockquote>
2013-11-18 19:50:29 +04:00
<p>Together with <a href="authentication">authentication</a> and <a href="throttling">throttling</a>, permissions determine whether a request should be granted or denied access.</p>
2013-11-17 22:26:41 +04:00
<p>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 <code>request.user</code> and <code>request.auth</code> properties to determine if the incoming request should be permitted.</p>
<h2 id="how-permissions-are-determined">How permissions are determined</h2>
<p>Permissions in REST framework are always defined as a list of permission classes. </p>
<p>Before running the main body of the view each permission in the list is checked.
If any permission check fails an <code>exceptions.PermissionDenied</code> exception will be raised, and the main body of the view will not run.</p>
<h2 id="object-level-permissions">Object level permissions</h2>
<p>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.</p>
<p>Object level permissions are run by REST framework's generic views when <code>.get_object()</code> is called.
As with view level permissions, an <code>exceptions.PermissionDenied</code> exception will be raised if the user is not allowed to act on the given object.</p>
<p>If you're writing your own views and want to enforce object level permissions,
or if you override the <code>get_object</code> method on a generic view, then you'll need to explicitly call the <code>.check_object_permissions(request, obj)</code> method on the view at the point at which you've retrieved the object.</p>
<p>This will either raise a <code>PermissionDenied</code> or <code>NotAuthenticated</code> exception, or simply return if the view has the appropriate permissions.</p>
<p>For example:</p>
<pre class="prettyprint lang-py"><code>def get_object(self):
obj = get_object_or_404(self.get_queryset())
self.check_object_permissions(self.request, obj)
return obj
</code></pre>
<h2 id="setting-the-permission-policy">Setting the permission policy</h2>
<p>The default permission policy may be set globally, using the <code>DEFAULT_PERMISSION_CLASSES</code> setting. For example.</p>
<pre class="prettyprint lang-py"><code>REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}
</code></pre>
<p>If not specified, this setting defaults to allowing unrestricted access:</p>
<pre class="prettyprint lang-py"><code>'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
)
</code></pre>
<p>You can also set the authentication policy on a per-view, or per-viewset basis,
using the <code>APIView</code> class based views.</p>
<pre class="prettyprint lang-py"><code>from rest_framework.permissions import IsAuthenticated
from rest_framework.responses 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)
</code></pre>
<p>Or, if you're using the <code>@api_view</code> decorator with function based views.</p>
<pre class="prettyprint lang-py"><code>@api_view('GET')
@permission_classes((IsAuthenticated, ))
def example_view(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
</code></pre>
<hr />
<h1 id="api-reference">API Reference</h1>
<h2 id="allowany">AllowAny</h2>
<p>The <code>AllowAny</code> permission class will allow unrestricted access, <strong>regardless of if the request was authenticated or unauthenticated</strong>.</p>
<p>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.</p>
<h2 id="isauthenticated">IsAuthenticated</h2>
<p>The <code>IsAuthenticated</code> permission class will deny permission to any unauthenticated user, and allow permission otherwise.</p>
<p>This permission is suitable if you want your API to only be accessible to registered users.</p>
<h2 id="isadminuser">IsAdminUser</h2>
<p>The <code>IsAdminUser</code> permission class will deny permission to any user, unless <code>user.is_staff</code> is <code>True</code> in which case permission will be allowed.</p>
<p>This permission is suitable is you want your API to only be accessible to a subset of trusted administrators.</p>
<h2 id="isauthenticatedorreadonly">IsAuthenticatedOrReadOnly</h2>
<p>The <code>IsAuthenticatedOrReadOnly</code> 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; <code>GET</code>, <code>HEAD</code> or <code>OPTIONS</code>.</p>
<p>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.</p>
<h2 id="djangomodelpermissions">DjangoModelPermissions</h2>
<p>This permission class ties into Django's standard <code>django.contrib.auth</code> <a href="https://docs.djangoproject.com/en/1.0/topics/auth/#permissions">model permissions</a>. When applied to a view that has a <code>.model</code> property, authorization will only be granted if the user <em>is authenticated</em> and has the <em>relevant model permissions</em> assigned.</p>
<ul>
<li><code>POST</code> requests require the user to have the <code>add</code> permission on the model.</li>
<li><code>PUT</code> and <code>PATCH</code> requests require the user to have the <code>change</code> permission on the model.</li>
<li><code>DELETE</code> requests require the user to have the <code>delete</code> permission on the model.</li>
</ul>
<p>The default behaviour can also be overridden to support custom model permissions. For example, you might want to include a <code>view</code> model permission for <code>GET</code> requests.</p>
<p>To use custom model permissions, override <code>DjangoModelPermissions</code> and set the <code>.perms_map</code> property. Refer to the source code for details.</p>
<h2 id="djangomodelpermissionsoranonreadonly">DjangoModelPermissionsOrAnonReadOnly</h2>
<p>Similar to <code>DjangoModelPermissions</code>, but also allows unauthenticated users to have read-only access to the API.</p>
<h2 id="djangoobjectpermissions">DjangoObjectPermissions</h2>
<p>This permission class ties into Django's standard <a href="https://docs.djangoproject.com/en/dev/topics/auth/customizing/#handling-object-permissions">object permissions framework</a> 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 <a href="https://github.com/lukaszb/django-guardian">django-guardian</a>.</p>
<p>When applied to a view that has a <code>.model</code> property, authorization will only be granted if the user <em>is authenticated</em> and has the <em>relevant per-object permissions</em> and <em>relevant model permissions</em> assigned.</p>
<ul>
<li><code>POST</code> requests require the user to have the <code>add</code> permission on the model instance.</li>
<li><code>PUT</code> and <code>PATCH</code> requests require the user to have the <code>change</code> permission on the model instance.</li>
<li><code>DELETE</code> requests require the user to have the <code>delete</code> permission on the model instance.</li>
</ul>
<p>Note that <code>DjangoObjectPermissions</code> <strong>does not</strong> require the <code>django-guardian</code> package, and should support other object-level backends equally well.</p>
<p>As with <code>DjangoModelPermissions</code> you can use custom model permissions by overriding <code>DjangoModelPermissions</code> and setting the <code>.perms_map</code> property. Refer to the source code for details. Note that if you add a custom <code>view</code> permission for <code>GET</code>, <code>HEAD</code> and <code>OPTIONS</code> requests, you'll probably also want to consider adding the <code>DjangoObjectPermissionsFilter</code> class to ensure that list endpoints only return results including objects for which the user has appropriate view permissions.</p>
<h2 id="tokenhasreadwritescope">TokenHasReadWriteScope</h2>
<p>This permission class is intended for use with either of the <code>OAuthAuthentication</code> and <code>OAuth2Authentication</code> classes, and ties into the scoping that their backends provide.</p>
<p>Requests with a safe methods of <code>GET</code>, <code>OPTIONS</code> or <code>HEAD</code> will be allowed if the authenticated token has read permission.</p>
<p>Requests for <code>POST</code>, <code>PUT</code>, <code>PATCH</code> and <code>DELETE</code> will be allowed if the authenticated token has write permission.</p>
<p>This permission class relies on the implementations of the <a href="http://code.larlet.fr/django-oauth-plus">django-oauth-plus</a> and <a href="https://github.com/caffeinehit/django-oauth2-provider">django-oauth2-provider</a> libraries, which both provide limited support for controlling the scope of access tokens:</p>
<ul>
<li><code>django-oauth-plus</code>: Tokens are associated with a <code>Resource</code> class which has a <code>name</code>, <code>url</code> and <code>is_readonly</code> properties.</li>
<li><code>django-oauth2-provider</code>: Tokens are associated with a bitwise <code>scope</code> attribute, that defaults to providing bitwise values for <code>read</code> and/or <code>write</code>.</li>
</ul>
<p>If you require more advanced scoping for your API, such as restricting tokens to accessing a subset of functionality of your API then you will need to provide a custom permission class. See the source of the <code>django-oauth-plus</code> or <code>django-oauth2-provider</code> package for more details on scoping token access.</p>
<hr />
<h1 id="custom-permissions">Custom permissions</h1>
<p>To implement a custom permission, override <code>BasePermission</code> and implement either, or both, of the following methods:</p>
<ul>
<li><code>.has_permission(self, request, view)</code></li>
<li><code>.has_object_permission(self, request, view, obj)</code></li>
</ul>
<p>The methods should return <code>True</code> if the request should be granted access, and <code>False</code> otherwise.</p>
<p>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 <code>SAFE_METHODS</code>, which is a tuple containing <code>'GET'</code>, <code>'OPTIONS'</code> and <code>'HEAD'</code>. For example:</p>
<pre class="prettyprint lang-py"><code>if request.method in permissions.SAFE_METHODS:
# Check permissions for read-only request
else:
# Check permissions for write request
</code></pre>
<hr />
<p><strong>Note</strong>: In versions 2.0 and 2.1, the signature for the permission checks always included an optional <code>obj</code> parameter, like so: <code>.has_permission(self, request, view, obj=None)</code>. The method would be called twice, first for the global permission checks, with no object supplied, and second for the object-level check when required.</p>
<p>As of version 2.2 this signature has now been replaced with two separate method calls, which is more explicit and obvious. The old style signature continues to work, but its use will result in a <code>PendingDeprecationWarning</code>, which is silent by default. In 2.3 this will be escalated to a <code>DeprecationWarning</code>, and in 2.4 the old-style signature will be removed.</p>
2013-11-18 19:50:29 +04:00
<p>For more details see the <a href="../topics/2.2-announcement">2.2 release announcement</a>.</p>
2013-11-17 22:26:41 +04:00
<hr />
<h2 id="examples">Examples</h2>
<p>The following is an example of a permission class that checks the incoming request's IP address against a blacklist, and denies the request if the IP has been blacklisted.</p>
<pre class="prettyprint lang-py"><code>from rest_framework import permissions
class BlacklistPermission(permissions.BasePermission):
"""
Global permission check for blacklisted IPs.
"""
def has_permission(self, request, view):
ip_addr = request.META['REMOTE_ADDR']
blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists()
return not blacklisted
</code></pre>
<p>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:</p>
<pre class="prettyprint lang-py"><code>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
</code></pre>
<p>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 <code>self.check_object_permissions(request, obj)</code> from the view once you have the object instance. This call will raise an appropriate <code>APIException</code> if any object-level permission checks fail, and will otherwise simply return.</p>
2013-11-18 19:50:29 +04:00
<p>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 <a href="filtering">filtering documentation</a> for more details.</p>
2013-11-17 22:26:41 +04:00
<hr />
<h1 id="third-party-packages">Third party packages</h1>
<p>The following third party packages are also available.</p>
<h2 id="drf-any-permissions">DRF Any Permissions</h2>
<p>The <a href="https://github.com/kevin-brown/drf-any-permissions">DRF Any Permissions</a> packages provides a different permission behavior in contrast to REST framework. Instead of all specified permissions being required, only one of the given permissions has to be true in order to get access to the view.</p>
<h2 id="composed-permissions">Composed Permissions</h2>
<p>The <a href="https://github.com/niwibe/djangorestframework-composed-permissions">Composed Permissions</a> package provides a simple way to define complex and multi-depth (with logic operators) permission objects, using small and reusable components.</p>
<h2 id="rest-condition">REST Condition</h2>
<p>The <a href="https://github.com/caxap/rest_condition">REST Condition</a> package is another extension for building complex permissions in a simple and convenient way. The extension allows you to combine permissions with logical operators.</p>
2013-11-17 22:26:41 +04:00
</div><!--/span-->
</div><!--/row-->
</div><!--/.fluid-container-->
</div><!--/.body content-->
<div id="push"></div>
</div><!--/.wrapper -->
<footer class="span12">
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
</footer>
<!-- Le javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
<script>
//$('.side-nav').scrollspy()
var shiftWindow = function() { scrollBy(0, -50) };
if (location.hash) shiftWindow();
window.addEventListener("hashchange", shiftWindow);
$('.dropdown-menu').on('click touchstart', function(event) {
event.stopPropagation();
});
// Dynamically force sidenav to no higher than browser window
$('.side-nav').css('max-height', window.innerHeight - 130);
$(function(){
$(window).resize(function(){
$('.side-nav').css('max-height', window.innerHeight - 130);
});
});
</script>
</body></html>