zoukankan      html  css  js  c++  java
  • 权限管理系统

    一、需求分析:

    用户登录
    - 获取当前用户具有的所有角色
    - 获取当前用户具有的所有权限(去重)

      -在访问列表页面时,需要判断:有无添加权限,有无删除权限,有无编辑权限;在页面上显示相应权限按钮

      -访问菜单URL时,默认展开其所属菜单

      -访问非菜单URL,默认选中原菜单

     二、方法步骤

    a.首先建一个名为rbac的APP

    b.创建表结构,基于角色权限控制、菜单:

      -5个类,7张表

    
    

     

    from django.db import models
    

    class Menu(models.Model):
    """
    菜单组
    """
    title
    = models.CharField(max_length=32)

    </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Meta:
        verbose_name_plural </span>= <span style="color: #800000;">"</span><span style="color: #800000;">菜单组</span><span style="color: #800000;">"</span>
    
    <span style="color: #0000ff;">def</span> <span style="color: #800080;">__str__</span><span style="color: #000000;">(self):
        </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> self.title
    

    class Group(models.Model):
    """
    权限组
    """
    caption
    = models.CharField(verbose_name='组名称', max_length=16)
    menu
    = models.ForeignKey(verbose_name='所属菜单', to='Menu', default=1)

    </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Meta:
        verbose_name_plural </span>= <span style="color: #800000;">"</span><span style="color: #800000;">权限组</span><span style="color: #800000;">"</span>
    
    <span style="color: #0000ff;">def</span> <span style="color: #800080;">__str__</span><span style="color: #000000;">(self):
        </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> self.caption
    

    class Permission(models.Model):
    """
    权限表
    """
    title
    = models.CharField(verbose_name='标题', max_length=32)
    url
    = models.CharField(verbose_name="含正则URL", max_length=64)

    menu_gp </span>= models.ForeignKey(verbose_name=<span style="color: #800000;">'</span><span style="color: #800000;">组内菜单</span><span style="color: #800000;">'</span>, to=<span style="color: #800000;">'</span><span style="color: #800000;">Permission</span><span style="color: #800000;">'</span>, null=True, blank=True, related_name=<span style="color: #800000;">'</span><span style="color: #800000;">x1</span><span style="color: #800000;">'</span><span style="color: #000000;">)
    
    code </span>= models.CharField(verbose_name=<span style="color: #800000;">"</span><span style="color: #800000;">操作</span><span style="color: #800000;">"</span>, max_length=16<span style="color: #000000;">)
    group </span>= models.ForeignKey(verbose_name=<span style="color: #800000;">'</span><span style="color: #800000;">所属组</span><span style="color: #800000;">'</span>, to=<span style="color: #800000;">"</span><span style="color: #800000;">Group</span><span style="color: #800000;">"</span><span style="color: #000000;">)
    
    </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Meta:
        verbose_name_plural </span>= <span style="color: #800000;">"</span><span style="color: #800000;">权限表</span><span style="color: #800000;">"</span>
    
    <span style="color: #0000ff;">def</span> <span style="color: #800080;">__str__</span><span style="color: #000000;">(self):
        </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> self.title
    

    class User(models.Model):
    """
    用户表
    """
    username
    = models.CharField(verbose_name='用户名', max_length=32)
    password
    = models.CharField(verbose_name='密码', max_length=64)
    email
    = models.CharField(verbose_name='邮箱', max_length=32)

    roles </span>= models.ManyToManyField(verbose_name=<span style="color: #800000;">'</span><span style="color: #800000;">具有的所有角色</span><span style="color: #800000;">'</span>, to=<span style="color: #800000;">"</span><span style="color: #800000;">Role</span><span style="color: #800000;">"</span>, blank=<span style="color: #000000;">True)
    
    </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Meta:
        verbose_name_plural </span>= <span style="color: #800000;">"</span><span style="color: #800000;">用户表</span><span style="color: #800000;">"</span>
    
    <span style="color: #0000ff;">def</span> <span style="color: #800080;">__str__</span><span style="color: #000000;">(self):
        </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> self.username
    

    class Role(models.Model):
    """
    角色表
    """
    title
    = models.CharField(max_length=32)
    permissions
    = models.ManyToManyField(verbose_name='具有的所有权限', to='Permission', blank=True)

    </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Meta:
        verbose_name_plural </span>= <span style="color: #800000;">"</span><span style="color: #800000;">角色表</span><span style="color: #800000;">"</span>
    
    <span style="color: #0000ff;">def</span> <span style="color: #800080;">__str__</span><span style="color: #000000;">(self):
        </span><span style="color: #0000ff;">return</span> self.title</pre>
    
    models.py
    verbose_name---在admin模式下,字段显示的名字
    blank=True  ---在admin模式下,字段可以为空
    class Meta:
    verbose_name_plural = "表名"  ---在admin模式下,显示的表名

    为了让我们的表能在admin模式下显示,我们需要在rbac文件下的admin.py中,进行如下设置

    from django.contrib import admin
    

    from . import models

    admin.site.register(models.Permission)
    admin.site.register(models.User)
    admin.site.register(models.Role)
    admin.site.register(models.Group)
    admin.site.register(models.Menu)

    /rbac/admin.py

    c.基于Django admin录入权限数据 

      python manage.py createsuperuser

    d.用户登录程序

      按照逻辑,当我们输入一个URL,在跳转到相应页面前,我们需要做3件事:

      1.首先应该先判断此URL,是否限制用户浏览,如果没有限制,则不需要登录,直接进入相应页面(可在settings中设置白名单实现)

            2.若限制了,则需要检验用户的访问权限,在检验用户权限之前,我们得先检验用户登录状态(通过判断登陆成功后设置的session值是否存在),拿到用户权限信息(先比对账户密码,正确则设置一个session,用作检验登陆状态)

            3.如果是登录的状态,我们还需要检验用户是否有浏览此页面的权限(为此我们需要把当前URL和用户所有权限里的URL进行比对),如能访问此URL,当进入URL后,我们还需要根据用户的身份,在页面上显示不同的操作权限(如增删改查,有哪些操作权限就让哪些操作权限显示,没有的就不让其显示出来)

    由于每次跳转一个URL前,都会重复上面的步骤,我们可以将上面的方法代码写入中间件中,以免为此给每个视图函数都加上一个装饰器(麻烦)

    比对账户密码,设置session的过程应该是在视图函数里完成,由于我们在中间件中会检验登陆状态时会用到session,所以我们可以用户的一些权限信息放到session中

    现在我们需要考虑的是session中到底需要存放哪些信息?

    首先,我们来考虑一下,作为权限管理系统,我们希望能根据用户的权限,在页面显示一些相应菜单信息和操作按钮,所以session设置,我们分两个部分:

    一个是权限相关,用来检验用户访问权限,以及页面权限相关按钮(添加、编辑、删除)显示与否

    二是菜单相关,比如我们点击菜单一里的子选项:用户列表,显示页面信息后,菜单一仍然是展开状态,当我们在用户列表点击添加用户,跳转新页面时,仍然展开菜单一

    session权限相关

    根据需求,我们知道,权限相关里,我们需要拿到用户可访问的所有页面(url,用来匹配访问权限)用户所有可执行的操作(code,用来匹配可显示的操作键)、和(permissions__group_id)用来把权限归类

    为了方便后取数据,所以我们最终想要的结构是

    {group_id1:{

      urls:[url1、url2、url3....],

      codes:[list、del、edit、add]},

    group_id2:{

      urls:[url1、url2、url3....],

      codes:[list、del、edit、add]}

    session菜单相关

    根据需求,我们知道,权限相关里,我们需要menu_title(大菜单标题)menu_id(大菜单的id,用来通过此id归类子菜单)menu_gp_id(组内id,用于判断是否可以作为子菜单,以及非子菜单所属的子菜单)permission_id(通过可做菜单的id,分组其下面的url)permission_title(子菜单的标题)url(用于放在a标签里作跳转链接,如果不是子菜单,则打开的是此链接,其所属组所在菜单栏应该展开)

    所以我们一共要取出

    复制代码
        list = user.roles.values('permissions__code',  # 权限操作
                                 'permissions__title',  # 权限名
                                 'permissions__url',  # 权限url
                                 'permissions__id',  # 权限id
                                 'permissions__menu_gp_id',  # 组内菜单id
                                 'permissions__group_id',  # 权限组id
                                 'permissions__group__menu__id',  # 菜单id
                                 'permissions__group__menu__caption',  # 菜单名
                                 ).distinct()
    复制代码

    一定要去重,因为有的人有几个身份,有的权限会重复,将上面拿到的数据,再处理一下,分别作为,菜单相关,权限相关所需的数据

    由于以上步骤过多,我们应该从视图函数里抽离出来,单独在rbac文件夹下建一个service文件夹,里面建一个名为init_permission.py的初始化文件

    from django.conf import settings
    

    def init_permission(user,request):
    """
    初始化权限信息,获取权限信息并放置到session中。
    """
    permission_list
    = user.roles.values('permissions__id',
    'permissions__title', # 用户列表
    'permissions__url',
    'permissions__code',
    'permissions__menu_gp_id', # 组内菜单ID,Null表示是菜单
    'permissions__group_id',
    'permissions__group__menu_id', # 菜单ID
    'permissions__group__menu__title',# 菜单名称
    ).distinct() #要去重,因为每个人可能有多种身份,权限会重复

    <span style="color: #008000;">#</span><span style="color: #008000;"> 菜单相关(以后再匹配)</span>
    sub_permission_list =<span style="color: #000000;"> []
    </span><span style="color: #0000ff;">for</span> item <span style="color: #0000ff;">in</span><span style="color: #000000;"> permission_list:
        tpl </span>=<span style="color: #000000;"> {
            </span><span style="color: #800000;">'</span><span style="color: #800000;">id</span><span style="color: #800000;">'</span>:item[<span style="color: #800000;">'</span><span style="color: #800000;">permissions__id</span><span style="color: #800000;">'</span><span style="color: #000000;">],
            </span><span style="color: #800000;">'</span><span style="color: #800000;">title</span><span style="color: #800000;">'</span>:item[<span style="color: #800000;">'</span><span style="color: #800000;">permissions__title</span><span style="color: #800000;">'</span><span style="color: #000000;">],
            </span><span style="color: #800000;">'</span><span style="color: #800000;">url</span><span style="color: #800000;">'</span>:item[<span style="color: #800000;">'</span><span style="color: #800000;">permissions__url</span><span style="color: #800000;">'</span><span style="color: #000000;">],
            </span><span style="color: #800000;">'</span><span style="color: #800000;">menu_gp_id</span><span style="color: #800000;">'</span>:item[<span style="color: #800000;">'</span><span style="color: #800000;">permissions__menu_gp_id</span><span style="color: #800000;">'</span><span style="color: #000000;">],
            </span><span style="color: #800000;">'</span><span style="color: #800000;">menu_id</span><span style="color: #800000;">'</span>:item[<span style="color: #800000;">'</span><span style="color: #800000;">permissions__group__menu_id</span><span style="color: #800000;">'</span><span style="color: #000000;">],
            </span><span style="color: #800000;">'</span><span style="color: #800000;">menu_title</span><span style="color: #800000;">'</span>:item[<span style="color: #800000;">'</span><span style="color: #800000;">permissions__group__menu__title</span><span style="color: #800000;">'</span><span style="color: #000000;">],
        }
        sub_permission_list.append(tpl)
    request.session[settings.PERMISSION_MENU_KEY] </span>=<span style="color: #000000;"> sub_permission_list
    
    
    </span><span style="color: #008000;">#</span><span style="color: #008000;"> 权限相关</span>
    result =<span style="color: #000000;"> {}
    </span><span style="color: #0000ff;">for</span> item <span style="color: #0000ff;">in</span><span style="color: #000000;">  permission_list:
        group_id </span>= item[<span style="color: #800000;">'</span><span style="color: #800000;">permissions__group_id</span><span style="color: #800000;">'</span><span style="color: #000000;">]
        code </span>= item[<span style="color: #800000;">'</span><span style="color: #800000;">permissions__code</span><span style="color: #800000;">'</span><span style="color: #000000;">]
        url </span>= item[<span style="color: #800000;">'</span><span style="color: #800000;">permissions__url</span><span style="color: #800000;">'</span><span style="color: #000000;">]
        </span><span style="color: #0000ff;">if</span> group_id <span style="color: #0000ff;">in</span><span style="color: #000000;"> result:
            result[group_id][</span><span style="color: #800000;">'</span><span style="color: #800000;">codes</span><span style="color: #800000;">'</span><span style="color: #000000;">].append(code)
            result[group_id][</span><span style="color: #800000;">'</span><span style="color: #800000;">urls</span><span style="color: #800000;">'</span><span style="color: #000000;">].append(url)
        </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
            result[group_id] </span>=<span style="color: #000000;"> {
                </span><span style="color: #800000;">'</span><span style="color: #800000;">codes</span><span style="color: #800000;">'</span><span style="color: #000000;">:[code,],
                </span><span style="color: #800000;">'</span><span style="color: #800000;">urls</span><span style="color: #800000;">'</span><span style="color: #000000;">:[url,]
            }
    
    request.session[settings.PERMISSION_URL_DICT_KEY] </span>= result</pre>
    
    init_permission.py

    我们只需要在login的视图函数里验证完用户名密码后,调用函数就行

    init_permission(user,request)

    要记得先导入,才能成功调用

    from rbac.service.init_permission import init_permission

    这样我们就完成了session值的设置,接下来我们可以写我们的中间件了

    在rbac中建立一个middlewares文件夹,然后建一个名为rbac.py的文件,用来编写我们自定义的中间件代码

    import re
    

    from django.shortcuts import redirect,HttpResponse
    from django.conf import settings

    class MiddlewareMixin(object):
    def init(self, get_response=None):
    self.get_response
    = get_response
    super(MiddlewareMixin, self).
    init()

    </span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__call__</span><span style="color: #000000;">(self, request):
        response </span>=<span style="color: #000000;"> None
        </span><span style="color: #0000ff;">if</span> hasattr(self, <span style="color: #800000;">'</span><span style="color: #800000;">process_request</span><span style="color: #800000;">'</span><span style="color: #000000;">):
            response </span>=<span style="color: #000000;"> self.process_request(request)
        </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> response:
            response </span>=<span style="color: #000000;"> self.get_response(request)
        </span><span style="color: #0000ff;">if</span> hasattr(self, <span style="color: #800000;">'</span><span style="color: #800000;">process_response</span><span style="color: #800000;">'</span><span style="color: #000000;">):
            response </span>=<span style="color: #000000;"> self.process_response(request, response)
        </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> response
    

    class RbacMiddleware(MiddlewareMixin):

    </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> process_request(self,request):
        </span><span style="color: #008000;">#</span><span style="color: #008000;"> 1. 获取当前请求的URL</span>
        <span style="color: #008000;">#</span><span style="color: #008000;"> request.path_info</span>
        <span style="color: #008000;">#</span><span style="color: #008000;"> 2. 获取Session中保存当前用户的权限</span>
        <span style="color: #008000;">#</span><span style="color: #008000;"> request.session.get("permission_url_list')</span>
        current_url =<span style="color: #000000;"> request.path_info
    
        </span><span style="color: #008000;">#</span><span style="color: #008000;"> 当前请求不需要执行权限验证</span>
        <span style="color: #0000ff;">for</span> url <span style="color: #0000ff;">in</span><span style="color: #000000;"> settings.VALID_URL:
            </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> re.match(url,current_url):
                </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> None
    
        </span><span style="color: #008000;">#</span><span style="color: #008000;">在视图函数那边验证用户登录成功后,会设置session,如果登录成功则会有此session</span>
        permission_dict =<span style="color: #000000;"> request.session.get(settings.PERMISSION_URL_DICT_KEY)
        </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> permission_dict:
            </span><span style="color: #008000;">#</span><span style="color: #008000;">没有session值,则说明没有登录,需要跳转登录页面</span>
            <span style="color: #0000ff;">return</span> redirect(<span style="color: #800000;">'</span><span style="color: #800000;">/login/</span><span style="color: #800000;">'</span><span style="color: #000000;">)
    
        flag </span>=<span style="color: #000000;"> False
        </span><span style="color: #0000ff;">for</span> group_id,code_url <span style="color: #0000ff;">in</span><span style="color: #000000;"> permission_dict.items():
    
            </span><span style="color: #0000ff;">for</span> db_url <span style="color: #0000ff;">in</span> code_url[<span style="color: #800000;">'</span><span style="color: #800000;">urls</span><span style="color: #800000;">'</span><span style="color: #000000;">]:
                regax </span>= <span style="color: #800000;">"</span><span style="color: #800000;">^{0}$</span><span style="color: #800000;">"</span>.format(db_url)  <span style="color: #008000;">#</span><span style="color: #008000;">为了精准匹配</span>
                <span style="color: #008000;">#</span><span style="color: #008000;"> 将当前页面与当前用户可访问的页面进行匹配</span>
                <span style="color: #0000ff;">if</span><span style="color: #000000;"> re.match(regax, current_url):
                    </span><span style="color: #008000;">#</span><span style="color: #008000;">匹配成功后将用户的可执行的(增、删、改、列表等操作)存到request中,方便调用</span>
                    request.permission_code_list = code_url[<span style="color: #800000;">'</span><span style="color: #800000;">codes</span><span style="color: #800000;">'</span><span style="color: #000000;">]
                    flag </span>=<span style="color: #000000;"> True
                    </span><span style="color: #0000ff;">break</span>
    
            <span style="color: #0000ff;">if</span><span style="color: #000000;"> flag:
                </span><span style="color: #0000ff;">break</span>
        <span style="color: #008000;">#</span><span style="color: #008000;">匹配失败,则显示无权访问</span>
        <span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> flag:
            </span><span style="color: #0000ff;">return</span> HttpResponse(<span style="color: #800000;">'</span><span style="color: #800000;">无权访问</span><span style="color: #800000;">'</span>)</pre>
    
    rbac/middlewares/rbac.py

    写完自定义中间件后,记得去settings.py中加上我们写的中间件,来让我们的中间件生效

    MIDDLEWARE = ['rbac.middlewares.rbac.RbacMiddleware',] 

    在settings中,我们还需要写上我们自定义的字符串

    PERMISSION_URL_DICT_KEY = "permission_url_dict"

    之所以这样写,是为了方便以后修改时,只需要修改settings里的值,其他引用到的地方都会自动应用

    还有加上URL白名单

    VALID_URL = [
        "/login/",
        "/admin.*"
    ]

    由于页面上都会显示菜单,所以我们先写一个模板,其他的只有继承就好

    {% load rbac %}    {# 引用自定义标签 #}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="/static/rbac/rbac.css" />
        <title>Title</title>
    </head>
    <body>
            <div style="float: left; 20%;height: 500px;background-color: #dddddd">
                {% menu_html request %}  {# 调用自定义menu_html标签,并传入request参数 #}
            </div>
            <div style="float: left; 80%">
                {% block content %}{% endblock %}
            </div>
    
            &lt;script src=<span style="color: #800000;">"</span><span style="color: #800000;">/static/jquery-3.2.1.min.js</span><span style="color: #800000;">"</span>&gt;&lt;/script&gt;
            &lt;script src=<span style="color: #800000;">"</span><span style="color: #800000;">/static/rbac/rbac.js</span><span style="color: #800000;">"</span>&gt;&lt;/script&gt;
    

    </body>
    </html>

    layout

    在rbac下建立一个static再在里面建立rbac文件夹,在建我们的css和js文件

    .item-permission{
        padding: 3px 10px;
    }
    .item-permission a{
        display: block;
    }
    .item-permission a.active{
        color: red;
    }
    .hide{
        display: none;
    }
    rbac.css
    /**
     * Created by Administrator on 2017/11/8.
     */
     $(function () {
        $('.item-title').click(function () {
            if($(this).next().hasClass('hide')){
                $(this).next().removeClass('hide')
            }else{
                $(this).next().addClass('hide')
            }
        })
    

    });

    rbac.js

    注意根目录下一定要有static文件下,否则我们的css,JS可能不生效

    jquery文件我们可以放在根目录下的static文件夹中

    接下来我们写自定义标签的内容在rbac下建立templatetags文件下,创建rbac.py

    import re
    from django.template import Library
    from django.conf import settings
    register = Library()
    

    @register.inclusion_tag("xxxxx.html")
    def menu_html(request):
    """
    去Session中获取菜单相关信息,匹配当前URL,生成菜单
    :param request:
    :return:
    """
    menu_list
    = request.session[settings.PERMISSION_MENU_KEY]
    current_url
    = request.path_info

    menu_dict </span>=<span style="color: #000000;"> {}
    </span><span style="color: #0000ff;">for</span> item <span style="color: #0000ff;">in</span><span style="color: #000000;"> menu_list:
        </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span> item[<span style="color: #800000;">'</span><span style="color: #800000;">menu_gp_id</span><span style="color: #800000;">'</span><span style="color: #000000;">]:
            menu_dict[item[</span><span style="color: #800000;">'</span><span style="color: #800000;">id</span><span style="color: #800000;">'</span>]] =<span style="color: #000000;"> item
    
    </span><span style="color: #0000ff;">for</span> item <span style="color: #0000ff;">in</span><span style="color: #000000;"> menu_list:
        regex </span>= <span style="color: #800000;">"</span><span style="color: #800000;">^{0}$</span><span style="color: #800000;">"</span>.format(item[<span style="color: #800000;">'</span><span style="color: #800000;">url</span><span style="color: #800000;">'</span><span style="color: #000000;">])
        </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> re.match(regex,current_url):
            menu_gp_id </span>= item[<span style="color: #800000;">'</span><span style="color: #800000;">menu_gp_id</span><span style="color: #800000;">'</span><span style="color: #000000;">]
            </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> menu_gp_id:
                menu_dict[menu_gp_id][</span><span style="color: #800000;">'</span><span style="color: #800000;">active</span><span style="color: #800000;">'</span>] =<span style="color: #000000;"> True
            </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
                menu_dict[item[</span><span style="color: #800000;">'</span><span style="color: #800000;">id</span><span style="color: #800000;">'</span>]][<span style="color: #800000;">'</span><span style="color: #800000;">active</span><span style="color: #800000;">'</span>] =<span style="color: #000000;"> True
    
    result </span>=<span style="color: #000000;"> {}
    </span><span style="color: #0000ff;">for</span> item <span style="color: #0000ff;">in</span><span style="color: #000000;"> menu_dict.values():
        active </span>= item.get(<span style="color: #800000;">'</span><span style="color: #800000;">active</span><span style="color: #800000;">'</span><span style="color: #000000;">)
        menu_id </span>= item[<span style="color: #800000;">'</span><span style="color: #800000;">menu_id</span><span style="color: #800000;">'</span><span style="color: #000000;">]
        </span><span style="color: #0000ff;">if</span> menu_id <span style="color: #0000ff;">in</span><span style="color: #000000;"> result:
            result[menu_id][</span><span style="color: #800000;">'</span><span style="color: #800000;">children</span><span style="color: #800000;">'</span>].append({ <span style="color: #800000;">'</span><span style="color: #800000;">title</span><span style="color: #800000;">'</span>: item[<span style="color: #800000;">'</span><span style="color: #800000;">title</span><span style="color: #800000;">'</span>], <span style="color: #800000;">'</span><span style="color: #800000;">url</span><span style="color: #800000;">'</span>: item[<span style="color: #800000;">'</span><span style="color: #800000;">url</span><span style="color: #800000;">'</span>],<span style="color: #800000;">'</span><span style="color: #800000;">active</span><span style="color: #800000;">'</span><span style="color: #000000;">:active})
            </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> active:
                result[menu_id][</span><span style="color: #800000;">'</span><span style="color: #800000;">active</span><span style="color: #800000;">'</span>] =<span style="color: #000000;"> True
        </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
            result[menu_id] </span>=<span style="color: #000000;"> {
                </span><span style="color: #800000;">'</span><span style="color: #800000;">menu_id</span><span style="color: #800000;">'</span>:item[<span style="color: #800000;">'</span><span style="color: #800000;">menu_id</span><span style="color: #800000;">'</span><span style="color: #000000;">],
                </span><span style="color: #800000;">'</span><span style="color: #800000;">menu_title</span><span style="color: #800000;">'</span>:item[<span style="color: #800000;">'</span><span style="color: #800000;">menu_title</span><span style="color: #800000;">'</span><span style="color: #000000;">],
                </span><span style="color: #800000;">'</span><span style="color: #800000;">active</span><span style="color: #800000;">'</span><span style="color: #000000;">:active,
                </span><span style="color: #800000;">'</span><span style="color: #800000;">children</span><span style="color: #800000;">'</span><span style="color: #000000;">:[
                    { </span><span style="color: #800000;">'</span><span style="color: #800000;">title</span><span style="color: #800000;">'</span>: item[<span style="color: #800000;">'</span><span style="color: #800000;">title</span><span style="color: #800000;">'</span>], <span style="color: #800000;">'</span><span style="color: #800000;">url</span><span style="color: #800000;">'</span>: item[<span style="color: #800000;">'</span><span style="color: #800000;">url</span><span style="color: #800000;">'</span>],<span style="color: #800000;">'</span><span style="color: #800000;">active</span><span style="color: #800000;">'</span><span style="color: #000000;">:active}
                ]
            }
    
    </span><span style="color: #0000ff;">return</span> {<span style="color: #800000;">'</span><span style="color: #800000;">menu_dict</span><span style="color: #800000;">'</span>:result}</pre>
    
    rbac.py

    此自定义标签中函数的作用是去Session中获取菜单相关信息,匹配当前URL,生成菜单

     1.首先我们需要从用户的权限中拿出菜单相关的信息,并获取当前访问的URL

     menu_list = request.session[settings.PERMISSION_MENU_KEY] 

     current_url = request.path_info 

    2.从menu_list中获取用户权限里能作为菜单的权限:

        menu_dict = {}
        for item in menu_list:
            if not item['menu_gp_id']:
                menu_dict[item['id']] = item

    3.匹配当前URL,判断当前URL是否可做菜单,如果可以,则展开此菜单,如果不是菜单,则将其所属菜单展开(给菜单加状态)

    复制代码
    for item in menu_list:
        regex = "^{0}$".format(item['url'])
        if re.match(regex,current_url):
            menu_gp_id = item['menu_gp_id']
            if menu_gp_id:    #不是子菜单则给其所属子菜单加上展开状态
                menu_dict[menu_gp_id]['active'] = True
            else:   #是子菜单则给自己加上展开状态
                menu_dict[item['id']]['active'] = True
    复制代码

    4,菜单相关信息已经整理完毕,存在了menu_dict中,接下来就要创建菜单结构,将菜单数据结构化,将同属一个大菜单下的菜单键放一个大菜单下

    复制代码
    result = {}
    for item in menu_dict.values():
        active = item.get('active')
        menu_id = item['menu_id']
        if menu_id in result: #一个大菜单下有多个子菜单,则只需要将子菜单的item和url以及状态加入即可
            result[menu_id]['children'].append({ 'title': item['title'], 'url': item['url'],'active':active})
            if active:  #只要子菜单是激活状态,则大菜单应该也是激活状态
                result[menu_id]['active'] = True
        else:
            result[menu_id] = {
                'menu_id':item['menu_id'],
                'menu_title':item['menu_title'],
                'active':active,
                'children':[
                    { 'title': item['title'], 'url': item['url'],'active':active}
                ]
            }
    复制代码

    @register.inclusion_tag("xxxxx.html")作用是:可以将其所装饰的函数menu_html的返回值直接给xxxxx.html(此页面是用来生成菜单相关的html)中使用,

    当调用自定义标签menu_html时,会将经过渲染后的xxxxx.html页面以字符串的形式返回给调用的地方

    用来形成菜单

    这样以后其他页面直接继承layout.html就会有其对应的菜单,内容部分,我们还需要判断一下用户的操作权限,以显示相应操作按钮,如userinfo页面

    from django.conf.urls import url
    from django.contrib import admin
    from rbac import views
    from app01 import views as app01_views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^test/', views.test),
        url(r'^login/', app01_views.login),
        url(r'^index/', app01_views.index),
        url(r'^userinfo/$', app01_views.userinfo),
        url(r'^userinfo/add/$', app01_views.userinfo_add),
        url(r'^order/$', app01_views.order),
        url(r'^order/add/$', app01_views.order_add),
    ]
    permissionurls.py
    class BasePagePermission(object):
        #定义这个类,是为了html页面方便调用判断
        def __init__(self,code_list):
            self.code_list = code_list
    
    </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> has_add(self):
        </span><span style="color: #0000ff;">if</span> <span style="color: #800000;">"</span><span style="color: #800000;">add</span><span style="color: #800000;">"</span> <span style="color: #0000ff;">in</span><span style="color: #000000;"> self.code_list:
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> True
    
    </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> has_edit(self):
        </span><span style="color: #0000ff;">if</span> <span style="color: #800000;">'</span><span style="color: #800000;">edit</span><span style="color: #800000;">'</span> <span style="color: #0000ff;">in</span><span style="color: #000000;"> self.code_list:
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> True
    </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> has_del(self):
        </span><span style="color: #0000ff;">if</span> <span style="color: #800000;">'</span><span style="color: #800000;">del</span><span style="color: #800000;">'</span> <span style="color: #0000ff;">in</span><span style="color: #000000;"> self.code_list:
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> True
    

    def userinfo(request):
    page_permission
    = BasePagePermission(request.permission_code_list)
    data_list
    = [
    {
    'id':1,'name':'xxx1'},
    {
    'id':2,'name':'xxx2'},
    {
    'id':3,'name':'xxx3'},
    {
    'id':4,'name':'xxx4'},
    {
    'id':5,'name':'xxx5'},
    ]
    return render(request,'userinfo.html',{'data_list':data_list,'page_permission':page_permission})

    def userinfo_add(request):
    page_permission
    = BasePagePermission(request.permission_code_list)
    return render(request, 'userinfo_add.html', { 'page_permission': page_permission})

    class OrderPagePermission(BasePagePermission):
    #继承基础的,方便扩展
    def has_report(self):
    if 'report' in self.code_list:
    return True

    def order(request):
    order_permission
    = OrderPagePermission(request.permission_code_list)

    </span><span style="color: #0000ff;">return</span> render(request,<span style="color: #800000;">'</span><span style="color: #800000;">order.html</span><span style="color: #800000;">'</span>)</pre>
    
    permissionapp01views.py
    {% extends "layout.html" %}
    

    {% block content %}
    {
    % if page_permission.has_add %}
    <a href="/userinfo/add/">添加</a>
    {
    % endif %}
    <table>
    {
    % for row in data_list %}
    <tr>
    <td>{{ row.id }}</td>
    <td>{{ row.name }}</td>
    {
    % if page_permission.has_edit %}
    <td><a href="#">编辑</a></td>
    {
    % endif %}
    {
    % if page_permission.has_del %}
    <td><a href="#">删除</a></td>
    {
    % endif %}
    </tr>
    {
    % endfor %}

            </span>&lt;/table&gt;<span style="color: #000000;">
    

    {% endblock %}

    templatesuserinfo.html

    三、总结

    rbac里有什么?

    settings中有什么?

    复制代码
    #########注册rbac的app,使其生效########
    INSTALLED_APPS = [
        'rbac.apps.RbacConfig',   ###也可直接写rbac
    ]
    

    #########加入我们自定义的中间件,使其生效########
    MIDDLEWARE = [
    'rbac.middlewares.rbac.RbacMiddleware',
    ]

    #############CSS,JS,JQ############
    STATICFILES_DIRS = (
    os.path.join(BASE_DIR,
    'static'),
    )

    ##########Session中用到的变量#############
    PERMISSION_URL_DICT_KEY = "permission_url_dict"
    PERMISSION_MENU_KEY
    = "permission_menu_key"

    #####白名单############

    VALID_URL
    = [
    "/login/",
    "/admin.*"
    ]

    复制代码

    使用方法

    1.创建project

    2.复制rbac文件

    3.在settings中按上面的设置

    4.去admin中配置文件,录入权限信息

    5.在登陆逻辑中,登陆成功时,调用init_permission方法(为此要在视图函数中导入

    from rbac import models
    from rbac.service.init_permission import init_permission

    6.视图函数中用来判断是否具有code操作

    复制代码
    class BasePagePermission(object):
        #定义这个类,是为了html页面方便调用判断
        def __init__(self,code_list):
            self.code_list = code_list
    
    </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> has_add(self):
        </span><span style="color: #0000ff;">if</span> <span style="color: #800000;">"</span><span style="color: #800000;">add</span><span style="color: #800000;">"</span> <span style="color: #0000ff;">in</span><span style="color: #000000;"> self.code_list:
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> True
    
    </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> has_edit(self):
        </span><span style="color: #0000ff;">if</span> <span style="color: #800000;">'</span><span style="color: #800000;">edit</span><span style="color: #800000;">'</span> <span style="color: #0000ff;">in</span><span style="color: #000000;"> self.code_list:
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> True
    </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> has_del(self):
        </span><span style="color: #0000ff;">if</span> <span style="color: #800000;">'</span><span style="color: #800000;">del</span><span style="color: #800000;">'</span> <span style="color: #0000ff;">in</span><span style="color: #000000;"> self.code_list:
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> True
    

    def userinfo(request):
    page_permission
    = BasePagePermission(request.permission_code_list)
    data_list
    = [
    {
    'id':1,'name':'xxx1'},
    {
    'id':2,'name':'xxx2'},
    {
    'id':3,'name':'xxx3'},
    {
    'id':4,'name':'xxx4'},
    {
    'id':5,'name':'xxx5'},
    ]
    return render(request,'userinfo.html',{'data_list':data_list,'page_permission':page_permission})

    def userinfo_add(request):
    page_permission
    = BasePagePermission(request.permission_code_list)
    return render(request, 'userinfo_add.html', { 'page_permission': page_permission})

    class OrderPagePermission(BasePagePermission):
    #继承基础的,方便扩展
    def has_report(self):
    if 'report' in self.code_list:
    return True

    def order(request):
    order_permission
    = OrderPagePermission(request.permission_code_list)

    </span><span style="color: #0000ff;">return</span> render(request,<span style="color: #800000;">'</span><span style="color: #800000;">order.html</span><span style="color: #800000;">'</span>)</pre>
    
    复制代码

    前端页面只需要

    {% if page_permission.has_add %}
        <a href="/userinfo/add/">添加</a>
    {% endif %}



    7. 模板中:
    {%load rbac %}  加载自定义标签

    <link rel="stylesheet" href="/static/rbac/rbac.css" />  引用rbac中的CSS



    {% menu_html  request %}      调用自定义menu_html标签,并传入request参数

    <script src="/static/jquery-3.2.1.min.js"></script>
    <script src="/static/rbac/rbac.js"></script>  引用rbac中的JS



  • 相关阅读:
    binary and out mode to open a file
    ADV7482&TP2825开发之总结
    C++ 操作符重载
    OpenCV学习(一)基础篇
    Linux设备驱动程序 第三版 读书笔记(一)
    My First Linux Module
    Bitmap每个像素值由指定的掩码决定
    C++ File Binary
    Bitmap RGB24 4字节对齐
    查看binlog的简单方法!
  • 原文地址:https://www.cnblogs.com/wq-mr-almost/p/10347127.html
Copyright © 2011-2022 走看看