1、url权限管理

设计表

1、设计表
系统一共有多少个路径;
有哪些用户使用;
用户在公司的角色;
对角色进行权限分配(什么样的角色可以访问什么样的路径);
2、往表中添加数据,分配角色权限
3、登录成功,设置session,并将该用户可以访问的url从表中取出保存在session中,
4、设置中间件rocess_request,

设置白名单放行登录和admin:

以admin开头的所有路径都放行

# 设置白名单放行
for i in ["/login/","/register/","/logout/","/code/","/admin/.*"]:
# 请求的路径能够和i匹配
# 匹配不到返回None
print(request.path)
ret = re.search(i,request.path)
if ret:
print(ret)
return None

登录认证:

# 登录认证,判断当前用户是否携带session来访问
if not request.user.username:
return redirect("login")

权限认证:

session中的路径是用户可以访问的路径,

request.path是当前访问路径,与session中的路径进行匹配,search成功return None

中间件继续往下执行,search不到ret为None,如果当前访问的路径都不在这个列表中证明该用户没有访问这个路径的权限,返回对应的错误(权限不够,无法访问)

# 权限认证
for item in request.session["permisson_list"]:
res = "^%s$"%item
ret = re.search(res,request.path)
if ret:
return None
return HttpResponse("您的权限不够不能访问该页面!!!")

2、左侧菜单栏权限分配

动态显示左侧一级菜单栏

权限表模型

# 权限表
class Permission(models.Model):
title = models.CharField(max_length=32)
url = models.CharField(max_length=128)
is_menu = models.BooleanField(default=False, verbose_name='是否是菜单')
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

admin显示:

展示的时候直接可以编辑:

from django.contrib import admin

# Register your models here.
from app01 import models
# 定义显示字段
class PermissonAdmin(admin.ModelAdmin):
list_display = ['pk','title','url','is_menu','icon']
# 展示时直接就可以编辑的字段
list_editable = ['is_menu','icon','url']
# 排序
ordering = ['pk',] class RoleAdmin(admin.ModelAdmin):
list_display = ['pk','title']
ordering = ['pk',] # 注册表
admin.site.register(models.Customer)
admin.site.register(models.Campuses)
admin.site.register(models.ClassList)
admin.site.register(models.UserInfo)
admin.site.register(models.ConsultRecord)
admin.site.register(models.Role,RoleAdmin)
admin.site.register(models.Permission,PermissonAdmin)

admin文件中配置

显示表的名字:

# 权限表
class Permission(models.Model):
title = models.CharField(max_length=32)
url = models.CharField(max_length=128)
is_menu = models.BooleanField(default=False, verbose_name='是否是菜单')
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

model中的verbose_name_plural

具体流程:

1、获取登录用户拥有的所有权限,用户菜单栏数据(用户权限的url中有哪些是菜单栏);
2、将菜单栏的数据注入到session中;
3、不管是公有客户还是私有客户菜单栏都是通过继承的模板,所以我们只需要在模板中动态生成菜单栏即可,哪些用户有哪些菜单栏;
4、为了加强代码的复用性,我们使用自定义标签来生成左侧菜单栏,,并给标签添加选中样式;
5、自定义标签把我们事先保存在session中的菜单栏数据取出来渲染到指定页面,这里我们用的inclusion_tag("result.html");
6、在后端给选中的标签添加样式,用request.path与我们取出的菜单栏数据的url进行匹配,匹配成功表示这个url就是我们点击的标签,对应的给它添加"class":"active";

用户菜单栏数据注入:

# 判断用户输入的用户名和密码与数据库中的是否匹配
user_obj = auth.authenticate(username=username, password=password)
if user_obj and str_code.upper()==code.upper():
# 登录成功设置session
auth.login(request, user_obj)
# 获取该用户的所有权限并保存在session中,并去重
permissions = models.Permission.objects.filter(role__userinfo__username=user_obj.username).distinct()
# 将该用户可以访问的所有url和菜单栏数据都添加到session中
permisson_list = []
permisson_is_menu_list = []
for item in permissions:
# 用户权限
permisson_list.append(item.url)
     # 如果路径是否是菜单栏
