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")

1
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()

1
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)
1
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 
1
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):
1
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 %}

1
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)

1
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)

1
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
上次更新: 2022/12/05, 22:29:05

Initializing...

最近更新
01
git的tag与branch 原创
05-21
02
阿里云SLS日志服务的数据脱敏及安全管理 原创
03-21
03
云平台的成本管理 原创
03-13
更多文章>
×