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天准備練習中

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM