Django的权限管理
# Django 的权限管理
Django原生提供了一种简单的全局权限(global permission)控制机制,但很多应用场景下,django-guardian的对象权限(object permission)更加有用。 guradian 可具体到每条数据对象的权限。
# Django原生权限
- user, group和permission Django 的 models User 默认有groups 及user_permissions 这两个ManyToManyField字段
groups = models.ManyToManyField(Group,
verbose_name=_('groups'),
blank=True, help_text=_('The groups this user belongs to. A user will ' 'get all permissions granted to each of ''their groups.'),
related_name="user_set", related_query_name="user")
user_permissions = models.ManyToManyField(Permission,
verbose_name=_('user permissions'), blank=True,
help_text=_('Specific permissions for this user.'),
related_name="user_set", related_query_name="user")
2
3
4
5
6
7
8
9
10
Django权限(Permissions)作为一个Model存在的,建立一个权限就是创建一个Permission Model的实例。
- 将属于model的某个permission赋予user或group 设置权限方法
myuser.groups = [group_list] # 设置用户
myuser.groups.add(group, group, ...) # 添加用户到用户组
myuser.groups.remove(group, group, ...) # 移除从用户组
myuser.groups.clear() # 清除所有用户组
myuser.user_permissions = [permission_list]
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()
group.permissions = [permission_list]
group.permissions.add(permission, permission, ...)
group.permissions.remove(permission, permission, ...)
group.permissions.clear()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
每个model默认都有三个permission,即add model, change model和delete model 若INSTALLED_APPS配置了django.contrib.auth,每个Django Model会被创建3个缺省权限:add, change 和 delete。 例如:定义一个名为『Task』model后,会自动创建相应的三个permission:add_task, change_task和delete_task。
也可以为Task自定义新的权限项:view_task, change_task_status, close_task等等
# 在models.py 中自定义permission
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"),
)
# 在代码中自定义权限
from .models import Task
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
content_type = ContentType.objects.get_for_model(Task)
permission = Permission.objects.create(codename='view_task',
name='Can see available tasks',
content_type=content_type)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 每个permission都是django.contrib.auth.Permission类型的实例
- 每个Permission Model实例包含三个字段name(permission的描述), codename(permission的名称"view_task") 和 content_type(permission属于哪个model)
# 代码设计
- 为用户或组关联 permission
- 在view 中配置装饰器 permission_required,进行请求检查
# 用户(User)权限
# 权限设置
用户权限设置 myuser.user_permissions = [permission_list] myuser.user_permissions.add(permission, permission, ...) #增加权限 myuser.user_permissions.remove(permission, permission, ...) #删除权限 myuser.user_permissions.clear() #清空权限
用户组权限设置 group.permissions = [permission_list] group.permissions.add(permission, permission, ...) group.permissions.remove(permission, permission, ...) group.permissions.clear()
# 权限检查看
myuser.has_perm('myapp.add_task') # 检查用户权限 myuser.get_all_permissions() # 方法列出用户的所有权限,返回值是permission name的list myuser.get_group_permissions() # 方法列出用户所属group的权限,返回值是permission name的list
# 权限缓存
User的权限检查时是可以被缓存的,如果一个新权限被赋予一个User,如果再立即检查是不会被检查出来的。最简单的方法是重新获取User对象实例。
from django.contrib.auth.models import Permission, User
from django.shortcuts import get_object_or_404
def user_gains_perms(request, user_id):
user = get_object_or_404(User, pk=user_id)
#查看用户的权限集
user.has_perm('myapp.change_bar')
permission = Permission.objects.get(codename='change_bar')
user.user_permissions.add(permission)
# 查看用户的权限集
user.has_perm('myapp.change_bar') # False
# 请求新的User实例
user = get_object_or_404(User, pk=user_id)
# 查看用户的权限集
user.has_perm('myapp.change_bar') # True
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# permission_required 装饰器
permission_required 装饰器,应用在用户请求的view.py 文件中用以检查用户的操作行为
from django.contrib.auth.decorators import permission_required
@permission_required('myapp.add_task')
def my_view(request):
2
3
4
# Template中的权限检查
{% if perms.myapp.add_task %}
<li class="dropdown">
<a href="#" rel="external nofollow" 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 'myapp:admin_pages' %}" rel="external nofollow" >All Pages</a></li>
<li><a href="{% url 'myapp:admin_page' %}" rel="external nofollow" >New Page</a></li>
<li><a href="{% url 'myapp:admin_pages' %}?draft=true" rel="external nofollow" >Drafts</a></li>
</ul>
</li>
{% endif %}
2
3
4
5
6
7
8
9
10
11
# 基于Django-guardian的object permission的应用
from guardian.shortcuts import assign_perm, get_perms
from guardian.core import ObjectPermissionChecker
from guardian.decorators import permission_required
# 给当前用户对mytask对象数据添加 change_task_status 的权限
assign_perm('myapp.change_task_status', request.user, mytask)
# 给用户组mygroup对mytask对象数据添加 change_task_status 的权限
assign_perm('myapp.change_task_status', mygroup, mytask)
2
3
4
5
6
7
8
9
10
# 权限检查
get_perms()方法 ,与user.has_perm() 功能一样。
#############################
# 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')
## 也可应用ObjectPermissionChecker 方法
checker = ObjectPermissionChecker(request.user)
print checker.has_perm('main.change_task_status', mytask)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# permission_required 装饰器
用以控制用户访问权限
from guardian.decorators import permission_required
class DeleteTask(View):
@method_decorator(
permission_required(
'main.delete_task',
(models.Task, 'id', 'pk'),
accept_global_perms=True # 是否检查user的global permission
)
)
def get(self, request, pk):
try:
pk = int(pk)
cur_task = models.Task.objects.get(pk=pk)
is_draft = cur_task.is_draft
url = reverse('main:admin_tasks')
if is_draft:
url = '{0}?draft=true'.format(url)
cur_task.delete()
except models.Task.DoesNotExist:
raise Http404
return redirect(url)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25