数据库models设计:
from django.db import models
"""
一级菜单
"""
class Menu(models.Model):
title = models.CharField(max_length=32, unique=True)
icon = models.CharField(max_length=32, verbose_name="图标", null=True, blank=True)
class Meta:
verbose_name_plural = "菜单表"
verbose_name = "菜单表"
def __str__(self):
return self.title
"""
有关联Menu表的是可以做二级展示菜单的权限
未关联Menu表的是不展示的权限
"""
class Permission(models.Model):
"""权限表"""
titlt = models.CharField(max_length=32, verbose_name="功能")
url = models.CharField(max_length=32, verbose_name="权限")
menu = models.ForeignKey(to="Menu", null=True, blank=True)
class Meta:
verbose_name_plural = "权限表"
verbose_name = "权限表"
def __str__(self):
return self.titlt
class Role(models.Model):
"""角色表"""
name = models.CharField(max_length=32, verbose_name="角色名")
permissions = models.ManyToManyField(to="Permission", verbose_name="角色所拥有的权限")
class Meta:
verbose_name_plural = "角色表"
verbose_name = "角色表"
def __str__(self):
return self.name
class User(models.Model):
"""用户表"""
name = models.CharField(max_length=32, verbose_name="用户名")
password = models.CharField(max_length=32, verbose_name="密码")
role = models.ManyToManyField(to="Role", verbose_name="用户拥有的角色")
class Meta:
verbose_name_plural = "用户表"
verbose_name = "用户表"
def __str__(self):
return self.name
URL:
url(r'^login/$', views.login),
----------------------------------------------------------------------------
url判断要执行的函数
VIew登录函数:
from django.shortcuts import render, HttpResponse, redirect, reverse
from rbac import models
from django.conf import settings
from rbac.server.init_permission import init_permission
def login(request):
if request.method == "POST":
username = request.POST.get("username")
pwd = request.POST.get("pwd")
user = models.User.objects.filter(name=username, password=pwd).first()
if not user:
error_msg = "用户名或密码错误!"
return render(request, "login.html", {"error_mag": error_msg})
# 调用封装的函数
init_permission(user, request)
return redirect(reverse("customer"))
return render(request, "login.html")
------------------------------------------------------------------------------------------------------------
用户在登录界面输入账号密码之后在login中获取并和数据库中的用户数据进行比对,
如果取到了真实的用户, 则证明用户输入的账号密码正确, 调用封装好的函数进行设置session, 返回重定向到页面
封装好的设置session的函数:
"""
获取权限的函数
封装成组件
"""
from django.conf import settings
def init_permission(user, request):
permission_list = user.role.filter(permissions__url__isnull=False).values(
"permissions__url",
"permissions__titlt",
"permissions__menu__title",
"permissions__menu__id",
"permissions__menu__icon",
).distinct()
# 存放权限信息的列表
permission_li = []
# 存放菜单信息的列表
menu_li = {}
# 单级菜单循环
for i in permission_list: # i 为字典形式
permission_li.append({"url": i["permissions__url"]})
# if i.get("permissions__is_menu"):
# menu_li.append({"url": i["permissions__url"],
# "icon": i["permissions__icon"],
# "titlt": i["permissions__titlt"],
# })
# 二级菜单循环
menu_id = i.get("permissions__menu__id")
if not menu_id:
continue
if menu_id not in menu_li:
menu_li[menu_id] = {
"title": i["permissions__menu__title"],
"icon": i["permissions__menu__icon"],
"children": [
{"title": i["permissions__titlt"], "url": i["permissions__url"]}
]
}
else:
menu_li[menu_id]["children"].append(
{"title": i["permissions__titlt", "url": i["permissions__url"]]}
)
# 将权限信息写入session
request.session[settings.PERMISSION_SESSION_KEY] = permission_li
# 将菜单信息写入session
request.session[settings.MENU_SESSION_KEY] = menu_li
---------------------------------------------------------------------------------------------------------------------
在数据库中取出需要的数据并去重,
二级菜单循环中获取menu_id是要判断Permission表是否有外键关联Menu表(即是否是二级展示的权限url)
获取session:
from django import template
register = template.Library()
from django.conf import settings
import re
"""
在此函数内获取init_permission初始化方法设置的session值
并且传递个menu.html进行渲染
"""
@register.inclusion_tag("menu.html")
def menu(request):
menu_list = request.session.get(settings.MENU_SESSION_KEY)
return {"menu_list": menu_list}
动态页面渲染:
<div class="multi-menu">
{% for i in menu_list.values %}
<div class="item">
<div class="title"> <i class="fa {{ i.icon }}"></i> {{ i.title }}</div>
<div class="body">
{% for f in i.children %}
<a href="{{ f.url }}">{{ f.title }}</a>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
中间件判断权限:
from django.utils.deprecation import MiddlewareMixin
from django.conf import settings
from django.shortcuts import render, HttpResponse, redirect, reverse
import re
class Permissionmiddleware(MiddlewareMixin):
def process_request(self, request):
# 目的 : 对权限进行校验
# 获取当前访问的URL
url = request.path_info
# 判断访问的URL是否在白名单中
for i in settings.WHITE_URL_LIST:
if re.match(i, url):
return
# 获取用户所拥有的权限
permission_list = request.session.get(settings.PERMISSION_SESSION_KEY)
# 将获取的URL和获取的权限进行一致性校验
for item in permission_list:
url_p = item["url"]
if re.match("^{}$".format(url_p), url):
return
else:
return HttpResponse("没有权限!")
--------------------------------------------------------------------------------------------------------
在web初次发送请求时, 系统会在中间件中判断所请求时用的url是否在设置的白名单中, 如果在正常向下执行, 不在则获取用户的所拥有的权限,
如果url在设置的白名单内, 执行白名单内的函数, 函数内会设置新的session, 当返回响应重定向时, 再次经过中间件, 则判断用户的权限(session和url的一致性校验)