zoukankan      html  css  js  c++  java
  • rbac之 权限粒度控制到按钮级别

    rbac之 权限粒度控制到按钮级别:  这里的意思就是 如果当前用户,没有这个权限。 那么这个相对应的这个按钮的权限, 就不应该展示。看都不能给看到。

    思路:
      为每一个权限,设置一个别名。  这里是这的别名。 要与 路由控制器中的,每条路径的 别名保持一直
      模板中每一个按钮标签的位置,进行 if 判断。 判断这个别名是否在当前用户的,权限字典中。 如果有显示这个按钮。如果没有那就不显示

    数据表,进行更改:

    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="权限别名", max_length=32, unique=True)
        menu = models.ForeignKey(verbose_name="所属菜单", to="Menu", null=True, blank=True, on_delete=models.CASCADE)
        pid = models.ForeignKey(verbose_name="关联权限", help_text="对于非菜单权限,需要确定当前权限归属于哪一个,父权限",
                                to="Permission", null=True, blank=True, on_delete=models.CASCADE, )
    
        def __str__(self):
            return self.title
    Permission的最终形态。(以后想改 再改喽)

    然后,为了比较的方便。我对 登录时的,保存session权限列表的步骤。 进行更改,让他变成一个字典 key 就是 每个权限的别名 name字段

    def init_permission(current_user, request):
        '''  二级菜单,实现
        :param current_user: 当前请求 用户对象
        :param request:  当前请求 数据
        :return:
        '''
        # 2. 权限 初始化
        # 根据当前用户信息,获取当前用户所拥有的所有的权限(queryset对象 是不能直接放入,session中的)
        permission_queryset = current_user.roles.filter(permissions__isnull=False) 
            .values("permissions__id", "permissions__url", "permissions__title", "permissions__name",
                    "permissions__pid_id", "permissions__pid__title", "permissions__pid__url",
                    "permissions__menu_id", "permissions__menu__icon", "permissions__menu__title", ).distinct()
    
        # 获取权限 和 菜单信息。  权限放在权限列表,菜单放在菜单列表
        menu_dict = {}
        permission_dict = {}
        for item in permission_queryset:
            permission_dict[item.get("permissions__name")] = {
                "id": item.get("permissions__id"),
                "title": item.get("permissions__title"),
                "url": item.get("permissions__url"),
                "paren_id": item.get("permissions__pid_id"),
                "paren_title": item.get("permissions__pid__title"),
                "paren_url": item.get("permissions__pid__url"),
            }
    
            menu_id = item.get("permissions__menu_id")
            if not menu_id:
                continue
    
            node = {"id": item.get("permissions__id"), "title": item.get("permissions__title"),
                    "url": item.get("permissions__url")}
            if menu_id in menu_dict:
                menu_dict[menu_id]["children"].append(node)
            else:
                menu_dict[menu_id] = {
                    "title": item.get("permissions__menu__title"),
                    "icon": item.get("permissions__menu__icon"),
                    "children": [node]
                }
        request.session[settings.PERMISSIONS_SESSION_KEY] = permission_dict
        request.session[settings.MENU_SESSION_KEY] = menu_dict
    init_permission初始化,权限列表更改为,权限字典!

    相应的中间件的地方,也作了修改。 以前因为是一个列表中嵌套的字典格式。 但现在是一个大字典了。 所以 现在循环的是一个字典。

    需要for item in permission_dict.values():  直接去循环这个字典的 values 就可以了!其他的 还是原来的配方,还是原来的味道。

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    from django.conf import settings
    import re
    
    
    class RbacMiddleware(MiddlewareMixin):
        '''用户权限信息的校验'''
    
        def process_request(self, request):
            '''当用户请求进入时 触发执行'''
            '''
            1. 获取当前用户请求的url
            2. 获取当前用户在session中保存的 权限列表 [......]
            3. 当前请求url 在 session中, 就可以,进行访问
            '''
    
            current_url = request.path_info
            for valid_url in settings.VALID_URL_LIST:
                if re.match(valid_url, current_url):
                    return None
    
            permission_dict = request.session.get(settings.PERMISSIONS_SESSION_KEY)
    
            if not permission_dict:
                return HttpResponse("您没有访问权限...请联系管理员")
    
            flag = False
            url_record = [
                {"title": "首页", "url": "#"}
            ]
            for item in permission_dict.values():
                reg = "^%s$" % item.get("url")
                if re.match(reg, current_url):
                    flag = True
                    request.current_selected_permission = item.get("paren_id") or item.get("id")
                    if not item.get("paren_id"):
                        url_record.extend([{"title": item.get("title"), "url": item.get("url"), "class": "active"}])
                    else:
                        url_record.extend([
                            {"title": item.get("paren_title"), "url": item.get("paren_url")},
                            {"title": item.get("title"), "url": item.get("url"), "class": "active"},
                        ])
                    request.url_record = url_record
                    break
            if not flag:
                return HttpResponse("无权访问")
    对 rbac.py 中间件,进行修改

    最后就是 判断当前这个按钮的别名。 是否在当前用户的权限中有,这个别名:
      解释: 1. 进行判断两个参数, 第一个是当前这个按钮所指向的 url 他的别名好说。 直接写字符串就行。
    然后就是,当前用户的权限信息了。 我保存在了  ssession 里面。  具体的就是:
                 request.session[settings.PERMISSIONS_SESSION_KEY] = permission_dict  ( 以别名为键的 权限字典 )
        我进行判断时,大概就是这个样子:
          {% if  "costomer_add" in request.session.permissions_url_list_key%}
            .........
          {%endif%}
    如果我想要直接进行,判断也是可以的, 但是我的初衷 这个 session-key 是可以在settings中进行配置的。 so我们来自定义一个 模板过滤器吧,因为模板过滤器是可以进行逻辑判断的  另外几个就不行 所以使用 @register.filter 没毛病:

      这个过滤器接收 name  和 request 两个参数:

    @register.filter
    def has_permission(request, name):
        '''
        :param request:  request对象
        :param name:   当前权限的别名
        :return:
        '''
        if name in request.session.get(settings.PERMISSIONS_SESSION_KEY):
            return True
    
    如果当前的name别名,在我保存的字典中,return Ture
    否则 默认返回 None
    rbac_tags 自第一过滤器

    ok  过滤器完成: 模板的使用,就简单了:

    {% if request|has_permission:"customer_add" %}
      ...........
    {% endif %}
    这是一种使用的规范,模板过滤器只接收 最多两个参数。 | 之前的时第一个参数。 |之后是这个过滤器的名字 : 之后的是第二个参数。 这中间不要加空格
    {% extends 'layout.html' %}
    {% load rbac_tags %}
            <div class="btn-group" style="margin: 5px 0">
                {% 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 %}
                {% if request|has_permission:"customer_aimport" %}
                <a class="btn btn-default" href="/customer/import/">
                    <i class="fa fa-file-excel-o" aria-hidden="true"></i> 批量导入
                </a>
                {% endif %}
            </div>
    对每一个按钮的 地方都加上,这样的一个判断。就OK啦

    然后, 有一点。 选项这里, 编辑和删除的操作。
    这里应该是  如果当前用户,有 编辑 或 删除任何一个,权限。那么就应该有选项 的 展示。 如果都没有,那么就应该是空的。
    依然使用 这个 过滤器:

    <table class="table table-bordered table-hover">
                <thead>
                <tr>
                    <th>ID</th>
                    <th>客户姓名</th>
                    <th>年龄</th>
                    <th>邮箱</th>
                    <th>公司</th>
                    {% if request|has_permission:"customer_edit" or request|has_permission:"customer_del" %}
                        <th>选项</th>
                    {% endif %}
                </tr>
                </thead>
                <tbody>
                {% for row in data_list %}
                    <tr>
                        <td>{{ row.id }}</td>
                        <td>{{ row.name }}</td>
                        <td>{{ row.age }}</td>
                        <td>{{ row.email }}</td>
                        <td>{{ row.company }}</td>
                        <td>
                            {% if request|has_permission:"customer_edit" %}
                                <a style="color: #333333;" href="/customer/edit/{{ row.id }}/">
                                    <i class="fa fa-edit" aria-hidden="true"></i></a>
                            {% endif %}
    
                            {% if request|has_permission:"customer_del" %}
                                <a style="color: #d9534f;" href="/customer/del/{{ row.id }}/"><i class="fa fa-trash-o"></i></a>
                            {% endif %}
                        </td>
                    </tr>
                {% endfor %}
                </tbody>
    

     ok 完美。

     

  • 相关阅读:
    627. Swap Salary
    176. Second Highest Salary
    596. Classes More Than 5 Students
    183. Customers Who Never Order
    181. Employees Earning More Than Their Managers
    182. Duplicate Emails
    175. Combine Two Tables
    620. Not Boring Movies
    595. Big Countries
    HDU 6034 Balala Power! (贪心+坑题)
  • 原文地址:https://www.cnblogs.com/chengege/p/10703633.html
Copyright © 2011-2022 走看看