• Django之权限管理


    Django权限管理之初步完整版

    项目背景:这是一个权限管理系统(给一些角色和他们的权限指URL和页面可以删除的按钮比如:增删改查)

    使用到了中间件,和初始化权限,使用了admin的后台管理系统。

    我们这个是基于角色的权限访问控制(Role-Based Access Control)做一个组件。

    首先建立一个项目工程里面有另个应用:app01与rbac,

    我们在rbac中model中建立一些数据类型代码如下:

    from django.db import models
    
    # Create your models her
    class  Menu(models.Model):#定义一个菜单组
        """菜单组"""
        title=models.CharField(max_length=32)
    class Group(models.Model):#权限组(用户组与权限组)
        """权限组"""
        caption=models.CharField(verbose_name="组名称",max_length=32)#组的名称
        menu=models.ForeignKey(verbose_name="所属菜单",to="Menu",default=1)#
    class Permission(models.Model):#权限表
        """权限表"""
        url=models.CharField(max_length=64,verbose_name="URL")#权限表的url
        title=models.CharField(max_length=64,verbose_name="标题")#权限表的名字
        menu_gp=models.ForeignKey(verbose_name="组内菜单",to="Permission",null=True,blank=True)#自关联 ,blank是在admin里可以设置为空,null是设置数据库的字段可以为空。
        code=models.CharField(verbose_name="代码",max_length=16)#定义代码
        group=models.ForeignKey(verbose_name="所属组",to="Group",null=True)#所属组
    
    
        class Meta:#在admin里面显示表明
             verbose_name_plural="权限表"
        def  __str__(self):#打印名字
            return  self.title
    
    
    class Userinfo(models.Model):#用户组
        """用户表"""
        username=models.CharField(verbose_name="名字",max_length=32)#用户的名字
        password=models.CharField(verbose_name="密码",max_length=32)#用户的password
        user_role=models.ManyToManyField(verbose_name="所有的角色",to="Role",blank=True)#和角色进行多对多关联
        class Meta:#在admin里面显示表明
            verbose_name_plural="用户表"
        def __str__(self):
            return  self.username
    class Role(models.Model):#角色名字
        """角色表"""
        title=models.CharField(verbose_name="职位",max_length=32)#角色的名字
        role_permission=models.ManyToManyField(verbose_name="权限",to="Permission",blank=True)
        class Meta:
            verbose_name_plural="角色表"
        def __str__(self):
            return  self.title
    rbac中的model

    再rbac中的admin中填入需要在生成的数据代码如下:

    from django.contrib import admin
    
    # Register your models here.
    from . import models#用djangoadmin时一定要在这里写东西
    admin.site.register(models.Permission)
    admin.site.register(models.Userinfo)
    admin.site.register(models.Role)
    View Code

    中间件的代码如下:

    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__()
    
        def __call__(self, request):
            response = None
            if hasattr(self, 'process_request'):
                response = self.process_request(request)
            if not response:
                response = self.get_response(request)
            if hasattr(self, 'process_response'):
                response = self.process_response(request, response)
            return response
    class Middle(MiddlewareMixin):
        def process_request(self,request):
            #1 .获取当前请求的URL
            # request.path_info
            #2. 获取Session中保存当前用户的权限
            # request.session.get("permission_url_list")
            current_url=request.path_info#这个是获取的当前请求的路径
            print("当前请求的路径",current_url)#获取当前的url
            for url in settings.VALID_URL:#这里设置白名单
                if re.match(url,current_url):#匹配是否在白名单这个不要格式化
                    return  None#返回None返回为空就可以经过下一个中间
            permission_dict = request.session[settings.PERMISSION_URL_DICT_KEY]#获取权限url和这个页面的某些权限
            print("有这些权限URl",permission_dict)
            if not permission_dict:
                return   redirect("/login/")#如果没有登录就直接返回登录页面
            flag = False#设置一个flag
            for group_id ,code_url in permission_dict.items():#字典循环获取值用 字典名.items()
                for db_url in code_url["urls"]:#循环取里面的url
                    regax="^{0}$".format(db_url)#对取出的url进行格式化
                    if re.match(regax,current_url):#通过匹配找出是否在这里面
                        request.permission_code_list=code_url["codes"]
                        print("这里是获取的是单个页面里面的权限",request.permission_code_list)
                        flag=True#如果匹配成功直接跳出去
                        break
                if flag:
                    break
            if not flag:#如果没有跳出说明他没有权限
                return  HttpResponse("你没有权限")
    中间的代码

    初始化权限的代码:

    from django.conf import settings
    def init__perimission(user,request):#初始化权限
        perimission_list = user.user_role.values("role_permission__id",#权限的id
                                                 "role_permission__title",#权限的名字
                                                 "role_permission__url",#权限的url
                                                 # "role_permission__is_menu",
                                                 "role_permission__code",#权限名字的代码
                                                 "role_permission__menu_gp_id",#组内菜单的id(一个组的菜单id)
                                                 "role_permission__group_id",#所属的组
                                                 "role_permission__group__menu_id",#菜单id
                                                 "role_permission__group__menu__title",#菜单的名字
                                                 ).distinct()#这里获取的是的个人的权限与明细
        print("这就是最终拿到的个人明细",perimission_list)
       # 更改菜单(这个菜单是在同一个组内的菜单不变始终存在)
        sub_perimission_list=[]#先定义一个列表
        for item in perimission_list:#首先是循环里面所有的数据
            tpl={
                "id":item["role_permission__id"],#获取id是权限的id
                "title":item["role_permission__title"],#获取的是权限的名字
                "url":item["role_permission__url"],#权限的url
                "menu_gp_id":item["role_permission__menu_gp_id"],#这是组内菜单的id
                "menu_id":item["role_permission__group__menu_id"],#这是菜单的id
                "menu_title":item["role_permission__group__menu__title"]#这是菜单的名字
            }
            sub_perimission_list.append(tpl)#加入到列表中
        request.session[settings.PERMISSION_MEN_KEY] = sub_perimission_list#复制到session
        "-----------以上是菜单的处理"
        #权限的处理
        result ={}#先定义一个字典
        for item in perimission_list:#从这个数据里循环数据
            group_id=item["role_permission__group_id"]#所属组
            code=item["role_permission__code"]#一个页面里的有哪些的权限
            url=item["role_permission__url"]#权限对应的url
            if group_id in result:
                result[group_id]["codes"].append(code)#加入权限代码
                result[group_id]["urls"].append(url)#加入权限url
            else:
                result[group_id]={
                    "codes":[code,],
                    "urls":[url,],
                }
        request.session[settings.PERMISSION_URL_DICT_KEY]=result#赋值权限
    初始化

    数据库的持久化后接着用admin的后台填一些数据:

    我们自己设置了关于网页的自定义标签:名字是rbac

    import re
    from django.template import Library
    from django.conf import settings
    register = Library()
    
    #自定义的标签
    @register.inclusion_tag("xxxx.html")#从别的地方拿到数据
    def menu_html(request):
        menu_list = request.session[settings.PERMISSION_MEN_KEY]#拿到菜单的数据
        current_url = request.path_info#当前的url
        menu_dict = {}#定义一个字典
        for item in menu_list:#先拿到所有的菜单
            if not item["menu_gp_id"]:#判断是否是菜单
                menu_dict[item["id"]]=item#如果是就把数据赋值给他
        for item in menu_list:#这个是循环所有的数据进行url的匹配  给要匹配的url匹配出要显示哪个页面
            regex="^{0}$".format(item["url"])#先把数据进行格式化
            if re.match(regex,current_url):#如果匹配到数据
                menu_gp_id=item["menu_gp_id"]#最内菜单id
                if menu_gp_id:#如果是数字就给这个数字加上“active”=True
                    menu_dict[menu_gp_id]["active"]=True
                else:
                    menu_dict[item["id"]]["active"]=True#如果不是的当前的加上“active”=True
        result={}#先定义一个字典
        for item in menu_dict.values():#这是字典的取值
            active=item.get("active")#获取它的active
            menu_id=item["menu_id"]#获取菜单值
            if menu_id in result:
                result[menu_id]["children"].append({"title":item["title"],"url":item["url"],"active":active})
                if active:
                    result[menu_id]["active"]=True#获取菜单的active用来判断是否加上hide
            else:
                result[menu_id]={
                    "menu_id":item["menu_id"],
                    "menu_title":item["menu_title"],
                    "active":active,#判断
                    "children":[
                        {
                            "titel":item["title"],
                             "url":item["url"],
                            "active":active   #这个的话是用来判断是否需要标红的
                        }
                    ]
                }
        return {'menu_dict':result}#返回用来显示字典的
    View Code

    xxxx代码:

    {% for foo,item in menu_dict.items %}
        <div class="item">
            <div class="item-title">{{ item.menu_title }}</div>
            {% if item.active %}
                <div class="item-permission">
            {% else %}
                <div class="item-permission hide">
            {% endif %}
            {% for v in item.children %}
                {% if v.active %}
                    <a href="{{ v.url }}" class="active">{{ v.titel }}</a>
                {% else %}
                    <a href="{{ v.url }}">{{ v.titel }}</a>
                {% endif %}
                </div>
            {% endfor %}
            </div>
    {% endfor %}
    View Code

    这是应用app01里调用代码:名字是layout是模板

    {% load rbac %}<!--这个是继承自定义标签的-->
    <!--这个是模板以后都从这个继承-->
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <link rel="stylesheet" href="/static/rbac/rbac.css"><!--这个是导入css样式-->
    </head>
    <body>
    
    <div class="header">
        {% block header %}
            <h1>欢迎回来</h1>
        {% endblock header %}
    </div>
    <div class="siderbar">
        {% block siderbar %}
            {% menu_html request %}<!--这个是产生菜单的样式-->
        {% endblock siderbar %}
    </div>
    <div class="content">
        {% block content %}
        {% endblock content %}
    </div>
    <script src="/static/jquery-3.2.1.min.js"></script>
    <script src="/static/rbac/rabc.js"></script><!--这个是导入js样式-->
    </body>
    </html>
    layout

    别的页面也是继承这个页面:

    {% extends 'layout.html' %}
    
    {% block content %}
        {% if page_permission.has_add %}
        <a href="/userinfo/add/">添加用户11</a>
                 {% endif %}
        <table>
            {% for user in userlist %}
                <tr>
                    <td>{{ user.id }}</td>
                    <td>{{ user.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 %}
    
        </table>
    {% endblock %}
    userinfo
     

     在判断一个权限是否属于时可以建立一个类:

    class BasePagePermission(object):#有某一个更改的权限
        def __init__(self,code_list):
            self.code_list=code_list
        def has_add(self):
            if "add" in self.code_list:
                return  True
        def has_edit(self):
            if "edit" in self.code_list:
                return  True
        def has_del(self):
            if "del" in self.code_list:
                return  True
    建立一个类

    项目app01中的view中的代码:

    import re
    from django.shortcuts import render,redirect,HttpResponse
    from rbac import models
    from rbac.server.init_permission import init__perimission
    def login(request):     #登录判断
        if request.method=="GET":
            return render(request,"login.html")
        else:
            name=request.POST.get("name")
            pwd=request.POST.get("pwd")
            user=models.Userinfo.objects.filter(username=name,password=pwd).first()
            print("用户名",user)
            if not user:
                return render(request,"login.html")
            init__perimission(user,request)#初始化权限
            return  redirect("/index/")#返回权限
    def index(request):
        return  render(request,"index.html")
    class BasePagePermission(object):#有某一个更改的权限
        def __init__(self,code_list):
            self.code_list=code_list
        def has_add(self):
            if "add" in self.code_list:
                return  True
        def has_edit(self):
            if "edit" in self.code_list:
                return  True
        def has_del(self):
            if "del" in self.code_list:
                return  True
    def  userinfo(request):
        pagepermission= BasePagePermission(request.permission_code_list)#查看有哪些表有哪些删除或者修改的权限
        data_list=[
            { "id":1,"name":"xx1" },
            { "id":2,"name":"xx1" },
            { "id":3,"name":"xx1" },
            { "id":4,"name":"xx1" },
            { "id":5,"name":"xx1" }
        ]
        return render(request,"userinfo.html",{"userlist":data_list,"page_permission":pagepermission})#返回的是数据和是不是有这些权限的布尔值
    
    def  userinfoadd(request):
        userinfo_permission = BasePagePermission(request.permission_code_list)
        return render(request,"userinfo_add.html",{"gepermissionon":userinfo_permission})
    class OrderPermission(BasePagePermission):
        def  has_order(self):
            if "order" in self.code_list:
               return  True
    def userinfodel(request,nid):
        return HttpResponse("删除人员信息")
    def userinfoedit(request,nid):
        return  HttpResponse("编辑人员信息")
    def orderinfo(request):
        order_permission = BasePagePermission(request.permission_code_list)
        return render(request,"orderinfo.html")
    def orderinfoadd(request):
        return  HttpResponse("增加订单")
    def orderinfodel(request,nid):
        return HttpResponse("删除订单")
    def orderinfoedit(request,nid):
        return  HttpResponse("编辑订单")
    app01的代码

     用到的js代码:

     $(function () {
        $('.item-title').click(function () {
            // if($(this).next().hasClass('hide')){
            //     $(this).next().removeClass('hide')
            // }else{
            //     $(this).next().addClass('hide')
            // }
            // alert(111)
            $(this).next().toggleClass('hide');
        })
    });
    点击隐藏的代码

    中间件的代码结构:

    在这次项目中我们要在settings里面配置白名单和两个全局变量。

    注:如果把组件导入到另一项目中,一定要在views中login函数中导入组件中的的models。源码放在了78天准备练习中

  • 相关阅读:
    SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder"
    Tomcat跨域
    Invalid bean definition with name 'dataSource' defined in class path resource [applicationContext.xml]
    网速测试
    程序员实用工具网站
    安装wls报(主清单位置 "/u01/app/oracle/inventory" 无效 (无法读取/写入/执行))
    pom.xml
    CUDA -- 内存分配
    最长上升子序列(LIS: Longest Increasing Subsequence)
    实例化渲染
  • 原文地址:https://www.cnblogs.com/1a2a/p/7811754.html
Copyright © 2020-2023  润新知