Django_RBAC_demo2 升級版權限控制組件

RBAC 升級版

 預期要求

  前端在無權限時不在提供操做標籤html

  更改部分硬編碼前端

  實現更加精準的權限控制正則表達式

未改動前的版本

在這裏 ⬇數據庫

Django_rbac_demo 權限控制組件框架模型django

具體更改

數據庫結構更改:

  對 permission 表新增兩個字段 用於分類具體控制表(group)  以及當前操做行爲 (action)session

  增長新表 permissiongroup 用來保存控制表字段app

 

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="1")
    group = models.ForeignKey("PermissionGroup", default=1)

    def __str__(self):return self.title


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

    def __str__(self): return self.title

 

permission.py

    表結構更改後,後臺可利用的數據更多。傳回一個字典。框架

   以及須要 數據處理成便於操做的形式oop

"""
爲了解耦,將處理權限的代碼保存在組件裏面
"""


def initial_session(user,request):

    """
    方案1
        很差用,只用一個權限字段實在功能有限
     已被淘汰
""" # # 查看當前用戶的全部的權限 # # 由於會有values 的原理會致使有重複須要去重 # ret = user.roles.all().values("permissions__url").distinct() # permission_list = [] # # 將全部的權限保存在一個列表裏面,稍微處理下數據便於操做 # for i in ret: # permission_list.append(i["permissions__url"]) # # 把用戶的用戶權限保存在 session 裏面 # request.session["permission_list"] = permission_list """ 方案2 """ # permission__group_id permission表 的group 字段 由於外鍵會後面加個 」_id「 別忘了啊 # 取出來當前用戶的權限,每一個權限對應的屬性 permissions = user.roles.all().values( "permissions__url", "permissions__group_id", "permissions__action",).distinct() # 對拿到的數據進行數據處理 permission_dict = {} for i in permissions: gid = i["permissions__group_id"] if gid not in permission_dict: permission_dict[gid] = { "urls": [i["permissions__url"], ], "actions": [i["permissions__action"], ] } else: permission_dict[gid]["urls"].append(i["permissions__url"]) permission_dict[gid]["actions"].append(i["permissions__action"]) request.session["permission_dict"] = permission_dict

 

rbac.py 

  對傳回的數據進行權限驗證post

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

"""
寫在中間件裏面能夠徹底避免每次都要重複校驗的問題
在請求來的時候進行校驗,所以要寫在 process_request 方法裏面
"""


class ValidPermission(MiddlewareMixin):
    def process_request(self, request):
        # 當前訪問路徑
        current_path = request.path_info
        """
        檢查是否屬於白名單
            admin 的內部流程
                不容許一上來就訪問首頁,必需要跳轉到 登錄頁面
                http://127.0.0.1:8000/admin/login/?next=/admin/
                第二次跳轉到登陸頁面的請求若是沒有被定義可經過就會被攔截
                沒法只使用 admin 爲過濾選項
                不能用 in 單純的判斷,仍是要用到正則處理
                須要放過全部 admin 開頭的 url
        """
        valid_url_list = ["/login/", "/reg/", "/admin/.*"]
        for valid_url in valid_url_list:
            ret = re.match(valid_url, current_path)
            if ret:
                # 中間件 return None 表示這個中間件已經執行完畢
                return None

        """
        校驗是否登陸
            對於沒有登錄的用戶返回報錯應該是讓他去登錄
        """
        user_id = request.session.get("user_id")
        if not user_id:
            return redirect("/login/")

        # """
        # 校驗權限 1 permission_list
        #     在編輯,以及刪除頁面的時候 url 不是固定的,
        #     會有內含的參數,所以權限列表裏面不能僅僅是寫死的url
        #     也不能再單純的用 in 來判斷。仍是要靠正則來處理
        #     將權限列表裏面的權限信息用 正則表達式來保存
        #     而後對訪問頁面進行驗證是否能夠經過來處理
        # """
        # permission_list = request.session.get("permission_list",[])
        # flag = False
        # for permission in permission_list:
        #     permission = "^%s$" % permission
        #     ret = re.match(permission, current_path)
        #     if ret:
        #         flag = True
        #         break
        # if not flag:
        #     return HttpResponse("沒有訪問權限!")
        # return None

        """
        校驗權限 2 permission_dict
        """
        permission_dict = request.session.get("permission_dict")
        for i in permission_dict.values():
            urls = i["urls"]
            for reg in urls:
                reg = f"^{reg}$"
                ret = re.match(reg, current_path)
                if ret:
                    # 加一個自定義的 actions 屬性在裏面
                    request.actions = i["actions"]
                    return None
        return HttpResponse("沒有訪問權限!")

 

views.py

   封裝一個 Per 類便於前端更方便的取數據

from django.shortcuts import render,HttpResponse
import re
# Create your views here.
from rbac.models import *
from rbac.service.perssions import *

class Per(): def __init__(self,actions): self.actions = actions def add(self): return "add" in self.actions def delete(self): return "del" in self.actions def edit(self): return "edit" in self.actions def cat(self): return "cat" in self.actions def users(request):
    user_list = User.objects.all()
    # permission_dict = request.session["permission_dict"]
    # 查詢當前登錄人的名字
    id = request.session.get("user_id")
    user = User.objects.filter(id=id).first()
per
= Per(request.actions)
return render(request, "users.html",locals()) def add_user(request): permission_list = request.session["permission_list"] return HttpResponse("add user.....") def del_user(request,id): return HttpResponse(f"del_user: {id}") def roles(request): role_list = Role.objects.all()
per
= Per(request.actions)
return render(request,"roles.html",locals()) def login(request): print("login") 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: # 把用戶的id 保存在 session 裏面 request.session["user_id"] = user.pk # 查詢當前用戶的全部的權限 initial_session(user, request) return HttpResponse("登陸成功!") return render(request, "login.html",locals())

 users.html 

   前端頁面基於 per 對象的 actions 控制才判斷是否對標籤進行顯示

{% extends "base.html" %}
{% block con %}
    <h4>用戶列表</h4> {% if per.add %} <a href="/users/add/" class="btn btn-primary">添加用戶</a> {% endif %} <table class="table table-bordered table-striped">
        <thead>
        <tr>
            <th>序號</th>
            <th>姓名</th>
            <th>角色</th>
            <th>操做</th>
        </tr>
        </thead>

        <tbody>
        {% for user in user_list %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ user.name }}</td>
                <td>
                    {% for role in user.roles.all %}
                        {{ role.title }}
                    {% endfor %}
                </td>
                <td> {% if per.delete%} <a href="/users/delete/{{ user.pk }}/" class="btn btn-danger">刪除</a> {% endif %}

                    {% if per.edit %} <a href="" class="btn btn-warning">編輯</a> {% endif %} </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
{% endblock %}
相關文章
相關標籤/搜索