1. Overview of the Django permissions mechanism
The permission mechanism can restrain the user behavior, control the display content of the page, make the API more secure and flexible, and use the privilege mechanism to make the system more powerful and robust. Therefore, it is very necessary to clarify the Django permission mechanism based on Django development.
1.1 Django's permissions control
Django completes the privilege mechanism with user, group, and permission, which assigns a permission that belongs to the model to the user or group, which can be understood as a global permission. That is, if user A has writable permissions to the data Model B, a can modify all instances of Model B (objects). The same is true for group permissions, and all instances of Model B can be modified by all users who belong to group C if you give the writable permission to model B for Group C.
This kind of permission mechanism can only solve some simple application requirements, and most of the scenarios require a more granular permission mechanism. For example, blog system users can be divided into "administrator", "editor", "author" and "Reader" four user groups; Blog system administrators and editors have permission to view, modify, and delete all articles, and authors can only modify and delete their own written articles, while the reader only has access to read. Administrator, editor and Reader permissions, we can use global permissions to control, and for the author, the global permissions can not meet the requirements, only through the global permissions, or allow the author to edit the article does not belong to the author, or even his own article can not be modified.
In the above scenario, the Django-brought permission mechanism does not meet the requirements and needs to introduce another finer-grained permission mechanism: Object permission.
Object permission is a permission mechanism on the granularity of objects that allows authorization for each specific object. Still follow the first example, if model B has three instances b1,b2 and B3, if we give B1 the writable permission to user A, then a can modify the B1 object, and the B2,B3 cannot be modified. For group, as well, if B2 's writable permission is given to group C, all users who belong to group C can modify B2, but cannot modify B1 and B3. Combining with Django's own permission mechanism and object permission, the author's permission control in the blog system is solved: the author is not allowed to edit the article globally, but for the specific articles belonging to the author, give the editor permission.
Django actually contains the framework of object permission, but without a specific implementation, the implementation of object permission requires the use of third-party app Django-guardian, which we call Django in development Guradian package is a good method.
1.2 Django's Permission entries
Django stores permission entries with permission objects, each of which has three permission, the Add model, the change model, and the delete model by default. For example, when you define a car named "Car", the corresponding three Permission:add_car, Change_car, and Delete_car are created automatically. Django also allows custom permission, for example, we can create new permission entries for car: Drive_car, Clean_car, Fix_car, and so on.
It is important to note that permission always corresponds to model, and if an object is not an instance of model, we cannot create/assign permissions for it.
2 Application of the Django self-2.1 mechanism Permission
As mentioned above, after the Django defines each model, the Add, change, and delete three permission of the model are added by default, and the custom permission can be added manually when we define the model:
class Task(models.Model):...class Meta:permissions = (("view_task", "Can see available tasks"),("change_task_status", "Can change the status of tasks"),("close_task", "Can remove a task by setting its status as closed"),)
Each permission is an instance of a django.contrib.auth.Permission type that contains three fields name, codename, and Content_Type, where Content_ The type responds to which permission belongs to which model,codename as above View_task, the code logic checks for permissions to use, and name is the description of permission, Name is displayed by default when you print permission to a screen or page.
Creating custom permissions in model, from a system development perspective, is understood to create built-in permissions for the system, if the requirements involve creating custom permissions when the user uses the system, use the following method:
from myapp.models import BlogPostfrom django.contrib.auth.models import Permissionfrom django.contrib.contenttypes.models import ContentTypecontent_type = ContentType.objects.get_for_model(BlogPost)permission = Permission.objects.create(codename=‘can_publish‘, name=‘Can Publish Posts‘, content_type=content_type)
2.2 User Permission Management
The User_permission field of the user object manages permissions for users:
myuser.user_permissions = [permission_list]myuser.user_permissions.add(permission, permission, ...) #增加权限myuser.user_permissions.remove(permission, permission, ...) #删除权限myuser.user_permissions.clear() #清空权限############################################################### 注:上面的permission为django.contrib.auth.Permission类型的实例##############################################################
Check user permissions with the Has_perm () method:
myuser.has_perm(‘myapp.fix_car‘)
The parameters of the Has_perm () method, that is, the permission codename, but the parameters need to be passed with the prefix of the app, in the format:
Whether the permission is given the user or the Group,has_perm () method applies
Note:
The User.get_all_permissions () method lists all permissions for the user, and the return value is the list of permission name
The User.get_group_permissions () method lists the permissions of the group to which the user belongs, and the return value is a list of permission name.
2.3 Group Permission Management
The group permission management logic is consistent with user permission management, and the group uses the permissions field for Rights Management:
group.permissions = [permission_list]group.permissions.add(permission, permission, ...)group.permissions.remove(permission, permission, ...)group.permissions.clear()。
Permission checks:
The User.has_perm () method is still used.
2.4 permission_required Decorator
Permissions can constrain user behavior, and when a permission check is involved in the business logic, decorator is able to separate permissions validation and core business logic, making the code more concise and logically clearer. The decorator of permission is permission_required:
from django.contrib.auth.decorators import permission_required@permission_required(‘car.drive_car‘)def my_view(request):...
Permission checks in the 2.5 template
The template uses the global variable perms to store all permissions for the current user, and the permission check can refer to the following example:
{% if perms.main.add_page %}<li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Pages <span class="caret"></span></a> <ul class="dropdown-menu" role="menu"><li><a href="{% url ‘main:admin_pages‘ %}">All Pages</a></li><li><a href="{% url ‘main:admin_page‘ %}">New Page</a></li><li><a href="{% url ‘main:admin_pages‘ %}?draft=true">Drafts</a></li> </ul></li>{% endif %}
3 Application of object permission based on Django-guardian
Django-guardian has extended Django's permissions mechanism based on Django's native logic, and after applying Django-guardian, you can check global permissions using the methods provided by Django-guardian and the native methods of Django. The object permission mechanism provided by Django-guardian makes Django's permissions mechanism more sophisticated.
Django-guardian the detailed use of the documentation, please refer to the official documentation, its object permission common methods are as follows:
from guardian.shortcuts import assign_perm, get_permsfrom guardian.core import ObjectPermissionCheckerfrom guardian.decorators import permission_required<p></p>
3.1 Adding an object permission
Add object permission using the Assign_perm () method, such as adding Drive_car permissions to the Mycar object for the user:
assign_perm(‘myapp.drive_car‘, request.user, mycar)
The Assign_perm () method can also be used for group
assign_perm(‘myapp.drive_car‘, mygroup, mycar)
3.2 Permission Check 3.2.1 Global permission
The Get_perms () method is used to check the user's global permission, which is similar to User.has_perm (), such as:
############################## It works! ############################# if not ‘main.change_post‘ in get_perms(request.user, post): raise HttpResponse(‘Forbidden‘)############################## It works, too!#############################if not request.user.has_perm(‘main.change_post‘)return HttpResponse(‘Forbidden‘)
In the example, although the post object is passed as a parameter to the Get_perms () method, it only checks the user's global permissions for Main.change_post permissions, and in many cases can be replaced with native User.has_perm, However, both user and group can be used as get_perms () parameters, and in some cases make the code more concise.
3.2.2 Object Permission
Django-guardian uses Objectpermissionchecker to check the user's object permission, as shown in the following example:
checker = ObjectPermissionChecker(request.user)print checker.has_perm(‘main.change_post‘, post)
3.3 permission_required Decorator
Guardian.decorators.permission_required is the decorator of the Django-guardian permission check, which checks both the global permission and the object's permissions (Objects permission), where , the Accept_global_perms parameter indicates whether to check the user's global permission, such as:
from guardian.decorators import permission_requiredclass DeletePost(View): @method_decorator(permission_required(‘main.delete_post‘, (models.Post, ‘id‘, ‘pk‘), accept_global_perms=True)) def get(self, request, pk): try: pk = int(pk) cur_post = models.Post.objects.get(pk=pk) is_draft = cur_post.is_draft url = reverse(‘main:admin_posts‘) if is_draft: url = ‘{0}?draft=true‘.format(url) cur_post.delete() except models.Post.DoesNotExist: raise Http404 return redirect(url)
Note:
In the decorator (models. Post, ' id ', ' PK ') section, used to specify an object instance, and if this argument is omitted, the global permission is only checked regardless of whether the accept_global_perms value is true or false.
4 Conclusion
Django Native provides a simple global permission control mechanism, but in many scenarios, object permissions (Objects permission) are more useful; Django-guardian is currently a more active Django Extension provides an effective object permission control mechanism, which is recommended for use with the Django native mechanism same strain.
Overview of the Django permissions mechanism