zoukankan      html  css  js  c++  java
  • Django权限机制的实现

    Django权限机制的实现


     

    一、django权限机制

    1.1、django 的权限控制

     Django用user, group和permission完成了权限机制,这个权限机制是将属于model的某个permission赋予user或group,可以理解为全局的权限,即如果用户A对数据模型(model)B有可写权限,那么A能修改model B的所有实例(objects)。group的权限也是如此,如果为group C 赋予model B的可写权限,则隶属于group C 的所有用户,都可以修改model B的所有实例。

     这种权限机制只能解决一些简单的应用需求,而大部分应用场景下,需要更细分的权限机制。以博客系统为例,博客系统的用户可分为『管理员』、『编辑』、『作者』和『读者』四个用户组;博客系统管理员和编辑具有查看、修改和删除所有的文章的权限,作者只能修改和删除自己写的文章,而读者则只有阅读权限。管理员、编辑和读者的权限,我们可以用全局权限做控制,而对于作者,全局权限无法满足需求,仅通过全局权限,要么允许作者编辑不属于自己的文章,要么让作者连自己的文章都无法修改。

     上述的应用场景,Django自带的权限机制无法满足需求,需要引入另一种更细的权限机制:对象权限(object permission)

    Object Permission是一种对象颗粒度上的权限机制,它允许为每个具体对象授权。仍沿用最开始的例子,如果model B有三个实例 B1,B2 和B3,如果我们把B1的可写权限赋予用户A,则A可以修改B1对象,而对B2,B3无法修改。对group也一样,如果将B2的可写权限赋予group C,则隶属于group C的所有用户均可以修改B2,但无法修改B1和B3。结合Django自带权限机制和object permission,可完成更细致的权限控制。

     Django其实包含了object permission的框架,但没有具体实现,object permission的实现需要借助第三方app django-guardian,我们在开发中用调用django guradian封装好的方法即可。


    1.2、django的权限项

     Django用permission对象存储权限项,每个model默认都有三个permission,即add model, change model和delete model。例如,定义一个名为『Car』model,定义好Car之后,会自动创建相应的三个permission:add_car, change_cardelete_car。Django还允许自定义permission,例如,我们可以为Car创建新的权限项:drive_car, clean_car, fix_car等等

    需要注意的是,permission总是与model对应的,如果一个object不是model的实例,我们无法为它创建/分配权限。


    2、django 自带权限权限机制的应用

     2.1、permission

     Django定义每个model后,默认都会添加该model的add, change和delete三个permission,自定义的permission可以在我们定义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"),
            )
    每个permission都是django.contrib.auth.Permission类型的实例,该类型包含三个字段name, codename 和 content_type,其中 content_type反应
    了permission属于哪个model,codename如上面的view_task,代码逻辑中检查权限时要用, name是permission的描述,将permission打印到屏幕或页面时默
    认显示的就是name

     在model中创建自定义权限,从系统开发的角度,可理解为创建系统的内置权限,如果需求中涉及到用户使用系统时创建自定义权限,则可以通过下面方法:

    from myapp.models import BlogPost
    from django.contrib.auth.models import Permission
    from django.contrib.contenttypes.models import ContentType
    
    content_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 管理

     User对象的user_permission字段管理用户的权限:

    from myapp.models import BlogPost
    from django.contrib.auth.models import Permission
    from django.contrib.contenttypes.models import ContentType
    
    content_type = ContentType.objects.get_for_model(BlogPost)
    permission = Permission.objects.create(codename='can_publish',
                                           name='Can Publish Posts',
                                           content_type=content_type)    # 单个权限
    
    permission_list = Permission.objects.create(content_type=content_type)    #权限列表
    
    
    myuser.user_permissions = [permission_list]   # 一次性增加所有权限
    myuser.user_permissions.add(permission, permission, ...) #一条条权限增加
    myuser.user_permissions.remove(permission, permission, ...) #一条条权限删除
    myuser.user_permissions.clear() #清空权限

    用户权限方法:

    1. myuser.user_permissions.set(permission_list):直接给定一个权限的列表。
    2. myuser.user_permissions.add(permission,permission,…):一个个添加权限
    3. myuser.user_permissions.remove(permission,permission,…):一个个删除权限。
    4. myuser.user_permissions.clear():清除所有的权限。
    5. myuser.has_perm(’<app_name>.’):判断是否拥有某个权限。权限参数是一个字符串,格式是app_name.codename。使用于 user、group 的权限判断
    6. myuser.get_all_permissons():获取所有的权限,返回值是permission name的list
    7. myuser.get_groupl_permissons():列出用户所属group的权限,返回值是permission name的list

    需要注意的是,执行完上述方法后,记得执行 save() 方法才能保存


    2.3、Group 与 权限管理

     group permission管理逻辑与user permission管理一致,group中使用permissions字段做权限管理:

    group.permissions = [permission_list]
    group.permissions.add(permission, permission, ...)
    group.permissions.remove(permission, permission, ...)
    group.permissions.clear()

     group 权限示例:分组 → 编辑组/财务组/管理员/超级管理员

    from django.core.management.base import BaseCommand
    from django.contrib.auth.models import Group, Permission, ContentType
    
    from news.models import News, NewsCategory, Comment, Banner
    from courses.models import Course, CourseCategory, Teacher, CourseOrder
    
    
    class Command(BaseCommand):
        def handle(self, *args, **options):
            # 1. 编辑组:管理新闻/管理课程/管理评论/管理轮播图
            edit_content_types = {   # 获取相关models下指定表的 contenttype
                ContentType.objects.get_for_model(News),
                ContentType.objects.get_for_model(NewsCategory),
                ContentType.objects.get_for_model(Banner),
                ContentType.objects.get_for_model(Comment),
                ContentType.objects.get_for_model(Course),
                ContentType.objects.get_for_model(CourseCategory),
                ContentType.objects.get_for_model(Teacher),
            }
            edit_permissions = Permission.objects.filter(content_type__in=edit_content_types)   # 找到相关表的所有权限
            editGroup = Group.objects.create(name="编辑组")    # 创建组
            editGroup.permissions.set(edit_permissions)     # 将表权限分配给 编辑组
            editGroup.save()
            self.stdout.write(self.style.SUCCESS("编辑分组完成!"))
    
            # 2. 财务组:管理课程订单
            finance_content_types = {  # 获取相关models下指定表的 contenttype
                ContentType.objects.get_for_model(CourseOrder),
            }
            finance_permissions = Permission.objects.filter(content_type__in=finance_content_types)  # 找到相关表的所有权限
            financeGroup = Group.objects.create(name="财务组")  # 创建组
            financeGroup.permissions.set(finance_permissions)  # 将表权限分配给 编辑组
            financeGroup.save()
            self.stdout.write(self.style.SUCCESS("财务分组完成!"))
    
            # 3. 管理员:包含编辑组 + 财务组 权限
            admin_permissions = edit_permissions.union(finance_permissions)
            adminGroup = Group.objects.create(name="管理员")  # 创建组
            adminGroup.permissions.set(admin_permissions)  # 将表权限分配给 编辑组
            adminGroup.save()
            self.stdout.write(self.style.SUCCESS("管理员分组完成!"))
    
            # 4.超级管理员
            # is_superuser
    View Code

    2.4、permission_required() 装饰器

     权限能约束用户行为,当业务逻辑中涉及到权限检查时,decorator能够分离权限验证和核心的业务逻辑,使代码更简洁,逻辑更清晰。permission的decorator为permission_required ,示例代码:

    from django.contrib.auth.decorators import permission_required
    
    @permission_required('news.add_news')
    def my_view(request):
        ...

    2.5、Template 模板中的权限检查:

    1)在前端模板中使用全局变量 perms

     在settings.py 中的TEMPLATES下定义了认证 auth 上下文处理器:

      'django.contrib.auth.context_processors.auth',

     因此,在全局中可使用全局变量 perms 来执行某些权限相关的操作,perms 中存储着当前用户的所有权限

    前端使用 perms 进行权限判断:

    # Django 前端模板中使用
    {% if perms.news.change_news %}
        ……
    {% endif %}
    
    # perms:全局变量 ,存储当前用户所有权限
    # news:app名称,不是表名
    # change_news:对表数据的操作类型, 即具有更改news表数据的权限

     2)在后端代码中使用全局变量 perms

     在后端代码中控制权限,需要用到 django 自带装饰器:permission_required , 如果后端代码使用的是类视图的方式,则还需要借助装饰器:method_decorator , 具体使用如下:

    # 1. 函数级别视图类型: 
    
    from django.contrib.auth.decorators import permission_required
    
    @permission_required(perm="news.view_newscategory", login_url="/crm/index/")
    def new_category(request):
        ……
    """
    只有具有查看newscategory 权限的用户才能查看newscategory ,无此权限则跳转到crm首页 news:app名称 view_newscategory:权限,查看newscategory表数据的权限
    """ # 2. 类视图级别使用: from django.utils.decorators import method_decorator from django.contrib.auth.decorators import permission_required @method_decorator(permission_required(perm="news.change_news", login_url="/crm/index/"), name="dispatch") class EditNews(View): """ 编辑新闻 @method_decorator:在类中要使用装饰器,得借助这个装饰器 permission_required: 权限装饰器 perm: 权限 ,有编辑新闻的权限才能进入此类中操作, login_url:没此权限时时跳转的url name:指明运行EditView类下的所有子函数 """

    二、基于 Django-guardian 的 object permission 的应用 

      Django-guardian基于django的原生逻辑扩展了django的权限机制,应用django-guardian后,可以使用django-guardian提供的方法以及django的原生方法检查全局权限,django-guardian提供的object permission机制使django的权限机制更加完善

    待续


  • 相关阅读:
    HDU 5486 Difference of Clustering 图论
    HDU 5481 Desiderium 动态规划
    hdu 5480 Conturbatio 线段树 单点更新,区间查询最小值
    HDU 5478 Can you find it 随机化 数学
    HDU 5477 A Sweet Journey 水题
    HDU 5476 Explore Track of Point 数学平几
    HDU 5475 An easy problem 线段树
    ZOJ 3829 Known Notation 贪心
    ZOJ 3827 Information Entropy 水题
    zoj 3823 Excavator Contest 构造
  • 原文地址:https://www.cnblogs.com/Eric15/p/11126999.html
Copyright © 2011-2022 走看看