if item.is_menu:
# 用户菜单栏数据(用户权限的url中有哪些是菜单栏)
permisson_is_menu_list.append({
"title": item.title,
"url": item.url,
"icon":item.icon,
})
request.session["permisson_list"] = permisson_list
request.session["permisson_is_menu_list"] = permisson_is_menu_list
print("permisson_list-->",permisson_list)
print("permisson_is_menu_list-->",permisson_is_menu_list)
# permisson_list--> ['/home/', '/customers/']
# permisson_is_menu_list--> [{'title': '首页', 'url': '/home/', 'icon': 'fa fa-link'}, {'title': '公共客户信息', 'url': '/customers/', 'icon': 'fa fa-link'}]

自定义标签:

from django import template
register = template.Library()
import re
@register.inclusion_tag("result.html")
def create_label(request):
menu_list = request.session.get("permisson_is_menu_list")
# 给点击的标签添加选中样式
for item in menu_list:
# 请求路径与当前用户的菜单栏数据中的url匹配成功说明这个路径就是当前用户点击的a标签发起的请求
if re.match("^{}$".format(item["url"]),request.path):
# match 匹配开头的,匹配失败返回None,匹配成功可通过group(0)返回匹配成功的字符串
# setch 扫描整个字符串,匹配不到返回None
item["class"]="active"
break
# 将菜单栏的数据交给result页面去渲染,选然后将结果当作组件返回给调用create_label的页面
return {"menu_list":menu_list}

inclusion_tag指定的result页面:

{% for foo in menu_list %}
<li class="{{ foo.class }}" ><a href="{{ foo.url }}" ><i class="{{ foo.icon }}"></i>
<span>{{ foo.title }}</span></a></li>
{% endfor %}

模板中引入自定义标签:

<ul class="sidebar-menu" data-widget="tree">
<li class="header">HEADER</li>
<!-- Optionally, you can add icons to the links --> {% load mytag %} <!--引用自定义标签-->
{% create_label request %} <!--调用自定义标签,并将request传过去--> </ul>

3、二级菜单

二级菜单和一级菜单不同的是:

1、设计表结构添加数据

一级菜单与权限表一对多关联,权限表设置自关联

# 菜单栏
class Menu(models.Model):
title = models.CharField(max_length=32,verbose_name='一级菜单',null=True,blank=True)
icon = models.CharField(max_length=32, verbose_name='图标', null=True, blank=True) # 权限表
class Permission(models.Model):
title = models.CharField(max_length=32)
url = models.CharField(max_length=128)
menu = models.ForeignKey("Menu",null=True)
pid = models.ForeignKey("self",null=True) # 自关联
class Meta:
verbose_name_plural="权限表"
verbose_name = '权限表'
def __str__(self):
return self.title

2、登陆成功后获取当前登录用户的所有权限,将用户所有可以访问的url和菜单栏数据保存在session中

# 获取该用户的所有权限并保存在session中,并去重
permissions = models.Permission.objects.filter(role__userinfo__username=user_obj.username).values("title","url","pk","pid","menu__title","menu__icon","menu_id").distinct()
# 将该用户可以访问的所有url和菜单栏数据都添加到session中
input_permission(request, permissions)
def input_permission(request, permissions):
# 将该用户可以访问的所有url和菜单栏数据都添加到session中
permisson_list = []
permisson_is_menu_dict = {}
for item in permissions:
# 用户权限
permisson_list.append({
"pk":item["pk"],
"url":item["url"],
"pid":item["pid"],
})
# 判断是否是一级菜单
if item["menu_id"]:
# menu_id同属于一个 一级菜单(下一个a标签的menu_id也是当前的一级标签)
if item["menu_id"] in permisson_is_menu_dict:
permisson_is_menu_dict[item["menu_id"]]["children"].append({
"pk":item["pk"],"title": item["title"], "url": item["url"]
})
else:
# 设计菜单栏数据结构(方便前端渲染)
permisson_is_menu_dict[item["menu_id"]] = {
"title": item["menu__title"],
"icon": item["menu__icon"],
"children": [
{ "pk":item["pk"],"title": item["title"], "url": item["url"]},
]
} request.session["permisson_list"] = permisson_list
request.session["permisson_is_menu_dict"] = permisson_is_menu_dict

