Django實現Rbac許可權管理
阿新 • • 發佈:2018-11-26
許可權管理
許可權管理是根據不同的使用者有相應的許可權功能,通常用到的許可權管理理念Rbac.
Rbac
基於角色的許可權訪問控制(Role-Based Access Control)作為傳統訪問控制(自主訪問,強制訪問)的有前景的代替受到廣泛的關注。在RBAC中,許可權與角色相關聯,使用者通過成為適當角色的成員而得到這些角色的許可權。這就極大地簡化了許可權的管理。在一個組織中,角色是為了完成各種工作而創造,使用者則依據它的責任和資格來被指派相應的角色,使用者可以很容易地從一個角色被指派到另一個角色。角色可依新的需求和系統的合併而賦予新的許可權,而許可權也可根據需要而從某角色中回收。角色與角色的關係可以建立起來以囊括更廣泛的客觀情況。
資料庫表體現
在後端資料庫rbac的表現是,一張使用者表,一張職位表,還有一張許可權表,使用者多對多職位表,因為同一個人可能擁有多個職位,職位表多對多許可權許可權表,一個職位可擁有多個許可權,許可權在web的體現就是url地址,你必須有相對url的許可權才能訪問頁面,從而限制你的功能
簡單rbac表例子:
可以看出對於關於使用者的增刪改查功能的許可權就是你能訪問對應的url。例如boss職位我可以給他分配所有的許可權,在職位許可權表中可以看出boss擁有所有的許可權。
如何實現
現在你可以給一個使用者指定職位以及職位的許可權,那麼django中如何實現許可權管理。首先你的知道django的運作流程,看下面的圖:
用過django框架的很容易看懂這張圖,簡單來說流程如下:
- wsgiref模組負責接受和傳送底層的socket訊息
- 中介軟體為全域性鉤子對django的輸入和輸出進行操作
- 路由系統根據url執行相應的檢視函式
- 檢視函式呼叫資料庫和模板語言渲染html檔案返回給前段
所以我們可以自己寫一箇中間件來實現許可權管理
實現原理分析
登入後要做的事:
- 登入成功後從資料庫中獲取當前使用者的所有許可權,也就是所有的url地址
- 利用session的特點將登入使用者的所有url地址以鍵值對的形式儲存
寫一箇中間件實現以下功能:
- 除了訪問白名單中的url,都必須校驗許可權
- 根據請求的session判斷當前使用者的許可權即獲取能訪問得url,沒有登入則獲取不到
- 校驗通過則執行執行django下一步流程
- 校驗不通過則返回沒有許可權提示,或返回登入頁面
具體實現
資料庫
from django.db import models
# Create your models here.
class Permission(models.Model):
title = models.CharField(max_length=22)
url = models.CharField(max_length=32)
def __str__(self):
return self.title
class Meta:
verbose_name ='許可權'
verbose_name_plural=verbose_name
class UserInfo(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
roles = models.ManyToManyField(to='Role')
class Meta:
verbose_name ='使用者'
verbose_name_plural=verbose_name
def __str__(self):
return self.username
class Role(models.Model):
title = models.CharField(max_length=32)
permissions =models.ManyToManyField(to='Permission',null=True,blank=True)
class Meta:
verbose_name ='角色'
verbose_name_plural=verbose_name
def __str__(self):
return self.title
登入檢視
from django.shortcuts import render,HttpResponse,redirect
from django.http import JsonResponse
# Create your views here.
from rbac.models import UserInfo,Permission,Role
def login(request):
ret = {'ret':0}
#獲取因許可權不足跳轉到登入頁面的原url,獲取不到預設/customer/list/
next_url = request.GET.get('next','/customer/list/')
if request.method=='POST':
#post請求,獲取前端傳送的賬號和密碼
name = request.POST.get('email')
pwd = request.POST.get('pwd')
#根據獲取到的賬號密碼去資料庫篩選
user_obj = UserInfo.objects.filter(username=name,password=pwd).first()
if user_obj:
ret={'ret':1}
ret['url']=next_url
# 如果篩選成功則跨邊將使用者所有的許可權url取出來
permission_queryset = user_obj.roles.all().filter(permissions__isnull=False).values_list('permissions__url')
#利用生成器儲存url
permission_list = [i[0] for i in permission_queryset]
#設定到session中
request.session['permission_list'] = permission_list
else:
ret['msg']='賬號密碼錯誤'
return JsonResponse(ret)
#如果是get請求直接返回頁面
return render(request,'login.html')
def logout(request):
request.session.flush()
return redirect('login')
中介軟體
class RBACMiddleware(MiddlewareMixin):
def process_request(self, request):
#白名單url
wirte_url = [reverse('login'),reverse('logout')]
#獲取當前的url
current_url = request.path_info
print('當前url',current_url)
#如果當前請求的url是白名單的url直接放行:
for url in wirte_url:
if re.match(r'^{}$'.format(url),current_url):
print('白名單通過')
return
#否則判斷當前請求url是否在當前登入的使用者的許可權url中
#獲取session中儲存的使用者許可權url表
permission_list = request.session.get('permission_list',[])
for url in permission_list:
if re.match(r'^{}$'.format(url),current_url):
print(permission_list)
print('許可權通過')
return
else:
return HttpResponse('沒有許可權')