• rbac(基于角色权限控制)-------权限管理



    权限管理
      创建一个rbac和app的应用,这个rbac主要是用来存放权限的,全称叫做基于角色权限控制
      一、先看配置文件合适不,给创建的rbac在配置文件里面设置一下
        找到INSTALLED_APPS=【'rbac'】
      二、设计表结构
        models中创建类:五个类,七张表
        角色表:
        用户表:
        权限表:

         组表:

         菜单表:

        角色表和权限表是多对多的关系(一个角色可以有多个权限,一个权限可以对应多个角色)
        用户表和角色表是多对多的关系(一个用户可以有多个角色,一个角色有多个用户)

        所以有会多生成两张关系表

        一个菜单下面有多个组

        一个组下面有多个菜单

        一个菜单下面有多个权限

    from django.db import models
    
    # Create your models here.
    class Role(models.Model):
        '''
        角色表
        '''
        title = models.CharField(max_length=32,verbose_name="角色名")
        permissions = models.ManyToManyField(to="Permission",verbose_name="具有的所有权限", blank=True)  # 建立用户表和角色表的多对多关系
    
        def __str__(self):
            return self.title
    
        class Meta:
            verbose_name_plural = "角色表"
    
    
    class Group(models.Model):
        caption = models.CharField(max_length=32,verbose_name="组名称")
        menu = models.ForeignKey(to="Menu",verbose_name="所属菜单",default=1,related_name="menu")
    class Menu(models.Model):
        title = models.CharField(max_length=32)
    
    class Permission(models.Model):
        '''
        权限表
        '''
        title = models.CharField(max_length=32,verbose_name="标题")
        url = models.CharField(max_length=64,verbose_name="带正则的URL")
        # is_mune = models.BooleanField(verbose_name="是否是菜单",default=0)
        menu_gp = models.ForeignKey(verbose_name="组内菜单",to="Permission",blank=True,null=True)  #自关联
        #主页就可以设置为菜单,当点击菜单的时候才可以做具体的操作
        codes = models.CharField(max_length=32,verbose_name="代码",default=1)
        group = models.ForeignKey(to="Group",verbose_name="所属组",null=True)  #新添加的字段记得设置默认值
    
        def __str__(self):
            return self.title
    
        class Meta:
            '''中文显示'''
            verbose_name_plural = "权限表"
    class UserInfo(models.Model):
        '''
        用户表
        '''
        username = models.CharField(max_length=32,verbose_name="用户名")
        password = models.CharField(max_length=64,verbose_name="密码")
        email = models.CharField(max_length=32,verbose_name="邮箱")
        roles = models.ManyToManyField(to="Role",verbose_name="具有的所有角色",blank=True)  #建立用户和角色的多对多关系
    
        def __str__(self):
            return self.username
    
        class Meta:
            verbose_name_plural = "用户表"


      三、通过django admin录入权限数据
        - 先创建一个超级用户
        - 用户名 root
        - 密码 zhy123456
        - 在admin.py 中
          from rbac import models
          admin.site.register(models.Permission)
          admin.site.register(models.Role)
          admin.site.register(models.UserInfo)
          这样的话上去的是英文的,如果你想让中文显示就在类中加一个类
          class Meta:
          verbose_name_plural = "权限表"
          - 当你给关联字段录入数据的时候会有错误提示,那么在类中你的那个关联字段在加一个属性blank = True 可以为空
          permissions = models.ManyToManyField(to="Permission",verbose_name="具有的所有权限", blank=True)

      四、编写登录
        用户登录后:
          获取当前用户具有的所有角色
          获取当前用户具有的所有权限(并且去重)

          #获取当前的用户对象
          user = models.UserInfo.objects.filter(username=name,password=password).first()
          #获取当前用户的所有角色user.roles.all()
          #获取当前用户的所有权限
          permission_list = user.roles.all().values("permissions__title","permissions__url","permissions__is_mune").distinct()
          print(permission_list)

          登录成功之后初始化---把所有的url都拿出来并且保存到session里
            1、可以建一个server的包,在里面建一个初始化的init_perssion.py文件
            2、定义函数

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    from rbac import models
    from day7权限管理 import settings
    def init_permission(user,request):
        #获取当前的用户对象
        '''
        获取所有权限中的url并放在session中
        :param user:
        :param request:
        :return:
        '''
    
        #user.roles.all()获取当前用户的所有角色
        #获取当前用户的所有权限
        permission_list = user.roles.all().values(
            "permissions__id",
            "permissions__title",  #用户列表
            "permissions__url",    #url
            "permissions__menu_gp",  #组内菜单id,如果为null表示是菜单
            "permissions__codes",
            "permissions__group_id",
            "permissions__group__menu__title",  #菜单名称
            "permissions__group__menu__id"  #菜单id
        ).distinct()
    
        print("-----------------",permission_list)
        #菜单相关
        sub_permisson_list = []
        for item in permission_list:
            tpl = {
                "id":item["permissions__id"],
                "title":item["permissions__title"],
                "url":item["permissions__url"],
                "menu_group_id":item["permissions__group_id"],
                "menu_id":item["permissions__group__menu__id"],
                "menu_title":item["permissions__group__menu__title"]
            }
            sub_permisson_list.append(tpl)
        request.session[settings.PERMISSION_MENU_KEY] = sub_permisson_list
        # 1、去掉不是菜单的url
        # 菜单操作
        # menu_list = []
        # for item in permission_list:
        #     if not item["permissions__is_mune"]:  # 如果不是菜单就继续
        #         continue
        #     else:  # 否则是菜单的话就把菜单添加到列表里面
        #         tpl = {
        #             "menu_id": item["permissions__group__menu__id"],
        #             "menu_title": item["permissions__group__menu__title"],
        #             "title": item["permissions__title"],
        #             "url": item["permissions__url"],
        #             "active": False
        #         }
        #         menu_list.append(tpl)
        # request.session[settings.PERMISSION_MENU_KEY] = menu_list  #吧所有的菜单都放在session里面
        # print("xcvxvxv", menu_list)
    
    
    
        # 权限相关
        result = {}
        for item in permission_list:
            group_id = item["permissions__group_id"]
            url =item["permissions__url"]
            code = item["permissions__codes"]
            if group_id in result:
                #如果在说明url和code已经生成了
                result[group_id]["codes"].append(code)
                result[group_id]["urls"].append(url)
            else:
                #如果不在就添加进去
                result[group_id] ={
                    "codes":[code,],
                    "urls":[url]
                }
        # print(result)
        #吧所有权限中的url字典放到session中
        request.session[settings.PERMISSION_URL_DICT_KEY] = result
    
    
        # # 打印的结果如下
        # result = {
        #     1: {
        #         "codes": ["list", "add", "del", "edit"]
        #         "urls": [
        #             "/userinfo/",
        #             "/userinfo/add" ,
        #             "/userinfo/del(d+)/ ",
        #             "/userinfo/edit(d+)/ ",
        #         ]
        #     },
        #     2: {
        #         "codes": {"list", "add", "del", "edit"}
        #          "urls": [
        #             "/order",
        #             "/order/add" ,
        #             "/order/del(d+)/ ",
        #             "/order/edit(d+)/ ",
        #         ]
        #     }
        # }

       五、中间件
          - 在setting里设置白名单(不用权限就可以访问)

    #白名单
    VALID_URL = [
        "/login/",
        "/admin.*/",
        "/index/"
    ]
    
    # ==================rabc==============
    PERMISSION_URL_DICT_KEY="permissions_url_dict"
    PERMISSION_MENU_KEY = "menu_list"
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'rbac.middlewears.rbac.Middle',
    ]


          - 获取当前的url请求
          - 获取session保存的权限信息

          - 循环url进行正则匹配,如果匹配成功就有权访问,不成功就无法访问

    用中间件的时候记得要在settings里面配置一下:

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    from django.shortcuts import render,HttpResponse,redirect
    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):
            #获取当前的url请求
            current_url = request.path_info #拿到当前的路径
            # print(request.path,current_url)
            #获取Session中保存当前用户的权限,
            # request.session.get("permissions_url_list")
            # 如果当前的路径和session里面保存的url一样就break了,如果不一样就说明无权访问
            for url in settings.VALID_URL:
                # print(url,current_url)
                if re.match(url,current_url):
                    return None    #如果url是表名单白名单里面的,就让直接走后面的
    
            permission_dict = request.session.get(settings.PERMISSION_URL_DICT_KEY)
            #在初始化的时候把url以字典的显示存在了session里面,现在获取的也就是一个字典了
            # print("==========",permission_dict)
            flag = False
            for group_id,code_url in permission_dict.items():
                for url in code_url["urls"]:
                    regax = "^{0}$".format(url)
                    # print(regax,current_url)
                    if re.match(regax,current_url):
                        #match只要是..开头的都能匹配到,多以的加个^和$符
                        request.permission_code_list=code_url["codes"]
                        flag = True
                        break
                if flag:  #跳出外层循环
                    break
            if not flag:
                return HttpResponse("无权访问")
    
    
        def process_response(self,request,response):
            return response
  • 相关阅读:
    idea jsp无法加载<c:foreach>循环遍历数据
    java POI读取Excel文件
    Javaweb中请求的资源[/Servlet]不可用解决方案
    大作业第一阶段冲刺(一)
    hive中sql左外连接查询列值为null
    关于ECharts在jsp页面无法显示的问题
    echarts通过ajax实现数据加载
    读书笔记
    解决:[Err] 1064
    idea启动Tomcat报错Artifact testdemo1:war exploded: Error during artifact deployment. See server log for details.问题解决
  • 原文地址:https://www.cnblogs.com/haiyan123/p/7801224.html
Copyright © 2020-2023  润新知