中间件取提取权限列表进行验证,并将当前访问路径的pid封装在request中

import re
from django.shortcuts import HttpResponse,redirect,render
from django.utils.deprecation import MiddlewareMixin class PermissonMiddleware(MiddlewareMixin):
def process_request(self,request):
# 设置白名单放行
for i in ["/login/","/register/","/logout/","/code/","/admin/.*"]:
# 请求的路径能够和i匹配
# 匹配不到返回None
ret = re.search(i,request.path)
if ret:
return None
# 登录认证,判断当前用户是否携带session来访问
if not request.user.username:
return redirect("login") # 权限认证
for item in request.session["permisson_list"]:
res = "^%s$"%item["url"]
ret = re.search(res,request.path)
if ret:
# 当前访问路径的pid 给request对象动态添加了个属性
request.show_id = item["pid"]
return None
return HttpResponse("您的权限不够不能访问该页面!!!")

3、菜单栏的数据我们通过自定义标签来渲染

根据我们构建的数据格式在前端进行渲染

    '': {
'title': '信息管理',
'icon': 'fa fa-link',
'children': [{
'pk': 5,
'title': '首页',
'url': '/home/'
}, {
'pk': 6,
'title': '公共客户信息',
'url': '/customers/'
}, {
'pk': 7,
'title': '我的客户',
'url': '/my_customers/'
}]
},

自定义标签

from django import template
register = template.Library() @register.inclusion_tag("result.html")
def create_label(request):
menu_dict = request.session.get("permisson_is_menu_dict")
for key, item in menu_dict.items():
# 默认给二级标签添加隐藏样式
item["class"] = "hide"
for child in item["children"]:
# if re.match("^{}$".format(child["url"]), request.path):
# 当前访问路径的pid如果等于它二级菜单的id证明他俩是属于同一个一级菜单,
# 如果是属于同一个一级菜单,我们就让这个二级菜单一直显示,并给它添加选中样式;
if request.show_id == child["pk"]:
item["class"] = ""
child["class"] = "active"
break
return {"menu_dict" :menu_dict }

我们通过权限表自关联的方式来区分他们的从属关系;

bug:通过正则匹配无法确定从属关系

那么我们为什么要区分他们的从属关系呢:
默认二级标签是隐藏状态的,我们为了在点击我的客户或当前一级标签的其他二级标签时都是展开的状态,我们通过正则当前请求的路径request.path与二级菜单进行匹配,匹配成功证明当前用户请求的url在二级菜单中,我们设置它父级标签的class属性值为空,让其展开; 当我们点击我的客户中的其他功能时,因为这些功能的路径都不在二级菜单中,所以无法通过正则的方式进行匹配,也就是说我们在点击这些功能时左侧的菜单栏会隐藏起来,为了避免这种bug出现我们扩展了权限表添加了pid字段,并通过自关联的方式解决了bug

当前请求路径的pid与菜单栏id进行判断:

result.html生成二级标签

<div class="multi-menu">
{% for item in menu_dict.values %}
<div class="item">
<div class="title">
<i class="{{ item.icon }}"></i>{{ item.title }}
</div>
<div class="body {{ item.class }}">
{% for child in item.children %}
<div class="body">
<a href="{{ child.url }}" class="{{ child.class}}">{{ child.title }}</a>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>

4、按钮权限分配

用户有没有这个按钮就看看他有没有这个按钮的权限

通过过滤器判断请求的url值否在权限列表里

{% load mytag %}
{% if "/add_customers/"|haspermission:request %}
<a href="{% url "add_customers" %}" class="btn btn-primary pull-right">添加</a>
{% endif %}
@register.filter
# 分配按钮权限
def haspermission(base_url,request):
for item in request.session["permisson_list"]:
ret = "^%s$"%item["url"]
res = re.search(ret,base_url)
if res:
return True
return False

