rbac基於角色的許可權管理開發
阿新 • • 發佈:2019-01-31
一、model模組
許可權表結構設計:
from django.db import models
class User(models.Model):
"""
使用者表
"""
username = models.CharField(verbose_name='使用者名稱', max_length=32)
password = models.CharField(verbose_name='密碼', max_length=64)
email = models.EmailField(verbose_name='郵箱')
def __str__(self):
return self.username
class Role(models.Model):
"""
角色表
"""
caption = models.CharField(verbose_name='角色', max_length=32)
def __str__(self):
return self.caption
class User2Role(models.Model):
"""
使用者角色關係表
"""
user = models.ForeignKey(User, verbose_name='使用者' , related_name='roles',on_delete='')
role = models.ForeignKey(Role, verbose_name='角色', related_name='users',on_delete='')
def __str__(self):
return '%s-%s' % (self.user.username, self.role.caption,)
class Menu(models.Model):
"""
選單表
"""
caption = models.CharField(verbose_name='選單名稱' , max_length=32)
parent = models.ForeignKey('self', verbose_name='父選單', related_name='p', null=True, blank=True,on_delete='')
def __str__(self):
prev = ""
parent = self.parent
while True:
if parent:
prev = prev + '-' + str(parent.caption)
parent = parent.parent
else:
break
return '%s-%s' % (prev, self.caption,)
class Permission(models.Model):
"""
許可權
"""
caption = models.CharField(verbose_name='許可權', max_length=32)
url = models.CharField(verbose_name='URL正則', max_length=128)
menu = models.ForeignKey(Menu, verbose_name='所屬選單', related_name='permissions',null=True,blank=True,on_delete='')
def __str__(self):
return "%s-%s" % (self.caption, self.url,)
class Action(models.Model):
"""
操作:增刪改查
"""
caption = models.CharField(verbose_name='操作標題', max_length=32)
code = models.CharField(verbose_name='方法', max_length=32)
def __str__(self):
return self.caption
class Permission2Action2Role(models.Model):
"""
許可權操作關係表
"""
permission = models.ForeignKey(Permission, verbose_name='許可權URL', related_name='actions',on_delete='')
action = models.ForeignKey(Action, verbose_name='操作', related_name='permissions',on_delete='')
role = models.ForeignKey(Role, verbose_name='角色', related_name='p2as',on_delete='')
class Meta:
unique_together = (
('permission', 'action', 'role'),
)
def __str__(self):
return "%s-%s-%s" % (self.permission, self.action, self.role,)
二、urls.py模組
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^auth-login.html$', views2.login),
url(r'^auth-index(-\d+)*.html$', views2.index),
]
三、views.py模組
from django.shortcuts import render,redirect,HttpResponse
from app02 import models
# Create your views here.
def login(request):
if request.method == 'GET':
return render(request, 'login2.html')
else:
# # 根據使用者登入資訊獲得所有許可權
# object = models.User.objects.filter(username='tom').first() # 假定根據登陸資訊獲得使用者名稱為tom
# # 根據使用者物件獲得對應的所有角色(有2種方式)
# role_list = models.User2Role.objects.filter(user_id=object.id) # 方式一:正向操作 獲得[User2Role,User2Role,User2Role]
# # 方式二:反向操作,通過users跨表到user表中的user_id欄位,獲得對應的role表的所有id,從而獲得所有role(推薦該方法)
# role_list = models.Role.objects.filter(users__user_id=object.id)
#
# # 根據角色物件,獲得所有許可權,並去重
# from django.db.models import Count
# # models.Permission2Action2Role.objects.filter(role__in=role_list).values('permission__url', 'action__code').annotate(c = Count('id'))
# # 推薦下面方式,不會生成新的欄位c
# permission_list = models.Permission2Action2Role.objects.filter(role__in=role_list).values('permission__url', 'action__code').distinct()
# # 獲得結果如下所示:
# """
# [
# {permission_url: '/index.html', action_code:'GET'},
# {permission_url: '/index.html', action_code:'POST'},
# {permission_url: '/index.html', action_code:'DEL'},
# {permission_url: '/index.html', action_code:'Edit'},
# {permission_url: '/order.html', action_code:'GET'},
# {permission_url: '/order.html', action_code:'POST'},
# {permission_url: '/order.html', action_code:'DEL'},
# {permission_url: '/order.html', action_code:'Edit'},
# ]
# """
# 再通過for迴圈將資料庫中查出的資料轉換成如下格式:
user_permission_dict = {
'/ah-index.html': ["GET","POST","DEL","Edit"],
'/order.html': ["GET","POST","DEL","Edit"],
'/auth-index(-\d+)*.html': ["GET","POST","DEL","Edit"], # 可接收通過格式 '/auth-index-3.html', '/auth-index.html'
}
# 將使用者的對應的許可權放入session中,當訪問其它連結時,可直接從session中進行校驗是否存在該許可權
request.session['user_permission_dict'] = user_permission_dict
return HttpResponse('登陸成功')
def index(request):
return HttpResponse('登陸成功,你擁有了許可權,恭喜你看見了我')
三、html模版
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="POST" action="/auth-login.html">
{% csrf_token %}
<input type="text" name="user/">
<input type="submit" value="提交/">
</form>
</body>
</html>
四、自定義中介軟體
# 新增中介軟體,控制權限
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
import re
class M1(MiddlewareMixin):
def process_request(self, request, **kwargs):
valid = ['/auth-login.html', '/index.html'] # 設定白名單,不進行校驗
if request.path_info not in valid: # /auth-index
action = request.GET.get('md') # 獲得操作指令
user_permission_dict = request.session.get['user_permission_dict'] # 獲得許可權字典
if not user_permission_dict:
return HttpResponse('無許可權')
flag = False
if request.path_info != '/favicon.ico': # 每一次請求,request.path_info會獲得兩個值,請求url和/favicon
for k, v in user_permission_dict.items():
if re.match(k, request.path_info): # 正則匹配,假定資料庫的為/index-(\d+).html,則/auth-index-3.html等格式可同樣包括
if action in v:
flag = True # 表示該使用者擁有該許可權操作,繼續往下執行
break
if not flag:
return HttpResponse('無許可權')
六、setting.py模組
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'middleware.md.M1', # 將該中介軟體註冊
]