一個網站如果沒有權限控管,就等於是沒有保安的辦公大樓,所有人都可以任意進出任何地點使用任何資料。

但我們也希望能夠製作一個可以插拔的權限控管,可以先把主要業務邏輯做好以後,再把權限控管加入,不用做太大的更動。

目前這個組件的目錄結構是長這樣子:

rbac
├─service
│      ├─middlewares.py
│      └─rbac.py
├─template
│ └─menu.html ├─tempaletags │ └─myilters.py └─models.py

我學習的是rbac(Role Based Access Control)權限控制模型,也就是依照使用者角色來區分權限。

這個方式的好處就是,不必在同一個權限上重複添加使用者,而是藉由角色來套用權限,減少儲存空間的浪費。

表結構:

from django.db import models

#用戶表
class User(models.Model):
    name = models.CharField(max_length=32)
    # password = models.CharField(max_length=32)
    roles = models.ManyToManyField("Role")

    def __str__(self):
        return self.name

#角色表
class Role(models.Model):
    title = models.CharField(max_length=32)
    permissions = models.ManyToManyField("Permission")
    def __str__(self):
        return self.title

#權限表
class Permission(models.Model):
    title = models.CharField(max_length=32)
    url = models.CharField(max_length=128)
    is_menu =models.BooleanField(default=False)
    icon = models.CharField(max_length=32)

    def __str__(self):
        return self.title

首先創建表結構,表結構包含用戶、角色、權限,還有另外兩個關係表

 User<---------多對多--------->Role

Role<---------多對多--------->Permission 

在用戶登入以後,我們將該用戶所有的權限,寫到session中的權限列表中,這樣子我們未來要判斷用戶權限,只要透過session,就可以取得該用戶的所擁有的權限。

service/rbac.py

from rbac import models


def initial_session(name,request):
    """
    功能:將當前登入人的所有權限錄入session中
    """
    # 查出當前用戶的所有權限列表,使用distnct()將所有重複項除去
    permissions = models.User.objects.filter(name=name).values("roles__permissions__url",
                                                               "roles__permissions__is_menu",
                                                               "roles__permissions__title",
                                                               "roles__permissions__icon"
                                                               ).distinct()
    permission_list = []
    permission_menu_list = []
    for item in permissions:
        #將用戶權限寫入權限列表
        permission_list.append(item["roles__permissions__url"])
        #選單權限列表
        #在寫入權限時,一併將選單權限寫入
        if item["roles__permissions__is_menu"]:
            permission_menu_list.append({
                'title':item["roles__permissions__title"],
                'icon':item["roles__permissions__icon"],
                'url':item["roles__permissions__url"]
            })
    # 將當前登錄人的權限列表寫入session中
    request.session["permission_list"] = permission_list
    # 將當前登錄人的左側選單寫入session中
    request.session["permission_menu_list"] = permission_menu_list
    print('permission_menu_list',permission_menu_list)

因為必須讓權限套用在全局,我們採用中間件的方式,這樣子就不用對每個視圖單獨做設置。

service/middleware.py中寫入以下程式碼:

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

class PermissionMiddleWare(MiddlewareMixin):
    def process_request(self,request):
        #獲取當前路徑
        current_path = request.path
        #設置白名單
        for reg in ["/admin*","/crm/login/","/crm/validimg/","/crm/logout/"]:
            if re.search(reg,current_path):
                return None
        #校驗用戶是否已登入
        user_id = request.session.get("user_id")
        if not user_id:
            return redirect("/crm/login/")

        #校驗權限
        #獲取session中寫入的用戶權限列表
        #如果用戶訪問的頁面不在權限列表中,禁止該用戶訪問    
        permission_list = request.session.get("permission_list")
        for reg in permission_list:
            reg = "^%s$" % reg
            ret = re.search(reg,current_path)
            if ret:
                return None
        return HttpResponse("無權訪問")

 未完....

01-06 09:50