rbac組件權限按鈕,菜單,可拔插


 

1、通用模板

 overflow: auto;       //在a和b模板中進行切換

a 模板 :左側菜單跟隨滾動條
 b模板  左側以及上不動 ****
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>


    <style type="text/css">
        .header {
            width: 100%;
            height: 60px;
            background-color: #369;
        }

        .right {
            float: right;
        }

        .left {
            float: left;
        }

        .menu {
            position: absolute;
            top: 60px;
            left: 0;
            bottom: 0;
            background-color: gainsboro;
            width: 20%;
        }

        .content {
            position: absolute;
            top: 60px;
            right: 0;
            bottom: 0;
            background-color: mediumpurple;
            width: 80%;

            overflow: auto;       //在a和b模板中進行切換
        }

    </style>
</head>
<body>


<div class="header"></div>

<div class="container">
    <div class="menu left">
        1111
    </div>

    <div class="content right">222
        {% block content %}

        {% endblock %}
    </div>

</div>

</body>
</html>
View Code

 

2、模板繼承

users.html / roles.html 繼承自 base.html

users.html

 
{% extends 'base.html' %}

{% block con %}
<h4>用戶列表</h4>
    {% for user in user_list %}
    <p>{{ user }}</p>
    {% endfor %}
    
{% endblock con%}
 

 

 2、權限按鈕控制:簡單控制

用戶權限不同,按鈕顯示就不同!

登錄成功后,就已經注冊了session
request.session['permission_list'] = permission_list

permission_list = request.session.get('permission_list')

    簡單控制:
        {% if "users/add" in permissions_list%} 

這樣完全足夠滿足開發的需求,並且沒有BUG,但是這樣做並不嚴謹,需要更改數據表結構。

 3、修改表結構

不想讓 if "/users/add/" 寫死,會有 "/roles/add/" 情況,不健壯!怎么辦?      不應該根據表名,去判斷!! 
權限不同,按鈕顯示就不同 如何做呢?    
上面問題的解決辦法:
  為了擴展,
  # 把兩條線 合成一個線
  /users/..
   /roles/...

1、admin顯示字段

注意:list_display = []

2、添加action,group字段

注意點:
加了一個權限組表,
將每張表的增刪改查,划到一個組里面!
無論多復雜的,最終一定是對數據庫的(增刪改查)

修改表結構,重新處理中間件,登錄頁面:
目的:全是為了按鈕的粒度,同一個模板,同一個視圖,
顯示不同的數據,權限

 

新的數據表:

models.py

from django.db import models

# Create your models here.

class User(models.Model):
    name=models.CharField(max_length=32)
    pwd=models.CharField(max_length=32)
    roles=models.ManyToManyField(to="Role")
    def __str__(self):
        return self.name

class Role(models.Model):
    title=models.CharField(max_length=32)
    permissions=models.ManyToManyField(to="Permission")

    def __str__(self):
        return self.title

class Permission(models.Model):
    title=models.CharField(max_length=32)
    url=models.CharField(max_length=32)

    action=models.CharField(max_length=32,default="")
    group=models.ForeignKey("PermissionGroup",default=1,on_delete=models.CASCADE)
    def __str__(self):
        return self.title

class PermissionGroup(models.Model):
    title=models.CharField(max_length=32)

    def __str__(self):
        return self.title
View Code

 

 

4、重構數據結構

1、登錄驗證

 

2、構建permission_dict

3.登錄之后,重寫 initial_session(user,request)
就是:
# 在session中注冊權限列表 用戶權限
# request.session['permission_list'] = permission_list

不應該是list 而是dict

# 在session中注冊權限字典
request.session['permission_dict'] = permission_dict

 注意點:

permission = user.roles.all().values('permission__url', 'permission__group_id', 'permission__action').distinct()

對數據的處理,以組為鍵

print(permissions)  #把下列結構構建成一個permission_dict
            '''
            permissions=[
            {'permissions__url': '/users/', 'permissions__group_id': 1, 'permissions__action': 'list'}, 

            {'permissions__url': '/users/add/', 'permissions__group_id': 1, 'permissions__action': 'add'},

            {'permissions__url': '/roles/', 'permissions__group_id': 2, 'permissions__action': 'list'}, 

            {'permissions__url': '/users/delete/(\\d+)', 'permissions__group_id': 1, 'permissions__action': 'delete'},

            {'permissions__url': 'users/edit/(\\d+)', 'permissions__group_id': 1, 'permissions__action': 'edit'}
            ]

            '''
View Code
{1: {'urls': ['/users/', '/users/add/', '/users/delete/(\\d+)/', '/users/edit/(\\d+)/'], 
     'actions': ['list', 'add', 'delete', 'edit']}, 
 2: {'urls': ['/roles/'], 
     'actions': ['list']}}

 

def initial_session(user,request):
    #方案一
    # permissions = user.roles.all().values("permissions__url").distinct()
    # print(permissions)
    # permission_list = []
    # for item in permissions:
    #     print("items",item)
    #     permission_list.append(item["permissions__url"])
    # print(permission_list)
    # request.session["permission_list"] = permission_list

    #方案二
    permissions = user.roles.all().values("permissions__url","permissions__group_id","permissions__action").distinct()
    print(permissions)
    permission_dict = {}
    temp = []
    for item in permissions:
        gid = item.get('permissions__group_id')
        if not gid in permission_dict:
            permission_dict[gid] = {
                "urls": [item["permissions__url"], ],
                "actions": [item["permissions__action"], ]
            }
        else:
            permission_dict[gid]["urls"].append(item["permissions__url"])
            permission_dict[gid]["actions"].append(item["permissions__action"])
    print(permission_dict)
    request.session["permission_dict"]=permission_dict

    #注冊菜單權限
    permissions = user.roles.all().values("permissions__url", "permissions__group__title", "permissions__action").distinct()
    menu_permission_list=[]
    for item in permissions:
        if item["permissions__action"] == "list":
            menu_permission_list.append((item["permissions__url"],item["permissions__group__title"]))

    # print("permission",men_permission_list)
    #注冊到session中
    request.session["menu_permission_list"]=menu_permission_list

