rbac(基於角色權限控制)-------權限管理


權限管理
  建立一個rbac和app的應用,這個rbac主要是用來存放權限的,全稱叫作基於角色權限控制
  1、先看配置文件合適不,給建立的rbac在配置文件裏面設置一下
    找到INSTALLED_APPS=【'rbac'】
  2、設計表結構
    models中建立類:五個類,七張表
    角色表:
    用戶表:
    權限表:html

     組表:python

     菜單表:django

    角色表和權限表是多對多的關係(一個角色能夠有多個權限,一個權限能夠對應多個角色)
    用戶表和角色表是多對多的關係(一個用戶能夠有多個角色,一個角色有多個用戶)session

    因此有會多生成兩張關係表app

    一個菜單下面有多個組函數

    一個組下面有多個菜單post

    一個菜單下面有多個權限this

複製代碼
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 = "用戶表"
複製代碼

 


  3、經過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)

  4、編寫登陸
    用戶登陸後:
      獲取當前用戶具備的全部角色
      獲取當前用戶具備的全部權限(而且去重)url

複製代碼
      #獲取當前的用戶對象
      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裏
        一、能夠建一個server的包,在裏面建一個初始化的init_perssion.py文件
        二、定義函數spa

 

複製代碼
#!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
    # 一、去掉不是菜單的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+)/ ",
    #         ]
    #     }
    # }
複製代碼

 

 

 

   5、中間件
      - 在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
複製代碼
相關文章
相關標籤/搜索