通过过滤器判断用户权限的url中有没有该按钮的url,有就说明该用户有这个按钮的权限,让其显示;反之隐藏

{% if "/edit_customers/1/"|haspermission:request or "/delete_customers/1/"|haspermission:request %}
<td>
{% if "/edit_customers/1/"|haspermission:request %}
<a href="{% url "edit_customers" customers.pk %}"
class="btn btn-primary btn-sm">编辑</a>
{% endif %}
{% if "/delete_customers/1/"|haspermission:request %}
<a href="{% url "delete_customers" customers.pk %}"
class="btn btn-danger btn-sm">删除</a>
{% endif %} </td>
{% endif %}

5、路径导航

页面效果:

点击我的客户页面中的其他功能:基于我的客户后面添加

1、首页是默认的,无论点击哪个菜单路径导航第一个都是首页;
2、点击左侧菜单路径导航显示对应的名称,
3、点击左侧菜单栏页面中对应的功能时路径导航基于菜单栏的路径继续往后添加;

实现思路:

我们只需要判断请求的路径是不是二级菜单:
如果是二级菜单取出对应的路径title和url在前端直接渲染即可;
如果不是二级菜单那么就是二级菜单的功能请求,我们取出功能请求的title和url并需要根据已知条件查出它父级菜单的title和url,在前端渲染时放在自己的前面;

代码:

每次请求都会走一遍中间件,权限认证通过之后判断是二级菜单还是二级菜单中的功能请求;

# -*- coding: utf-8 -*-
# @Time : 2019/6/14 20:22
import re
from django.shortcuts import HttpResponse,redirect,render
from django.utils.deprecation import MiddlewareMixin
from app01 import models
class PermissonMiddleware(MiddlewareMixin):
def process_request(self,request):
# 设置白名单放行
for i in ["/login/","/register/","/logout/","/code/","/admin/.*"]:
# 请求的路径能够和i匹配
# 匹配不到返回None
ret = re.search(i,request.path)
if ret:
return None
# 登录认证,判断当前用户是否携带session来访问
if not request.user.username:
return redirect("login") # 路径导航
request.path_navigation = [{
"title":"首页",
"url":"/home/",
}]
# 权限认证
for item in request.session["permisson_list"]: res = "^%s$"%item["url"]
ret = re.search(res,request.path)
if ret:
# 当前访问路径的pid 给request对象动态添加了个属性
request.show_id = item["pid"] # pid=pk 就是菜单栏请求的url
if item["pk"]==item["pid"]:
request.path_navigation.append({
"title":item["title"],
"url":request.path,
})
else:
# 通过pid找到二级菜单的对象
obj = models.Permission.objects.filter(pk=item["pid"]).first()
li = [
# 父级权限
{
"title":obj.title,
"url":obj.url,
},
# 子权限
{
"title": item["title"],
"url": request.path,
}
]
# 迭代添加到path_navigation中
request.path_navigation.extend(li)
return None
return HttpResponse("您的权限不够不能访问该页面!!!")

在中间件中,权限认证通过之后

用bootstrap给最后一层添加灰色样式

<ol class="breadcrumb">
{% for foo in request.path_navigation %}
{% if forloop.last %}
<li class="active">{{ foo.title }}</li>
{% else %}
<li><a href="{{ foo.url }}">{{ foo.title }}</a></li>
{% endif %} {% endfor %} </ol>

