一個網站如果沒有權限控管,就等於是沒有保安的辦公大樓,所有人都可以任意進出任何地點使用任何資料。
但我們也希望能夠製作一個可以插拔的權限控管,可以先把主要業務邏輯做好以後,再把權限控管加入,不用做太大的更動。
目前這個組件的目錄結構是長這樣子:
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("無權訪問")
未完....