5、限制權限粒度

1、中間件校驗權限:

    # 注意:妙 !!
request.actions = item["actions"]

    

  

rbac.py方案二

import re
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import  HttpResponse,redirect

class ValidPermission(MiddlewareMixin):

    def process_request(self,request):

        # 當前訪問路徑
        current_path = request.path_info

        # 檢查是否屬於白名單
        valid_url_list=["/login/","/reg/","/admin/.*"]

        for valid_url in valid_url_list:
            ret=re.match(valid_url,current_path)
            if ret:
                return None


        # 校驗是否登錄
        user_id=request.session.get("user_id")

        if not user_id:
            return redirect("/login/")

        #校驗權限2
        permission_dict=request.session.get("permission_dict",[])#加個列表防止空不可循環導致保存
        for item in permission_dict.values():
            urls=item['urls']
            for reg in urls:
                reg="^%s$"%reg
                ret = re.match(reg,current_path)
                if ret:
                    print("actions",item["actions"])
                    request.actions = item["actions"]
                    return  None

        return HttpResponse("沒有訪問權限!")
     #在中間件校驗權限的過程中,匹配到哪兒成功了,把匹配到那里對應的actions取出來,放到request.actions中.

模板層,權限按鈕控制

2用類來實現

from django.shortcuts import render, HttpResponse

# Create your views here.

from rbac.models import *
from rbac.service.perssions import *


class Per(object):
    def __init__(self, actions):
        self.actions = actions
    def add(self):
        return "add" in self.actions
    def delete(self):
        return "delete" in self.actions
    def edit(self):
        return "edit" in self.actions
    def list(self):
        return "list" in self.actions


def users(request):
    user_list = User.objects.all()
    permission_list = request.session.get("permission_list")

    # 查詢當前登錄人的名字
    id = request.session.get("user_id")
    user = User.objects.filter(id=id).first()
    print(user)

    per = Per(request.actions)

    return render(request, "users.html", locals())


def add_user(request):
    return HttpResponse('add user')


def delete_user(request, id):
    return HttpResponse('delete_user')


def edit_user(request, id):
    return HttpResponse('edit_user')


def roles(request):
    role_list = Role.objects.all()

    per = Per(request.actions)
    print(request.actions)
    return render(request, "roles.html", locals())


def login(request):
    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")

        user = User.objects.filter(name=user, pwd=pwd).first()
        if user:
            ############## 在session中注冊用戶
            request.session['user_id'] = user.pk

            ############# 在session中注冊權限list
            initial_session(request, user)

            return HttpResponse("登錄成功")

    return render(request, 'login.html', locals())
View

 

 

3、效果

不同的用戶,具有不同的權限,權限不同,顯示的按鈕就不同

 

 

 6、權限不同,菜單顯示不同

只有查看,有必要放到菜單欄!
即:action == list 放到 菜單欄中

1.用戶登錄后,在initial_session中,注冊菜單權限

  注意:permission__group__title 還可以這樣用,跨了3張表!!

 2、menu

 

可以實現,菜單顯示!但是不行,為什么?

因為模板繼承,只繼承樣式,不繼承數據!所有需要用到 自定義標簽(inclusion_tag)

 

 3、自定義標簽(inclusion_tag)

 

my_tags.py

# Author:Jesi
# Time : 2018/9/17 13:44
from django import template
register=template.Library()

@register.inclusion_tag("rbac/menu.html")
def get_menu(request,):
    menu_permission_list=request.session["menu_permission_list"]
    return {"menu_permission_list":menu_permission_list}

+

 

 

7、可拔插配置:包...建在哪個App

    屬於權限的就建在rbac的APP里,因為rpac最后是可插拔的組件!!

users.html / roles.html / base.html / menu.html
是和權限相關的,所以應該放在 rbac/templates/... 方便以后copy走!!

djangod的render去渲染 .html 時,先到項目的 templates 下找,找不到,再到App下 templates 下找,
最后找不到,才報錯!!

  

 

 如果多個App的templates 下的.html重名怎么辦? django 會根據注冊的順序顯示!
解決辦法:
項目/rbac/templates/rbac/xxx.html

這時調用:
return render(request, 'rbac/users.html', locals())

注意:
templates 或者 templatetag 注意多個app下面 的文件名 有可能都會重名!!
辦法:就是 eg:/rbac/templates/rbac/xxx.html 或者不起重名

注意:
如果 base.html 在項目下有,在App下有,先找項目下的,找不到才找App
全局可以覆蓋局部的!!

 

 

 

臨時補充問題(與rbac無關):

 

路徑自動添加

知識點:路徑自動添加問題:
http://127.0.0.1:8010/users
http://127.0.0.1:8010/users/

瀏覽器發請求:
django 發現之后,發了一個重定向的 url 加了一個 /
所有才能匹配上:
path('users/', views.users),

如何讓django不給瀏覽器發重定向,不加 /
配置:
APPEND_SLASH = False

APPEND_SLASH = True # 默認為 True

ajax 也是,django會默認的加 / 發重定向

1、django瀏覽器重定向

 

 2、APPEND_SLASH = False

  ajax 也是,django會默認的加 / 發重定向

 

 

 

 


免責聲明!

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



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