CRM项目之页面按钮

权限粒度控制到按钮

在这里插入图片描述
在上面的页面中,有添加缴费记录、删除缴费记录、修改缴费记录三个按钮,这三个按钮的权限不是对所有用户开放的,对与有权限的用户展示这些按钮是正常的,但是对于没有权限去操作按钮的用户,我们应该将无权限的按钮隐藏起来。就是说页面中的按钮显示与否,根据服务端权限配置来决定的,这就是权限粒度控制到按钮级别。

方式一:

我们之前在session中存储的权限信息结构是

    [
        {
            'id': 1,
            'url': '/customer/list/',
            'pid': null
        },
        {
            'id': 4,
            'url': '/customer/edit/(?P<cid>\d+)/',
            'pid': 1
        }
    ]

我们在显示按钮时,拿到按钮对应的url,在权限列表中进行匹配,如果存在就显示,不存在就不显示。但是写起来麻烦,'/customer/edit/(?P<cid>\d+)/'权限为这种时,就需要写正则来匹配。

方式二:

给每个url权限起个别名,后面拿着这个别名来来进行比较,就方便了很多,这个别名和在路由层的别名保持一致,在数据库中每个url对应的别名都是唯一且存在的。路由层的别名 url(r'^customer/list/$', customer.customer_list, name='customer_list'),.

方式二的实现流程:

1.修改权限表结构,给添加别名字段,给已有的表增加新字段,先将这个字段的参数设置为null=True, blank=True,进行数据库迁移和表字段内容更新。

class Permission(models.Model):
    """
    权限表
    """
    title = models.CharField(verbose_name='标题', max_length=32)
    url = models.CharField(verbose_name='含正则的URL', max_length=128)
    name = models.CharField(verbose_name='URL的别名', max_length=32, null=True, blank=True)

    menu = models.ForeignKey(to="Menu", verbose_name="所属菜单", null=True, blank=True, help_text="null表示不是菜单,非null表示是二级菜单")
    pid = models.ForeignKey(verbose_name="关联的权限",
                            help_text="对于非菜单权限选择一个可以成为菜单的权限,用于做默认展开和选中在访问非菜单功能时",
                            to="Permission",
                            null=True,
                            blank=True,
                            related_name="parents")

    def __str__(self):
        return self.title

2.数据更新完成后,将name字段修改为唯一不重复的属性,再次进行数据库迁移,name字段新增完毕。

name = models.CharField(verbose_name='URL的别名', max_length=32, unique=True)

3.存储在session中的权限信息结构修改。现在存储是以列表存储的,在判断当前按钮的url是否存在于session中时,不好进行判断,所以将以列表存储修改为以字典存储,用url的别名作为key,在判断的时直接判断key在不在session中,就可以决定了这个按钮是否显示。
4.代码修改
init_permission.py

def init_permission(current_user, request):
    '''
    初始化权限信息
    :param current_user: 当前登录用户
    :param request: 请求相关参数
    :return:
    '''
    # 当前用户所有权限
    permission_queryset = current_user.roles.filter(permissions__isnull=False).values(
        "permissions__id",
        "permissions__url",
        "permissions__name",
        "permissions__title",
        "permissions__pid",
        "permissions__pid__url",
        "permissions__pid__title",
        "permissions__menu__id",
        "permissions__menu__title",
        "permissions__menu__icon").distinct()

    # 获取权限中的url + 菜单信息
    menu_dict = {}
    permission_dict = {}
    for item in permission_queryset:
        permission_dict[item.get('permissions__name')] = {
            'id': item.get('permissions__id'),
            'url': item.get('permissions__url'),
            'pid': item.get('permissions__pid'),
            'title': item.get('permissions__title'),
            'p_title': item.get('permissions__pid__title'),
            'p_url': item.get('permissions__pid__url')
        }

        menu_id = item.get('permissions__menu__id')
        if not menu_id:
            continue

        node = {'title': item.get('permissions__title'), 'url': item.get("permissions__url"), 'id': item.get('permissions__id')}
        if menu_id not in menu_dict.keys():
            menu_dict[menu_id] = {
                'title': item.get('permissions__menu__title'),
                'icon': item.get('permissions__menu__icon'),
                'children': [node]
            }
        else:
            menu_dict[menu_id]['children'].append(node)

    print(menu_dict)
    # 放入session中
    request.session[settings.PERMISSION_SESSION_KEY] = permission_dict
    request.session[settings.MENU_SESSION_KEY] = menu_dict

mindwares/rbac.py

class RbacMiddleware(MiddlewareMixin):
    def process_request(self, request):
        '''
        1. 拿到当前用户请求的url
        2. 获取当前用户在session中保存的权限列表
        3. 权限信息匹配
        '''
        current_url = request.path_info
        # 有一些权限是所有人默认都有的,不需要做权限判断,先进行一个白名单判断,如果是白名单url,就不用再走权限判断了
        valid_url_list = settings.VALID_URL_LIST
        for valid_url in valid_url_list:
            if re.match(valid_url, current_url):
                # 白名单中的url,无需权限验证
                # 返回None,继续走后续步骤
                return None

        permission_dict = request.session.get(settings.PERMISSION_SESSION_KEY)
        if not permission_dict:
            # 返回 HttpResponse 不走 后续步骤,直接返回到页面
            return HttpResponse('为获取到用户权限信息')

        print(current_url)
        print(permission_dict)

        flag = False
        url_record = [
            {'title': '首页', 'url': '#'}
        ]
        for item in permission_dict.values():
            regx = '^{}$'.format(item.get('url'))
            if re.match(regx, current_url):
                flag = True
                request.current_selected_permission = item.get('pid') or item.get('id')
                if item.get('pid'):
                    # 三级路径导航
                    url_record.extend([
                        {'title': item.get('p_title'), 'url': item.get('p_url')},
                        {'title': item.get('title'), 'url': item.get('url'), 'class': 'active'}
                    ])
                else:
                    url_record.extend([{'title': item.get('title'), 'url': item.get('url'), 'class': 'active'}])
                print(url_record)
                break
        request.url_record = url_record

        if not flag:
            return HttpResponse('无权访问')

使用filter功能来判断,该按钮是否有权限显示

@register.filter
def has_permission(request, name):
    """
    判断是否有权限
    :param request:
    :param name:
    :return:
    """
    if name in request.session.get(settings.PERMISSION_SESSION_KEY):
        return True

    return False

使用的地方:
filter只能接收两个参数,这是注意点。

{% load rbac %}

{% if request|has_permission:'customer_add' %}
	<a class="btn btn-default" href="/customer/add/">
		<i class="fa fa-plus-square" aria-hidden="true"></i> 添加客户
	</a>
{% endif %}

5.在所有按钮处添加has_permission来判断按钮的显示即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值