zoukankan      html  css  js  c++  java
  • Django-xadmin+rule对象级权限的实现

    原文:https://blog.csdn.net/zcyuefan/article/details/77743380 

    1. 需求vs现状

    1.1 需求
    要求做一个ERP后台辅助管理的程序,有以下几项基本要求:
    1. 基本的增删改查功能
    2. 基于对象的权限控制(如:系统用户分为平台运营人员和商家用户,商家用户小A只能查看编辑所属商家记录,而管理员可以纵览全局)
    3. 数据库记录导入导出(xsl, json等),并且拥有对象级的权限控制(如:小A不能导出小B公司的信息,更不能导入小B公司信息进行更新和新增)

    1.2 现状
    实现需求1:Django-admin让我们能够很方便的实现一个管理后台程序。django-xadmin则在拥有admin基本功能的基础上增加了更为丰富的功能、界面也更加漂亮。类似还有django-suit等,本文使用xadmin(功能更丰富);
    实现需求2:django-admin,以及xadmin都只有基于model级的权限控制机制,需要自己扩展或者使用开源解决方案,如django-guardian,django-rules,本文结合django-rules实现了该功能;
    实现需求3:xadmin虽然自带导出功能,但是导入功能没有实现,django自带后台结合django-import-export可以很容易实现,但是xadmin并不直接兼容,只有通过xadmin的插件机制实现。
    2. 功能实现
    本节主要展示对象级权限功能实现。django工程、xadmin替换原生admin的设置,请参照官方文档。

    2.1 安装并配置rules
    pip安装:

    $ pip install rules
    1
    配置settings.py

    # settings.py
    INSTALLED_APPS = (
    # ...
    'rules',
    )
    AUTHENTICATION_BACKENDS = (
    'rules.permissions.ObjectPermissionBackend',
    'django.contrib.auth.backends.ModelBackend',
    )

    2.2 建立model
    新增CompanyUser模型表示商家账户(即对django自带user模块进行扩展,使每个账号绑定自己的公司码),新增Customer模型表示商家的客户信息并包含公司码字段,商家账号只能查看、编辑、导入、导出公司码一致的商家客户信息

    # model.py
    class CompanyUser(models.Model):
    user = models.OneToOneField(User, verbose_name='用户名')
    is_taixiang_admin = models.BooleanField('是否运营人员', default=False)
    company_code = models.CharField('公司码', max_length=20, blank=True, default='')

    def __unicode__(self):
    return '%s' % self.user

    class Meta:
    verbose_name = '导入账号'
    verbose_name_plural = verbose_name

    class Customer(models.Model):
    name = models.CharField('客户姓名', max_length=50)
    phone = models.CharField('客户电话', max_length=12)
    type_choice = ((1, '普通'), (2, '批发'), (3, 'VIP'))
    creator = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='创建人', blank=True, null=True)
    company_code = models.CharField('公司码', max_length=20, blank=True, null=True)

    def __unicode__(self):
    return '%s-%s-%s' % (self.company_code, self.name, self.phone1)

    class Meta:
    permissions = (
    ("simulate_import_customer", "允许模拟导入客户"),
    ("import_customer", "允许导入客户至商家系统"),
    )
    verbose_name = "客户"
    verbose_name_plural = verbose_name

    2.2 使用rule
    在model统计目录新增rules.py,配置该app相关的对象权限
    引用rules

    # rules.py
    # On Python 2, you must also add the following to the top of your rules.py file, or you'll get import errors trying to import django-rules itself
    from __future__ import absolute_import

    import rules

    # 使用修饰符@rules.predicate自定义predicates(判断),返回True表示有权限,False表示无权限

    # Predicates

    @rules.predicate
    def is_colleague(user, entry):
    if not entry or not hasattr(user, 'companyuser'):
    return False
    return entry.company_code == user.companyuser.company_code


    @rules.predicate
    def is_taixiang_admin(user):
    if not hasattr(user, 'companyuser'):
    return False
    return user.companyuser.is_taixiang_admin

    # predicates间可以进行运算
    is_colleague_or_taixiang_admin = is_colleague | is_taixiang_admin | rules.is_superuser

    # 设置Rules

    rules.add_rule('can_view_customer', is_colleague_or_taixiang_admin)
    rules.add_rule('can_delete_customer', is_colleague_or_taixiang_admin)
    rules.add_perm('can_change_customer', is_colleague_or_taixiang_admin)

    # 设置Permissions

    rules.add_perm('data_import.view_customer', is_colleague_or_taixiang_admin)
    rules.add_perm('data_import.delete_customer', is_colleague_or_taixiang_admin)
    rules.add_perm('data_import.add_customer', is_colleague_or_taixiang_admin)
    rules.add_perm('data_import.change_customer', is_colleague_or_taixiang_admin)

    2.3 admin.py以及adminx.py设置
    如果使用原生的django-admin,admin.py做如下设置:

    # admin.py
    from __future__ import absolute_import

    from django.contrib import admin
    from rules.contrib.admin import ObjectPermissionsModelAdmin
    from .models import Customer

    # ModelAdmin class继承ObjectPermissionsModelAdmin即可
    class CustomerAdmin(ObjectPermissionsModelAdmin):
    pass

    admin.site.register(Customer, CustomerAdmin)

    使用xadmin,由于ObjectPermissionsModelAdmin无法直接使用,故参照源码重写has_change_permission和has_delete_permission方法即可。
    注意:必须引用rules文件,权限规则才会生效,对于xadmin,添加
    from .rules import *即可

    # adminx.py
    class CustomerAdmin(object):
    def has_change_permission(self, obj=None):
    codename = get_permission_codename('change', self.opts)
    return self.user.has_perm('%s.%s' % (self.app_label, codename), obj)

    def has_delete_permission(self, obj=None):
    codename = get_permission_codename('delete', self.opts)
    return self.user.has_perm('%s.%s' % (self.app_label, codename), obj)

    # 重写queryset()或者get_list_display(),list view的权限也做到了对象级隔离
    def queryset(self):
    qs = super(CustomerAdmin, self).queryset()
    if self.request.user.is_superuser or is_taixiang_admin(self.request.user):
    return qs
    try:
    return qs.filter(company_code=self.request.user.companyuser.company_code)
    except AttributeError:
    return None

    class CompanyUserAdmin(object):
    pass

    xadmin.sites.site.register(Customer, CustomerAdmin)
    xadmin.sites.site.register(CompanyUser, CompanyUserAdmin)

    ---------------------
    作者:zcyuefan
    来源:CSDN
    原文:https://blog.csdn.net/zcyuefan/article/details/77743380
    版权声明:转载请附上博文链接!

  • 相关阅读:
    oracle 导入数据时提示只有 DBA 才能导入由其他 DBA 导出的文件
    oracle 常用语句
    android udp 无法收到数据 (模拟器中)
    android DatagramSocket send 发送数据出错
    AtCoder ABC 128E Roadwork
    AtCoder ABC 128D equeue
    AtCoder ABC 127F Absolute Minima
    AtCoder ABC 127E Cell Distance
    CodeForces 1166E The LCMs Must be Large
    CodeForces 1166D Cute Sequences
  • 原文地址:https://www.cnblogs.com/chdltanke/p/10368021.html
Copyright © 2011-2022 走看看