role base access control 基于角色的权限控制
1、Models
from django.db import models
class User(models.Model):
name = models.CharField(max_length=32)
password = models.CharField(max_length=32)
class Meta:
verbose_name_plural = '用户表'
def __str__(self):
return self.name
class Role(models.Model):
caption = models.CharField(max_length=32)
class Meta:
verbose_name_plural = '角色表'
def __str__(self):
return self.caption
class User2Role(models.Model):
u = models.ForeignKey(User, on_delete=models.CASCADE)
r = models.ForeignKey(Role, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = '用户角色表'
unique_together = [
('u', 'r'),
]
def __str__(self):
return '%s-%s'%(self.u,self.r)
class Permission(models.Model):
caption = models.CharField(max_length=32, unique=True)
url = models.CharField(max_length=128, unique=True)
menu = models.ForeignKey('Menu', on_delete=models.CASCADE, blank=True, null=True)
class Meta:
verbose_name_plural = 'url表'
unique_together = [
('caption','url'),
]
def __str__(self):
return self.caption + self.url
class Action(models.Model):
caption = models.CharField(max_length=32)
code = models.CharField(max_length=32)
class Meta:
verbose_name_plural = '动作表'
def __str__(self):
return self.caption + ":" + self.code
class Permission2Action(models.Model):
p = models.ForeignKey(Permission, on_delete=models.CASCADE)
a = models.ForeignKey(Action, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = '权限表'
unique_together = [
('p','a'),
]
def __str__(self):
return '%s-%s:%s-%s'%(self.p.caption, self.a.caption, self.p.url, self.a.code)
class Permission2Action2Role(models.Model):
p2a = models.ForeignKey(Permission2Action, on_delete=models.CASCADE)
r = models.ForeignKey(Role, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = '角色权限表'
unique_together = [
('p2a', 'r'),
]
def __str__(self):
return '%s:%s'%(self.r.caption, self.p2a)
class Menu(models.Model):
caption = models.CharField(max_length=32)
parent = models.ForeignKey('self', on_delete=models.CASCADE, blank=True,null=True)
class Meta:
verbose_name_plural = '菜单表'
def __str__(self):
return self.caption
2、权限、菜单
class MenuHelper():
def __init__(self, request, username):
self.permission2action_dict = None
self.menu_leaf_list = None
self.menu_list = None
self.__menu_str = None
self.username = username
self.current_url = request.path_info
self.request = request
self.session_data()
def session_data(self):
# 获取当前用户的所有权限
# 获取在菜单中显示的权限
# 获取所有菜单
# 放置session中
info_session_key = 'permission_info'
permission2action_dict_key = 'permission2action_dict'
menu_leaf_list_key = 'menu_leaf_list'
menu_list_key = 'menu_list'
permission_dict = self.request.session.get(info_session_key)
if permission_dict:
self.permission2action_dict = permission_dict[permission2action_dict_key]
self.menu_leaf_list = permission_dict[menu_leaf_list_key]
self.menu_list = permission_dict[menu_list_key]
else:
roles = models.Role.objects.filter(user2role__u__name=self.username).all()
# p = models.Permission2Action2Role.objects.filter(r__in=role).values('p2a')
permission2action = models.Permission2Action.objects. \
filter(permission2action2role__r__in=roles). \
distinct().values('p__url', 'a__code')
permission2action_dict = {}
for pa in permission2action:
url = pa['p__url']
code = pa['a__code']
if url in permission2action_dict:
permission2action_dict[url].append(code)
else:
permission2action_dict[url] = [code, ]
menu_leaf_list = list(models.Permission2Action.objects.filter(permission2action2role__r__in=roles). \
exclude(p__menu__isnull=True). \
distinct().values('p__id', 'p__caption', 'p__url', 'p__menu'))
menus = list(models.Menu.objects.values('id', 'caption', 'parent_id'))
self.request.session[info_session_key] = {
permission2action_dict_key: permission2action_dict,
menu_leaf_list_key: menu_leaf_list,
menu_list_key: menus,
}
self.permission2action_dict = permission2action_dict
self.menu_leaf_list = menu_leaf_list
self.menu_list = menus
def menu_data_list(self):
url_parent_id = None
m2_dict = {}
for i in self.menu_leaf_list:
item = {
'caption': i['p__caption'],
'url': i['p__url'],
'parent_id': i['p__menu'],
'child': [],
'status': True,
'open': False,
}
key = item['parent_id']
if key in m2_dict:
m2_dict[key].append(item)
else:
m2_dict[key] = [item, ]
if re.match(item['url'], self.current_url):
url_parent_id = item['parent_id']
item['open'] = True
menu_dict = {}
for menu in self.menu_list:
menu['child'] = []
menu['status'] = False
menu['open'] = False
menu_dict[menu['id']] = menu
for k, v in m2_dict.items():
menu_dict[k]['child'] = v
parent_id = k
while parent_id:
menu_dict[parent_id]['status'] = True
parent_id = menu_dict[parent_id]['parent_id']
menus = []
for k, v in menu_dict.items():
key = v['parent_id']
if key:
menu_dict[key]['child'].append(v)
else:
menus.append(v)
while url_parent_id:
menu_dict[url_parent_id]['open'] = True
url_parent_id = menu_dict[url_parent_id]['parent_id']
return menus
def menu_str(self):
if self.__menu_str: return self.__menu_str
menus = self.menu_data_list()
if menus.count:
s = ''
for m in menus:
if not m['status']: continue
s2 = self.__menu_content_str(m['child'])
if s2:
s += '<li><a href="javaScript:void(0);">%s</a>%s</li>' % (m['caption'], s2)
elif m['url']:
s += '<li><a href="%s">%s</a></li>' % (m['url'], m['caption'])
else:
s += '<li>%s</li>' % m['caption']
self.__menu_str = '<ul class="active">%s</ul>' % s if s else None
return self.__menu_str
else:
return None
def __menu_content_str(self, menus):
if menus.count:
s = ''
active = ''
for m in menus:
if not m['status']: continue
s2 = self.__menu_content_str(m['child'])
if s2:
s += '<li><a href="javaScript:void(0);">%s</a>%s</li>' % (m['caption'], s2)
elif m['url']:
s += '<li><a href="%s">%s</a></li>' % (m['url'], m['caption'])
else:
s += '<li>%s</li>' % m['caption']
if m['open']:
active = 'active'
return '<ul class="%s">%s</ul>' % (active, s) if s else None
else:
return None
def actions(self):
"""
检查当前用户是否对当前URL有权访问,并获取对当前URL有什么权限
"""
action_list = []
# 当前所有权限
# {
# '/index.html': ['GET',POST,]
# }
for k,v in self.permission2action_dict.items():
if re.match(k,self.current_url):
action_list = v # ['GET',POST,]
break
return action_list
3、权限控制装饰器
def permission(func):
def inner(request,*args,**kwargs):
user_info = request.session.get('user_info')
if not user_info:
return redirect(reverse('login'))
obj = MenuHelper(request, user_info['username'])
action_list = obj.actions()
if not action_list:
return HttpResponse('无权限访问')
kwargs['menu_string'] = obj.menu_str()
kwargs['action_list'] = action_list
return func(request,*args,**kwargs)
return inner
4、应用
<div class="menu">
{{ menu_str|safe }} # 菜单元素
</div>
def login(request):
if request.method == "GET":
return render(request,'login.html')
else:
username = request.POST.get('username')
pwd = request.POST.get('pwd')
obj = models.User.objects.filter(name=username,password=pwd).first()
if obj:
# obj.id, obj.username
# 当前用户信息放置session中
request.session['user_info'] = {'nid':obj.id,'username':obj.name}
MenuHelper(request,obj.name)
return redirect('/')
else:
return redirect('/login/')
def logout(request):
request.session.clear()
return redirect('/login/')
@permission
def index(request,*args,**kwargs):
action_list = kwargs.get('action_list')
menu_string = kwargs.get('menu_string')
if "GET" in action_list:
result = models.User.objects.all()
else:
result = []
return render(request,'index.html',{'menu_string':menu_string,'action_list':action_list})
标签:__,菜单,三十三,models,menu,self,list,RBAC,dict
From: https://www.cnblogs.com/zhlforhe/p/18014266