Django-权限管理与路径导航的更多相关文章

  1. Django 权限管理(二)

    权限菜单展示 1.展示的效果 实现该效果,涉及到的核心点(突破点) 1. 权限分类: (1)菜单权限 (主要用来展示的权限(url)如查看权限 url,  如上图中的每个权限都归类为菜单权限,主要用来 ...

  2. django权限管理(一)

    权限:权限就是一个包含正则的url. Rbac 权限管理: Role-Based Access Control,基于角色的访问控制.用户通过角色与权限进行关联,一个用户可以有多个角色,一个角色可以有多 ...

  3. 【Python】django权限管理

    参考:http://www.cnblogs.com/esperyong/ 参考:https://docs.djangoproject.com/en/1.8/topics/auth/default/#t ...

  4. 一.8.django权限管理/drf权限管理

    1.什么是权限管理: .权限管理,一般指根据系统设置的安全规则或者安全策略,用户可以访问而且只能访问自己被授权的资源 .权限管理好比如钥匙,有了钥匙就能把门打开,但是权限设置是有级别之分的,假如这个系 ...

  5. SpringSecurity实现权限管理和页面导航栏动态实现

    用户模块. 3 1.1  需求:获取用户名. 3 1.1.1     分析. 3 1.1.2     服务端获取用户信息. 4 1.1.3     页面获取用户信息. 5 1.2  给用户分配角色. ...

  6. Django 权限管理

    对于Django而言,虽然自带了一些基本的通用权限限制,但现实中,可能我们更希望自己去定义业务权限划分 Django对于权限这块的部分验证方法 user = request.user user.is_ ...

  7. Django权限管理测试

    测试内容:当我单击登录页面登录的时候页面会弹出当前用户的个人信息 当我点击提交的时候可以看到我当前用户的所有权限: 测试成功,接下来看一下后台的简单代码: class User(models.Mode ...

  8. django权限管理

    当我们为应用创建一个Models, 在同步到数据库里,django默认给了三个权限 ,就是 add, change, delete权限. 首先,我们创建一个perm_test的project, 然后再 ...

  9. Django之权限管理

    Django权限管理之初步完整版 项目背景:这是一个权限管理系统(给一些角色和他们的权限指URL和页面可以删除的按钮比如:增删改查) 使用到了中间件,和初始化权限,使用了admin的后台管理系统. 我 ...

随机推荐

  1. Azure下安装Redis

    注意:这里需要注意Redis的区域,需要跟服务器在同一区域,否则Redis访问会很慢 Azure 中国区目前不支持在Portal管理界面创建 Redis,只能通过PowerShell创建,请参考以下步 ...

  2. C# WebForm 屏蔽输入框的验证

    按钮做界面跳转时,屏蔽输入框的验证可添加属性:  CausesValidation="FALSE" <form runat="server"> &l ...

  3. uni-app中picker组件的一个坑

    这里直接贴出代码 <view class="goods-info-add fl-sw"> <view>运费模板:</view> <view ...

  4. sonarqube执行命令遇上的小问题

    在安装好sonarqube,本地或是服务器上都是可疑正常运行的情况下. 这一次我重新上传,修改配置SonarQube.Analysis.xml,sonar.host.url的值已经改为服务器上的,执行 ...

  5. js模糊查询案例

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. 说说css hack,说真的,我也是才去了解这个东西

    之前在很多地方看到css hack,今天狠下心,看看到底是什么鬼,所有我去百度了,然后看了一篇文章,然后写个小总结. css hack就是通过加一些特定的符号,不同的浏览器可以识别特定符号的样式,以此 ...

  7. mybatis+Oracle 批量插入数据,有数据做更新操作

    <!-- 批量添加 -->     <insert id="batchAdd" parameterType="java.util.List"& ...

  8. RabbitMQ的持久化

      RabbitMQ的持久化主要体现在三个方面,即交换机持久化,队列持久化及消息持久化 注意,因公司使用php-amqplib来实现RabbitMQ,故之后举例说明的代码均使用的php-amqplib ...

  9. 去掉行尾的^M

    1. 处理掉行尾的^M 在windos下进行linux内核驱动编写,调试成功后需要集成到内核代码中去,所以会通过虚拟机共享文件夹拷贝到内核对应目录,这时候看源码文件还是没有异常的. 当对该文件进行回车 ...

  10. idou老师教你学istio2:监控能力介绍

    我们知道每个pod内都会有一个Envoy容器,其具备对流入和流出pod的流量进行管理,认证,控制的能力.Mixer则主要负责访问控制和遥测信息收集. 如拓扑图所示,当某个服务被请求时,首先会请求ist ...