array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 rbac之 权限粒度控制到按钮级别 - 爱码网
chengege

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

 

 

分类:

技术点:

相关文章: