权限 RBAC
一丶RBAC
# 五张表
# 角色表
# 权限表
# 用户表
# 权限与角色表 (权限组表)
# 角色与用户表 (用户组表)
2.为什么要有权限?
给不同的用户分配上不同的权限(不同功能)
3.开发上一个权限的组件,为什么要开发的组件?
4.在web开发中,什么是权限?
url代表的是权限
5.表结构的设计
id url
1 /user_list/
2 /customer_list/
用户表
id username pwd
1 root 123
2 alex 123
用户和权限的关系表
id user_id permission_id
1 1 1
2 1 2
登陆后保存权限信息
查询
permissions = user_obj.roles.filter(permissions__url__isnull=False).values('permissions__url').distinct()
去空 去重
权限的控制是如何实现的?
url代表的是权限
表结构的设计
5张表 3个model
权限表
url 权限 url地址正则表达式的字符串 /login/
title 标题
角色表
name 角色的名称
permissions 多对多 管理权限
用户表
username 用户名
password 密码
roles 多对多 管理角色
角色和权限的关系表
用户和角色的关系表
流程:
1.登陆
中间件
-
白名单
-
登陆状态的校验
-
免认证地址的校验
-
权限的校验
-
从session中获取权限的信息
-
正则匹配
-
匹配成功直接return
-
-
-
拒绝请求
登陆的视图
-
验证用户名和密码
-
验证成功 获取到用户对象
-
根据用户对象查询到权限的信息
-
orm values __跨表 去空 去重 queryset
-
-
保存权限信息和登陆状态到session中
-
json的序列化
-
转成列表
-
-
回复重定向 去 index
今日安排
1.动态生成一级菜单
2.动态生成二级菜单
销售功能 —— 一级菜单
-
客户列表 —— 二级菜单
-
跟进记录
班主任功能
-
班级管理
客户管理
-
客户列表
财务管理
-
缴费列表
3.git
git 版本控制
git init 初始化仓库
git add .
git commit -m '描述 备注'
git config --global user.name
git config --global user.email
git status 查看状态
git push origin master
git remote add origin https://gitee.com/maple-shaw/day75.git
git clone https://gitee.com/maple-shaw/day75.git
git pull origin master
git reset --hard 版本号 版本回退
git log 查看版本
git reflog 查看历史记录
分支
master
git branch 查看分支
git branch 分支 创建分支
git branch -d 分支 删除分支
git checkout 分支 切换分支
git merge dev 将dev分支上的代码合并当当前分支
合并分支时会出现冲突 出现冲突手动修改
个人开发的流程
创建代码仓库
有两个分支 master dev
在dev分支上 开发了一个功能 提交一个commit
dev分支上的代码合并到master
修改BUG的流程:
从master分支上新建debug分支
在debug分支修改bug 提交版本
切换回master 合并debug上分支
删除debug分支
公司和家配合开发
公司的电脑上创建仓库 写代码 提交版本
推送代码到远程仓库
回家在家里的电脑 克隆仓库
开发新功能 提交 推送到远程仓库
上班在公司
从远程仓库 拉取代码
-
-
如何实现权限控制?
web应用中 url 代表的权限
表结构
简单的权限控制
-
url 权限 url的地址 正则表达式 ^$
-
title 标题 分权限看功能
角色表
name 角色名称
permissions 多对多 管理权限
用户表
username 用户
password 密码
roles 多对多 关联角色
角色和权限的关系表
用户和角色的关系表
动态生成一级菜单
权限表
-
url 权限 url的地址 正则表达式 ^$
-
title 标题 分权限看功能
-
is_menu 是否是菜单
-
icon 图标
动态生成二级菜单
菜单表
-
title 一级菜单的标题
-
icon 图标
权限表
-
url 权限 url的地址 正则表达式 ^$
-
title 标题 分权限看功能
-
menu 外键 关联菜单表 可为空 menu_id 有menu_id 当前的权限是二级菜单 没有menu_id 普通权限
对一级菜单进行排序
菜单表
-
title 一级菜单的标题
-
icon 图标
-
weight 权重 权重大在前面
非菜单权限归属
权限表
-
url 权限 url的地址 正则表达式 ^$
-
title 标题 分权限看功能
-
menu 外键 关联菜单表 可为空 menu_id 有menu_id 当前的权限是二级菜单 没有menu_id 普通权限
-
parent 外键 自关联 可为空 parent_id 有parent_id 当前的权限是子权限 没有parent_id 父权限
-
-
流程 + 技术点
-
中间件
-
方法 process_request
-
request.current_menu_id = None
-
request.breadcrumb_list = [ { url :'indedx' 'title':'首页' } ]
-
白名单
-
re
-
settings
-
-
登陆状态的校验
-
免认证的校验
-
权限的校验
-
从session中获取权限的字典
-
循环做校验
-
re
-
匹配成功
id pid
判断是否有pid
- 没有pid
当前访问的是二级菜单
request.current_menu_id= id request.breadcrumb_list.append({url title })
- 有pid
当前访问的是子权限
通过pid找到父权限的信息 p_permission = permissions[str(pid)]
request.current_menu_id =pid
request.breadcrumb_list.append({ url :p_permission['url'],'title': })
request.breadcrumb_list.append({ url,title })
-
-
-
所有的都匹配不成功 拒绝请求
-
-
登陆的视图
-
验证用户名和密码 校验成功 获取用户对象
-
初始化权限(菜单)信息
-
通过用户对象查询权限
-
permissions= user_obj.roles.filter(permission__url__isnull=False).values().distinct()
-
跨表 去空 去重
-
-
构建数据结构
简单的权限控制
权限的列表 list(permissions) [ {'permissions__url':'xxxxx'} ]
动态生成一级菜单
权限的列表 [ {'url':'xxxxx'} ]
菜单的列表 [ {'title' , 'url' 'icon '} ]
动态生成二级菜单
权限的列表 [ {'url':'xxxxx'} ]
菜单的字典
{
一级菜单的id:{
title 一级菜单的标题
icon 图标
children: 【
{ url title } 二级菜单的信息
】
}
}
对一级菜单进行排序
权限的列表 [ {'url':'xxxxx'} ]
菜单的字典
{
一级菜单的id:{
title 一级菜单的标题
icon 图标
weight 权限
children: 【
{ url title } 二级菜单的信息
】
}
}
非菜单权限的归属
权限的列表 [ {'url':'xxxxx' id pid } ]
菜单的字典
{
一级菜单的id:{
title 一级菜单的标题
icon 图标
weight 权限
children: 【
{ url title id } 二级菜单的信息
】
}
}
路径导航
权限的字典 { id : {'url':'xxxxx' id title pid } }
菜单的字典
{
一级菜单的id:{
title 一级菜单的标题
icon 图标
weight 权限
children: 【
{ url title id } 二级菜单的信息
】
}
}
-
保存权限菜单信息到session中
-
重定向到index
-
-
模板
自定义的方法 inclusion_tag
menu (需要模板 menu.html css js)
有序字典
二级菜单的判断
breadcrumb
-
-
-
表结构(4个model 6张表)
菜单表
-
title 标题
-
icon 图标
-
weight 权重
权限表
-
url 权限 url正则表达式 没有^$
-
title 标题 显示名字
-
name url的别名 (权限控制到按钮级别)
-
menu 外键 关联菜单表 (有menu_id 当前的权限是二级菜单,没有menu_id 是普通权限)
-
parent 外键 自关联 (非菜单权限的归属)
is_menu
icon
角色表
-
name 名称
-
permissions 多对多 关联权限表
用户表
-
username
-
password
-
roles 多对多 关联角色表
角色和权限的关系表
用户和角色的关系表
流程和技术点
-
中间件
-
获取当前访问的url地址
-
request.current_menu_id = None
-
request.breadcrumb_list = [ { url :'index' title:'首页' } ]
-
白名单
-
登陆状态的校验
-
免认证的校验
-
权限的校验
-
从session中获取权限的字典
-
循环权限的字典
-
正则匹配
-
匹配成功
-
id pid pname
-
没有pid 当前访问的是二级菜单 父权限
-
request.current_menu_id =id
-
request.breadcrumb_list .append({ url title }) 当前权限的信息
-
-
有pid 当前访问的是子权限
-
request.current_menu_id =pid
-
获取父权限的信息 permissions[pname]
-
request.breadcrumb_list .append({ url title }) 父权限的信息
-
request.breadcrumb_list .append({ url title }) 当前权限的信息
-
-
return
-
-
-
-
拒绝请求
-
-
登陆的视图
-
校验用户
-
根据用户查询权限相关信息
-
orm 跨表 values 去空 去重
-
-
构建权限和菜单的数据结构
权限 permission_dict = { name : { url id pid title pname } }
菜单 menu_dict = {
一级菜单的id : {
title icon weight
children: [
{ url title id }
]
}
}
-
保存数据到session中
-
重定向index
-
-
模板
-
母板和继承
-
动态生成二级菜单
-
inclusion_tag
-
有序字典
-
sorted
-
循环二级菜单
-
比较 当前二级菜单的id request.current_menu_id
-
比较成功 给一级菜单的 class=‘hidden’ 移除掉 给当前的二级菜单加上class=‘active’
-
-
模板中两次for循环
-
-
路径导航
-
inclusion_tag
-
循环 request.breadcrumb_list
-
-
权限控制到按钮级别
-
filer - has_permission
-
-
name in request.session['permission'] 返回true
-
-
-
1.批量操作
新增权限 路由系统中有 数据库中没有 路由系统name的集合 - 数据库name的集合
待更新的权限 路由系统中有 数据库中也有 路由系统name的集合 & 数据库name的集合
删除的权限 路由系统没有 数据库中有 数据库name的集合 - 路由系统name的集合
2.分配权限
3.权限组件的应用
-
拷贝rbac的app 到项目中并且注册
INSTALLED_APPS = [
...
'rbac.apps.RbacConfig',
] -
数据库的迁移
-
修改用户
class User(models.Model):
# username = models.CharField('用户名', max_length=32)
# password = models.CharField('密码', max_length=32)
roles = models.ManyToManyField(Role, verbose_name='用户所拥有的角色', blank=True)
def __str__(self):
return self.username
class Meta:
abstract = True # 基类 不会在数据库中生成表 让别的表继承继承
from rbac.models import User
class UserProfile(User):
-
执行迁移
-
先删除rbac 下migrations中除了
__init__.py
之外的py文件 -
执行命令
-
python manage.py makemigrations
-
python manage.py migrate
-
-
-
-
路由配置
urlpatterns = [
...
url(r'^rbac/', include('rbac.urls', namespace='rbac')),
] -
录入权限信息
角色管理 http://127.0.0.1:8000/rbac/role/list/
菜单管理 http://127.0.0.1:8000/rbac/menu/list/
批量添加权限 http://127.0.0.1:8000/rbac/multi/permissions/
菜单分配二级菜单 以及子权限
-
分配权限
确定用户 如果使用不是rbac的User 需要修改rbac/views.py中的User为当前使用的用户表
给角色分配权限
给用户分配角色
-
应用权限
加中间件
MIDDLEWARE = [
....
'rbac.middlewares.rbac.RbacMiddleWare'
]在settings中配置权限的相关配置
# rbac 白名单
WHITE_LIST = [
r'^/crm/login/$',
r'^/crm/reg/$',
r'^/admin/'
]
# 免认证的地址
PASS_AUTH_LIST = [
r'^/index/$'
]
# 权限的session的key
PERMISSION_SESSION_KEY = 'permission'
# 菜单的session的key
MENU_SESSION_KEY = 'menus' -
修改登录的视图
登录成功后初始化权限信息
from rbac.service.init_permission import init_permission
# 登录后初始化
init_permission(obj,request)
-
动态生成二级菜单
在模板中修改:
{% load rbac %}
{% menu request %}导入css js
<link rel="stylesheet" href="{% static 'rbac/css/menu.css' %} "/>
<script src="{% static 'rbac/js/menu.js' %} "></script> -
路径导航
{% breadcrumb request %}
10 .权限控制到按钮级别
{% if request|has_permission:'crm:consult_record_add' %}
<a href="{% url 'crm:consult_record_add' %}" class="btn btn-primary btn-sm">新增</a>
{% endif %}
crm 客户关系管理系统
功能:
-
登陆注册
-
-
客户信息管理
公户和私户 防止抢单
公户 所有人都能查看 没有绑定销售
私户 只有他的销售能看 绑定销售
-
跟进记录的管理
-
报名表的管理
-
缴费记录管理
-
-
班主任
-
班级的管理
-
课程记录的管理
-
学习记录的管理
-
展示信息:
-
普通字典
对象.字段名
-
choices
对象.字段名 数据库的结果
对象.get_字段名_display()
-
外键
对象.外键.name
__str__
-
自定义方法
model中定义方法
新增和编辑
设计两个url地址 + 一个视图(modelform ) + 一个模板
删除
crm的表:
用户 部门 校区 客户 跟进记录 报名 缴费 班级表 课程记录 学习记录表
权限 : 菜单 权限 角色 用户 角色和权限 用户和角色
权限的控制:
-
url 代表权限
-
表结构的设计
-
流程
-
登陆成功后获取用户的权限 保存到session中
获取权限
user_obj.roles.filter('permission__url__isnull=False).values('permission__url').distinct()
-
中间件实现权限的校验
-
白名单的校验
-
登陆状态的校验
-
免认证地址的校验
-
权限的校验
-
拒绝请求
-
-
表结构
# 实现简单的权限控制
class Permission(models.Model):
url = models.CharField(max_length=200, verbose_name='权限')
title = models.CharField(max_length=32, verbose_name='标题')
class Role(models.Model):
name = models.CharField(max_length=32, verbose_name='角色名称')
permission = models.ManyToManyField(Permission, verbose_name='角色所拥有的权限')
class User(models.Model):
name = models.CharField(max_length=32, verbose_name='用户名')
password = models.CharField(max_length=32, verbose_name='密码')
roles = models.ManyToManyField(Role, verbose_name='用户所拥有的角色')
permission_lit = [ { 'permission__url':'xxxx' } ]
# 一级菜单
class Permission(models.Model):
url = models.CharField(max_length=200, verbose_name='权限')
title = models.CharField(max_length=32, verbose_name='标题')
is_menu = models.BooleanField(default=False)
icon = models.CharField(max_length=100, verbose_name='图标')
class Role(models.Model):
name = models.CharField(max_length=32, verbose_name='角色名称')
permission = models.ManyToManyField(Permission, verbose_name='角色所拥有的权限')
class User(models.Model):
name = models.CharField(max_length=32, verbose_name='用户名')
password = models.CharField(max_length=32, verbose_name='密码')
roles = models.ManyToManyField(Role, verbose_name='用户所拥有的角色')
permission_lit = [ { 'url':'xxxx' } ]
menu_lit = [ { 'url':'xxxx' ,title: ,icon } ]
# 二级菜单
class Menu(models.Model):
title = models.CharField(max_length=32, verbose_name='菜单名')
icon = models.CharField(max_length=100, verbose_name='图标')
class Permission(models.Model):
url = models.CharField(max_length=200, verbose_name='权限')
title = models.CharField(max_length=32,