创建权限表
基于角色的权限管理,一个员工可以有多个角色,每个角色的访问权限以url的方式存储。
建表
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')
role = models.ForeignKey(Role, verbose_name='角色', related_name='users')
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)
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)
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')
action = models.ForeignKey(Action, verbose_name='操作', related_name='permissions')
role = models.ForeignKey(Role, verbose_name='角色', related_name='p2as')
class Meta:
unique_together = (
('permission', 'action', 'role'),
)
def __str__(self):
return "%s-%s-%s" % (self.permission, self.action, self.role,)
models查询权限
def permit(request):
"""
权限管理,获取权限,并存放在session中
:param request:
:return:
"""
from django.db.models import Count
user_obj = models.User.objects.filter(username="zouruncheng").first()
print(user_obj)
# 获取 user2role信息
x = models.User2Role.objects.filter(user_id=user_obj.id)
# 通过users关联到User2Role表,通过user__关联到user表。获取当前用户的角色
role_obj = models.Role.objects.filter(users__user__username="zouruncheng").all()
print(role_obj)
# 一个用户可能有多个角色,查询出的数据可能重复。annotate分组问题?
# permission_list = models.Permission2Action2Role.objects.filter(role__in=role_obj).
# values("permission__url","action__code").annotate(c=Count("id"))
# 使用distinct时效率较低,不会增加额外的列
permission_list = models.Permission2Action2Role.objects.filter(role__in=role_obj).
values("permission__url","action__code").distinct()
print(permission_list)
# 构造权限条件
permission_dict = {}
for item in permission_list:
if item["permission__url"] in permission_dict:
permission_dict[item["permission__url"]].append(item["action__code"])
else:
permission_dict[item["permission__url"]]=[item["action__code"]]
print(permission_dict)
# {'/order.html': ['post', 'get', 'edit', 'del'], '/users.html': ['post', 'get', 'edit', 'del']}
request.session["permission_dict"] = permission_dict
return HttpResponse("模拟登录成功")
模拟权限访问
1.建立一个关于权限访问的中间件
MIDDLEWARE = [
'middleware.permission.PermissionMiddle',
]
2.中间件
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class PermissionMiddle(MiddlewareMixin):
"""
权限过滤,中间件
"""
def process_request(self,request,*args,**kwargs):
# 只有授权才能访问的url
invalid_url = ["/permit/order.html"]
if request.path_info in invalid_url:
action = request.GET.get("md") # GET传参---?md=get
permission_dic = request.session.get("permission_dict")
# {
# '/order.html': ['post', 'get', 'edit', 'del'],
# '/users.html': ['post', 'get', 'edit', 'del']
# }
if not permission_dic:
return HttpResponse("无权限(未登录)")
action_list = permission_dic.get(request.path_info)
if not action_list:
return HttpResponse("无权限2")
if action not in action_list:
return HttpResponse("无权限3")
生成权限菜单
# ==========================day90===============================================
# 根据表结构,生成权限菜单
def menu(request):
all_menu_list = models.Menu.objects.values("id", "caption", "parent_id")
# print(all_menu_list)
# user = models.User.objects.filter(rusername="zouruncheng")
role_list = models.Role.objects.filter(users__user__username="zouruncheng").all()
permission_list = models.Permission2Action2Role.objects.filter(role__in=role_list).
values("permission__id", "permission__url", "permission__caption", "permission__menu__id").distinct()
# print(permission_list)
# print(permission_list.count())
# 将权限挂靠到菜单上
all_menu_dict = {}
for row in all_menu_list:
row["child"] = []
row["status"] = False # 是否显示该权限
row["opened"] = False # 菜单是否展开
all_menu_dict[row["id"]]=row
for per in permission_list:
if not per["permission__menu__id"]:
continue
item = {
"id":per["permission__id"],
"caption":per["permission__caption"],
"url":per["permission__url"],
"parent_id":per["permission__menu__id"],
"status":True,
"opened":False
}
# if re.match("permission__url",request.path_info):
if re.match(item["url"], "/permit/users.html"):
item["opened"]=True
pid = item["parent_id"]
all_menu_dict[pid]["child"].append(item)
# 将当前权限的父级status=True
temp = pid
while not all_menu_dict[temp]["status"]:
all_menu_dict[temp]["status"]=True
temp = all_menu_dict[temp]["parent_id"]
if not temp:
break
# 将当前权限的父级opened = True
if item["opened"]:
temp1 = pid
while not all_menu_dict[temp1]["opened"]:
all_menu_dict[temp1]["opened"] = True
temp1 = all_menu_dict[temp1]["parent_id"]
if not temp1:
break
# print(all_menu_dict)
# print(all_menu_list)
# 构造菜单和菜单之间的等级关系
result=[]
for row in all_menu_list:
if row["parent_id"]:
all_menu_dict[row["parent_id"]]["child"].append(row)
else:
result.append(row)
# print(result)
# for row in result:
# print("----",row["caption"],row["status"],row["opened"])
"""
---- 用户管理 True
---- 订单管理 True
---- 博客管理 False
"""
'''
结构化处理结果
result= [
{'id':1, 'caption':'菜单1', parent_id:None,status:True,opened:True,child:[
{'url':'/order.html','caption': '订单管理','id': 1,'opened': True, 'status': True},
{'id':4, 'caption':'菜单1-1', parent_id:1,status:False,opened:False,child:[]},]},
{'id':2, 'caption':'菜单2', parent_id:None,status:True,opened:False,child:[]},
{'id':3, 'caption':'菜单3', parent_id:None,status:False,opened:False,child:[]},
]
'''
def menu_tree(menu_list):
tpl1 = """
<div class='menu-item'>
<div class='menu-header'>{0}</div>
<div class='menu-body {2}'>{1}</div>
</div>
"""
tpl2 = """
<a href='{0}' class='{1}'>{2}</a>
"""
menu_str = ""
for menu in menu_list:
if not menu['status']:
continue
# menu: 菜单,权限(url)
if menu.get('url'):
# 权限
menu_str += tpl2.format(menu['url'],'active' if menu['opened'] else "",menu['caption'])
else:
# 菜单
if menu['child']:
child_html = menu_tree(menu['child'])
else:
child_html = ""
menu_str += tpl1.format(menu['caption'], child_html,"" if menu['opened'] else 'hide')
return menu_str
menu_html = menu_tree(result)
print(menu_html)
return render(request,"ShowMenu.html",{"menu_html":menu_html})
前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>权限显示菜单</title>
<style>
.hide {
display: none;
}
.menu-body {
margin-left: 20px;
}
.menu-body a {
display: block;
}
.menu-body a.active {
color: red;
}
</style>
</head>
<body>
{{ menu_html|safe }}
</body>
<script src="/static/plugin/jquery-3.2.1.js"></script>
<script>
$(function () {
$('.menu-header').click(function () {
$(this).next().removeClass('hide').parent().siblings().find('.menu-body').addClass('hide');
})
})
</script>
</html>