zoukankan      html  css  js  c++  java
  • 基于角色权限管理: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
    复制代码
  • 相关阅读:
    Windows 8实例教程系列 开篇
    qt 开发发布于 windeploy.exe
    qt qoci 测试验证
    vmware vmx 版本不兼容
    qt oracle
    vc qt dll
    QOCIDriver unable to create environment
    qoci 编译完 放置位置 具体根据情况
    calling 'lastError' with incomplete return type 'QSqlError' qsqlquer
    Hbase 操作工具类
  • 原文地址:https://www.cnblogs.com/mqhpy/p/11372600.html
Copyright © 2011-2022 走看看