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 完美。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM