写在前面



    世间安得双全法 不负如来不负卿



 s17day26 CRM项目

 项目概要:XX公司CRM
- 权限管理,公共组件,app *****
- 熟悉增删改查,Low ***
- 增删改查组件,公共组件,app **** 内容回顾:
. .all,values,values_list
models.xx.objects.all()
---> [obj,obj,obj,]
models.xx.objects.values('id','name')
---> [{"id":,'name':'兴普'},{"id":,'name':'兴普1'},]
models.xx.objects.values_list('id','name')
---> [(,'兴普'),(,'记不住就别来了')] . 中间件是什么?有什么作用? class Md1: def process_request(self,request):
pass class process_response(self,request,response):
return response class Md2: def process_request(self,request):
pass class process_response(self,request,response):
return response MIDDLEWARE = [ "xxxxx.xxxx.Md1",
"xxxxx.xxxx.Md2"
] . ORM创建表 FK常用操作
class A(Model):
name = models.CharField(...) class B(Model):
name = models.CharField(...)
fk = models.FK(A) a. B表中有几列
id
name
fk_id b. 跨表操作
b_list = models.B.objects.all()
for item in b_list:
item.id
item.name
item.fk_id
item.fk
item.fk.name
item.fk.id
c. 跨表操作
b_list = models.B.objects.values('id','name','fk_id','fk__name')
for item in b_list:
item['id']
item['name']
item['fk_id']
item['fk__name'] d. 跨表操作
b_list = models.B.objects.vlaues_list('id','name','fk_id','fk__name')
for item in b_list:
item[]
item[]
item[']
item[]
e. 找A名称=“吴一飞”所有B表中的数据
models.B.objects.filter(fk__name='吴一飞') M2M常用操作: class A(Model):
name = models.CharField(...) class B(Model):
name = models.CharField(...)
m = models.M2M(A) a. B表中有几列
id
name PS: 自动生成一个第三张表;m用于间接的对第三张表进行操作 b. 在B表中插入三条数据;A表中插入2条数据
models.A.objects.create(name='赵峰分')
models.A.objects.create(name='王勇')
models.A.objects.create(name='刘宏伟') models.B.objects.create(name='兴普')
models.B.objects.create(name='香姐')
models.B.objects.create(name='名扬') c. 兴普和【赵峰分,王勇,刘宏伟】创建关系 obj = models.B.objects.create(name='兴普')
obj.m.add()
obj.m.add()
obj.m.add()
obj.m.add(*[,,]) d. 查找和兴普有关系的男人?
obj = models.B.objects.create(name='兴普')
obj.m.all() [A—obj,A—obj,A—obj] . Session是什么?和Cookie有什么区别? . 正则表达式 re.match() ^ $ 示例程序:pro_crm
员工模块:
权限,根据含有正则表达式URL进行分配
操作,通过配置文件进行定制
学生模块:
问卷 今日内容: 权限:授权 s17crm
- app01
- rbac
- models.py 第一版:
. 权限表(含有正则表达式),permission id url title
/userinfo/ 用户列表
/userinfo/(\d+)/delete/ 删除用户
/userinfo/(\d+)/change/ 修改用户
/userinfo/add/ 添加用户 . 用户表,userinfo
id username password
yql
wxp
zmx
ll . 用户和权限关系表
id 用户ID 权限ID 问题:用户分配权限时,麻烦 第二版: . 权限组,group
id title
用户组
订单组 . 权限表(含有正则表达式),permission id url title code group_i1 is_menu
/userinfo/ 用户列表 list true
/userinfo/(\d+)/delete/ 删除用户 del false
/userinfo/(\d+)/change/ 修改用户 edit false
/userinfo/add/ 添加用户 add true
/order/add/ ... add true
/order/(\d+)/delete/ del false
/order/(\d+)/change/ edit false
/order/ list true . 用户表,userinfo
id username password
yql
wxp
zmx
ll . 角色表,role
id title
销售员
销售经理
市场专员
市场经理
IT
CTO
销售市场总监
CEO . 用户角色关系表
用户ID 角色ID . 角色和权限关系表
角色ID 权限ID 注意:根据用户找权限
- 用户具有的所有角色
- 再根据角色找所有权限(去重) 中午作业:
- 填充数据
- id=1的用户,
- 找具有所有角色
- 找到所有权限
- 找到所有权限(去重) 填充数据:
基于Django Admin数据填充 补充:不要相信你的眼睛 分配权限:
销售员:用户列表
孟祥杰
王勇 销售经理:用户列表,添加用户
银秋良 总监: 用户列表,添加用户,订单列表
兴普 CEO:....
刘磊 注意:Djang Admin进行添加权限或授权 权限: 自动生成菜单 . 获取数据 [
{'menu_id': , 'menu_title': '用户管理菜单', 'title': '用户列表', 'url': '/userinfo/'},
{'opened':True,'menu_id': , 'menu_title': '用户管理菜单', 'title': '订单列表', 'url': '/order/'}, {'menu_id': , 'menu_title': '权限管理菜单', 'title': 'xxx列表', 'url': '/order/add/'}
{'menu_id': , 'menu_title': '权限管理菜单', 'title': 'xx列表', 'url': '/order/add/'}
] . 根据数据创建两级菜单
用户管理菜单
用户列表!
订单列表
权限管理菜单
xxx列表
xx列表 思路:
page_menu = {
:{'menu_id':,'menu_title':'用户管理菜单','children': [{ 'title': '用户列表', 'url': '/userinfo/'},{'title': '订单列表', 'url': '/order/'} ]}
: {'menu_id':,'menu_title':'权限管理菜单','children': [{ 'title': '用户列表', 'url': '/userinfo/'},{'title': '订单列表', 'url': '/order/'} ]}
} current_url = request.path_info for item in permission_menu_list:
url = item['url']
regex = xxx.format(url)
if re.match(regex,current_url):
item['opened'] = True menu_id = item['menu_id']
opened = "active" if item.get('opened') else "" child = {'title':item['title'],'url':item['url'],'opened': opened}
if menu_id in page_menu:
page_menu[menu_id]['children'].append(child)
if opened:
page_menu[menu_id]['opened'] = opened
else:
page_menu[menu_id] = {'opened':opened, 'menu_title': item['menu_title'], 'children': [child, ]} 总结: . 表结构设计 . 录入数据 . 用户登录:
- 获取角色
- 获取权限
- 对权限去重 . 结构,权限信息
{
: {
'urls': ['/userinfo/', '/userinfo/add/', '/userinfo/(\\d+)/delete/', '/userinfo/(\\d+)/change/'],
'codes': ['list', 'add', 'del', 'edit']
},
: {
'urls': ['/order/', '/order/add/', '/order/(\\d+)/delete/', '/order/(\\d+)/change/'],
'codes': ['list', 'add', 'del', 'edit']
} }
放入session中
. 中间件
白名单
request.path_info
session获取权限,进行验证 . 自动生成菜单
- inclusion_tag
- 母版 . Django Admin 权限app中写代码:
- 中间件
- init_permission
- models
- admin
- templatetags 依赖配置文件:
XX = "permission_dict"
OO = "permission_menu_list"
RBAC_LOGIN_URL = "/login/"
URL_FORMAT = "^{0}$" VALID_URL_LIST = [
"^/login/$",
"^/admin.*",
] 使用权限管理:
. 创建cmdb project
. rbac拷贝到项目中
. 在settings.APP中将 rbac 注册
. 在settings中设置
XX = "permission_dict"
OO = "permission_menu_list"
RBAC_LOGIN_URL = "/login/"
URL_FORMAT = "^{0}$" VALID_URL_LIST = [
"^/login/$",
"^/admin.*",
]
. 开发CMDB完成 . 中间件中注册
. 利用temaplatetags和母版获取动态菜单 . 在Django Admin中操作权限信息 作业:
. 权限系统:4天
. 自己创建一个主机管理系统:
- 主机
- 主机组
- 部门
- 机房
. 使用 权限系统[10天]

武Sir - 笔记

一、内容回顾

- .all  .values  .values_list
models.xxx.objects.all() --> [obj,obj,obj,...]
models.xxx.objects.values('id','name') --> [{'id':1,'name':'alex'},{'id':2,'name':'standby'},...]
models.xxx.objects.values_list('id','name') --> [(1,'alex'),(2,'standby',....)] - 中间件是什么?有什么用?
可以拦截所有的请求和响应,进行一些处理
中间件执行时有序的,从上到下执行,如果当前中间件不允许过,那么就不会再执行后面的中间件
比如说:对用户的请求做下黑名单 process_request() 默认没有返回值,即返回None; 则继续往下执行
但是如果有返回值,则不再继续往下执行,直接返回; 每个中间件就是一个类:
class Md1:
def process_request(self,request):
pass
def process_response(self,request,response):
return response
class Md2:
def process_request(self,request):
pass
def process_response(self,request,response):
return response settings.py里配置 MIDDLEWARE = [
"XXXXXX.XXXXX.Md1",
"XXXXXX.XXXXX.Md2",
] - ORM创建表 - ForeignKey常用操作
class A(Model):
name = models.CharField(...) class B(Model):
name = models.CharField(...)
fk = models.ForeignKey(A) a. B表中有几列:
id
name
fk_id b. 跨表操作
b_list = models.B.objects.all()
for item in b_list:
item.id
item.name
item.fk
item.fk_id
item.fk.id
item.fk.name c. 跨表操作
b_list = models.B.objects.values('id','name','fk_id','fk__name')
for item in b_list:
item['id']
item['name']
item['fk_id']
item['fk__name'] d. 跨表操作
b_list = models.B.objects.vlaues_list('id','name','fk_id','fk__name')
for item in b_list:
item[0]
item[1]
item[2]
item[3] e. 找A表名称等于"alex"的所有B表中的数据 *****
models.B.objects.filter(fk__name="alex") good models.B.objects.filter(fk.name="alex") 这个是不可以,需要验证!!!!!! - M2M常用操作
class A(Model):
name = models.CharField(...) class B(Model):
name = models.CharField(...)
m = models.ManyToMany(A) a. B表中有几列?
id
name PS:ManyToMany 会自动生成第三张表,字段m用于间接的对第三张表进行操作 b. 在B表中插入3条数据,A表中插入2条数据 models.A.objects.create(name='alex1')
models.A.objects.create(name='alex2') models.B.objects.create(name='egon1')
models.B.objects.create(name='egon2')
models.B.objects.create(name='egon3') c. 让 egon1 和 [alex1,alex2] 创建关系
obj = models.B.objects.filter('name'='egon1')
obj.m.add(*[1,2]) d. 查找和egon1有关系的人
obj = models.B.objects.filter('name'='egon1')
obj.m.all() # 拿到了queryset对象集合,都是A表的对象 - Session是什么? 和cookie有什么区别?
- session依赖cookie而存在
- session是存储在服务端的键值对
- cookie是存储在客户端浏览器里的键值对 - 用户第一次来访问主页,服务端生成一个随机字符串通过cookie返回给客户端
同时服务端把这个字符串当做key存储在数据库表里(也可以存在其他地方),值可以为空 - 用户第二次发起登录请求则带上刚才的cookie和用户信息
服务端则把用户信息(比如用户名密码)用某种方式存储在刚才随机字符串对应的值里
这样就表示用户登录过了

  

二、CRM项目介绍

  - CRM简介

xxx公司的CRM项目
- 权限管理 (写成一个公共的组件/app,适用于Django项目) *****
- low的增删改查 ***
- 增删改查的组件 (写成公共组件/app) **** - 员工模块
- 权限:根据 含有正则表达式的url 进行分配的
- 操作:通过配置文件进行定制
- 学生模块
- 问卷

  - RBAC简介

RBAC(Role-Based Access Control,基于角色的权限控制)
就是用户通过角色与权限进行关联。 简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。
这样,就构造成“用户-角色-权限”的授权模型。 在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系。

  

三、表结构设计

- 第一版
- permission权限表(含有正则表达式的url)
id url title
1 /userinfo/ 用户列表
2 /userinfo/(\d+)/delete/ 删除用户
3 /userinfo/(\d+)/change/ 修改用户
4 /userinfo/add/ 添加用户 - userinfo用户表
id username password
1 alex 123
2 egon 123
3 standby 123 - 用户和权限的关系表
id user_id permission_id
1 1 1
2 1 2
3 2 1
4 3 1
5 3 2
6 3 3 问题:用户分配权限时,很麻烦,不方便后面的维护 - 第二版
- permission权限表(含有正则表达式的url)
id url title
1 /userinfo/ 用户列表
2 /userinfo/(\d+)/delete/ 删除用户
3 /userinfo/(\d+)/change/ 修改用户
4 /userinfo/add/ 添加用户 - userinfo用户表
id username password
1 alex 123
2 egon 123
3 standby 123 - role 角色表
id title
1 销售员
2 销售经理
3 市场专员
4 市场经理
5 IT
6 CTO
7 CEO - 用户和角色关系表
id user_id role_id
1 1 1
2 2 1
3 2 2
4 3 1
5 3 2
6 3 7 - 角色和权限的关系表
id role_id permission_id
1 1 1
2 2 1
3 2 4
4 6 1
5 6 3
6 6 4
7 7 1
8 7 2
9 7 3
10 7 4 列出standby所具有的所有权限,可能会重复,所以需要去重;
注意:根据用户找权限
- 根据用户找角色
- 根据角色找权限 - 增加权限组表group
id title
1 用户组
2 订单组 - permission权限表 增加一个代号code字段、权限组字段以及 是否是菜单字段(涉及到在前端页面展示):
- permission权限表(含有正则表达式的url)
id url title code group_id is_menu
1 /userinfo/ 用户列表 list 1 true
2 /userinfo/(\d+)/delete/ 删除用户 del 1 false
3 /userinfo/(\d+)/change/ 修改用户 edit 1 false
4 /userinfo/add/ 添加用户 add 1 true
5 /order/ 订单列表 list 2 true
6 /order/(\d+)/delete/ 删除订单 del 2 false
7 /order/(\d+)/change/ 修改订单 edit 2 false
8 /order/add/ 添加订单 add 2 true

  

class Group(models.Model):
"""
权限组表
"""
title = models.CharField(max_length=32) class Meta:
verbose_name_plural = "权限组表"
def __str__(self):
return self.title
class Permission(models.Model):
"""
权限表
"""
title = models.CharField(verbose_name='标题',max_length=32)
url = models.CharField(verbose_name="含正则的URL",max_length=128)
code = models.CharField(verbose_name="权限代号",max_length=16)
group = models.ForeignKey(verbose_name="权限组",to="Group") # 把具体的权限分组管理,类似省市县
is_menu = models.BooleanField(verbose_name="是否是菜单") # 用来筛选出可以在左侧菜单展示的选项
class Meta:
verbose_name_plural = "权限表" def __str__(self):
return self.title class UserInfo(models.Model):
"""
用户表
"""
username = models.CharField(verbose_name="用户名",max_length=32)
password = models.CharField(verbose_name='密码',max_length=64)
roles = models.ManyToManyField(verbose_name='具有所有角色',to="Role",blank=True) class Meta:
verbose_name_plural = "用户表" def __str__(self):
return self.username class Role(models.Model):
"""
角色表
"""
title = models.CharField(verbose_name='角色名称',max_length=32)
permissions = models.ManyToManyField(verbose_name="具有所有权限",to='Permission',blank=True) class Meta:
verbose_name_plural = "角色表" def __str__(self):
return self.title

  

 

让组和菜单创建关系     页面显示的时候是不显示组的

组的存在只是为了在分配权限的时候方便一些:一个组下面的增删改查

但是菜单的信息存储在哪呢?

- 可以把菜单和组都存储在  Group表里

- 增加parent字段,让某些组属于某个菜单(ORM里就是自关联,需要related_name字段)

- 然后再增加一个is_group字段用来区分组和菜单

补充:

- 具体的权限只能在 组 下面,不能直接挂载菜单下面

class Permission(models.Model):
"""
权限表
"""
title = models.CharField(verbose_name='标题',max_length=32)
url = models.CharField(verbose_name="含正则的URL",max_length=128)
code = models.CharField(verbose_name="权限代号",max_length=16)
# group = models.ForeignKey(verbose_name="权限组",to="Group") # 把具体的权限分组管理,类似省市县
group = models.ForeignKey(verbose_name="权限组",to="Group",limit_choices_to={'is_group':True})
is_menu = models.BooleanField(verbose_name="是否是菜单") # 用来筛选出可以在左侧菜单展示的选项
class Meta:
verbose_name_plural = "权限表" def __str__(self):
return self.title

  

group = models.ForeignKey(verbose_name="权限组",to="Group")
group = models.ForeignKey(verbose_name="权限组",to="Group",limit_choices_to={'is_group':True})

就是说:只有是组的时候才能做 Permission表的外键

 最终的表结构如下:

class Group(models.Model):
"""
权限组表
"""
title = models.CharField(max_length=32)
parent = models.ForeignKey(to="Group",related_name="xxx",null=True,blank=True)
is_group = models.BooleanField(verbose_name="是否是组",default=True) class Meta:
verbose_name_plural = "权限组表"
def __str__(self):
return self.title class Permission(models.Model):
"""
权限表
"""
title = models.CharField(verbose_name='标题',max_length=32)
url = models.CharField(verbose_name="含正则的URL",max_length=128)
code = models.CharField(verbose_name="权限代号",max_length=16)
# group = models.ForeignKey(verbose_name="权限组",to="Group") # 把具体的权限分组管理,类似省市县
group = models.ForeignKey(verbose_name="权限组",to="Group",limit_choices_to={'is_group':True})
is_menu = models.BooleanField(verbose_name="是否是菜单") # 用来筛选出可以在左侧菜单展示的选项 class Meta:
verbose_name_plural = "权限表" def __str__(self):
return self.title class UserInfo(models.Model):
"""
用户表
"""
username = models.CharField(verbose_name="用户名",max_length=32)
password = models.CharField(verbose_name='密码',max_length=64)
roles = models.ManyToManyField(verbose_name='具有所有角色',to="Role",blank=True) class Meta:
verbose_name_plural = "用户表" def __str__(self):
return self.username class Role(models.Model):
"""
角色表
"""
title = models.CharField(verbose_name='角色名称',max_length=32)
permissions = models.ManyToManyField(verbose_name="具有所有权限",to='Permission',blank=True) class Meta:
verbose_name_plural = "角色表" def __str__(self):
return self.title

  

四、需求分析

# 几点注意事项

- 双下划线跨表取值
- 外键和多对多 都可以用 __(双下划线) 跨表获取对应字段
- user -> 多个角色roles -> 根据角色的permissions字段加 '__' 跨到权限表 ```
permission_list = user.roles.filter(permissions__id__isnull=False).values(
'permissions__id',
'permissions__title',
'permissions__url',
'permissions__code',
'permissions__group',
'permissions__is_menu'
).distinct()
``` - 列表distinct()去重
- [].distinct() 进行去重 - 自定义配置
- 在settings.py里定义好 (变量名一定要大写)
- 在代码里引入
Django的所有配置(既包含自定义的也包含Django内置的):
from django.conf import settings - 找到某个用户所具有的权限
- 先查找所具有的角色
- 再查找所具有的权限
- 最后把权限去重 - 自动生成权限菜单
- 获取数据
- 创建两级菜单
- 两级菜单生成
- 在视图函数中拼接好返回给前端
- @register.simple_tag()
- @register.inclusion_rag("menu_tpl.html") - 请求url验证中间件
- 要在settings.py里维护一份白名单
- 请求验证中间件依赖于session,所以自定义中间件的位置应该放在session中间件(SessionMiddleware)之后
- 对用户请求的url和该用户所具有的权限要做正则匹配:re.match(patten, current_request_url)

 

# 1/2/3 是组ID
{
1: {
'urls': ['/userinfo/', '/userinfo/add/'],
'codes': ['list', 'add']
},
2: {
'urls': ['/order/'],
'codes': ['list']
},
3: {
'urls': ['/index/'],
'codes': ['index']
}
} [
{'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/userinfo/', 'permission_title': '用户列表'},
{'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/userinfo/add/', 'permission_title': '添加用户'},
{'menu_id': 6, 'menu_title': '权限管理菜单', 'permission_url': '/permissioninfo/', 'permission_title': '权限列表'},
{'menu_id': 6, 'menu_title': '权限管理菜单', 'permission_url': '/permissioninfo/add', 'permission_title': '添加权限'}
] # 4/6 是菜单ID
# 菜单和组都在同一张表里,有父子关系,最后的目的是构造菜单和is_menu=True的权限item的两级菜单
{
4:{
'opened':False,
'menu_title':'用户管理菜单',
'children': [
{'title': '用户列表', 'url': '/userinfo/', 'opened':False},
{'title': '订单列表', 'url': '/order/', 'opened':False,}
]
},
6: {
'opened':False,
'menu_title':'权限管理菜单',
'children': [
{'title': '权限列表', 'url': '/userinfo/', 'opened':False},
{'title': '添加权限', 'url': '/order/', 'opened':False,}
]
}
}
总结:
- 表的设计(很重要)
4个类 6张表 - Django admin 录入数据 - 用户登录处理
- 获取角色
- 获取权限
- 对权限去重
- 然后把权限数据存储到session - 登录中间件
- 白名单
- request.path_info
- 从session获取权限,进行验证 - 自动生成菜单
- 跨表取出相关数据,转换字典结构
- 视图中生成好字典返回给前端
- 前端模板渲染 - simple_tag
- inclusion_rag
- 模板layout.html - 权限app包含哪些内容
- 中间件
- init_permission
- models
- admin
- templatetags 依赖配置文件 PERMISSION_DICT = "permission_dict"
URL_FORMAT = "^{0}$"
RBAC_LOGIN_URL = "/login/"
VALID_URL_LIST = [
"^/login/$",
"^/admin.*",
] - 使用rbac权限管理
- 创建CMDB项目
- 把rbac拷贝到项目中
- 在settings.APP中注册 rbac
- 在settings中配置相关变量:
PERMISSION_DICT = "permission_dict"
URL_FORMAT = "^{0}$"
RBAC_LOGIN_URL = "/login/"
VALID_URL_LIST = [
"^/login/$",
"^/admin.*",
]
- 开发CMDB
- 开启中间件验证
- 利用tmplatetags和模板动态生成菜单
- 在Django admin中操作权限信息 练习
- 权限系统补充完整,搞清楚每一行代码 [4天]
- 自己创建project,比如主机管理系统
- 主机
- 主机组
- 部门
- 机房
- ...
- 使用rbac权限系统 [10天]

  

五、代码实现

表结构如上所述,此处略过...

# 项目结构

D:\soft\work\Python_17\day26\homework\s17crm>tree /F
卷 NewDisk 的文件夹 PATH 列表
卷序列号为 2E8B-8205
D:.
│ db.sqlite3
│ manage.py


├─app01
│ │ admin.py
│ │ apps.py
│ │ models.py
│ │ tests.py
│ │ views.py
│ └─ __init__.py


├─rbac
│ │ admin.py
│ │ apps.py
│ │ models.py
│ │ tests.py
│ │ views.py
│ │ __init__.py
│ │
│ ├─middleware
│ │ └─ rbac.py
│ │
│ │
│ ├─service
│ │ │ init_permission.py
│ │ │
│ │ └─__pycache__
│ │ init_permission.cpython-35.pyc
│ │
│ ├─templatetags
│ │ menu_gennerator.py
│ └─ __init__.py


├─s17crm
│ │ settings.py
│ │ urls.py
│ │ wsgi.py
│ └─ __init__.py

├─statics
│ ├─css
│ │ bbs.css
│ │ bootstrap-select.min.css
│ │ bootstrap-theme.css
│ │ bootstrap-theme.css.map
│ │ bootstrap-theme.min.css
│ │ bootstrap-theme.min.css.map
│ │ bootstrap.css
│ │ bootstrap.css.map
│ │ bootstrap.min.css
│ │ bootstrap.min.css.map
│ │ bootstrapValidator.min.css
│ │
│ ├─image
│ │ header.png
│ │
│ └─js
│ bootstrap-select.js.map
│ bootstrap-select.min.js
│ bootstrap.js
│ bootstrap.min.js
│ bootstrapValidator.min.js
│ city_info.js
│ jquery-3.2.1.js
│ jquery-3.2.1.min.js
│ jquery.cookie.js
│ npm.js

└─templates
index.html
login.html
menu_tpl.html
order.html
order_add.html
tpl.html
user.html
user_add.html D:\soft\work\Python_17\day26\homework\s17crm>

  

# s17crm/app01/views.py

from django.shortcuts import render,HttpResponse,redirect
from django.forms import Form
from django.forms import fields
from django.forms import widgets
from rbac import models
from rbac.service.init_permission import init_permission
from django.conf import settings class LoginForm(Form):
username = fields.CharField(required=True,error_messages={'required':"用户名不能为空"})
password = fields.CharField(required=True,error_messages={'required':"密码不能为空"}) def login(request):
if "GET" == request.method:
form = LoginForm()
return render(request,'login.html',{'form':form})
else:
form = LoginForm(data=request.POST)
if form.is_valid():
# 格式验证通过
# 注意:只有当 LoginForm 里面变量名称和models表字段名称一致才能使用 **form.cleaned_data
user = models.UserInfo.objects.filter(**form.cleaned_data).first()
if user:
# 获取当前用户的权限信息做格式化然后存储到session中
init_permission(request,user)
print(request.session.get(settings.PERMISSION_DICT))
print(request.session.get(settings.PERMISSION_MENU_LIST))
return redirect('/index/')
else:
from django.core.exceptions import ValidationError
form.add_error('password',ValidationError("用户名或密码错误!!!")) return render(request,'login.html',{'form':form}) def index(request):
# 通过 @register.inclusion_tag('menu_tpl.html') 构造菜单结构并渲染
# 所以这里不用做处理
return render(request,'index.html') def clear(request):
# 手动清空session
request.session.clear()
return HttpResponse("已清除") def order(request):
return render(request,'order.html') def order_add(request):
return render(request,'order_add.html') def user(request):
return render(request,'user.html') def user_add(request):
return render(request,'user_add.html')

  

# s17crm\rbac\middleware\rbac.py
# 用户访问鉴权中间件 #!/usr/bin/python
# -*- coding:utf-8 -*-
# 这是页面权限验证的中间件 from django.shortcuts import HttpResponse,redirect
from django.conf import settings
import re class MiddlewareMixin(object):
def __init__(self, get_response=None):
self.get_response = get_response
super(MiddlewareMixin, self).__init__() def __call__(self, request):
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
if not response:
response = self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response class RbacMiddleware(MiddlewareMixin):
def process_request(self,request): # 1. 获取当前请求的 uri
current_request_url = request.path_info # 2. 判断是否在白名单里,在则不进行验证,直接放行
for url in settings.VALID_URL_LIST:
if re.match(url, current_request_url):
return None # 3. 验证用户是否有访问权限
flag = False
permission_dict = request.session.get(settings.PERMISSION_DICT) print(permission_dict) # 如果没有登录过就直接跳转到登录页面
if not permission_dict:
return redirect(settings.RBAC_LOGIN_URL)
"""
{
1: {
'codes': ['list', 'add'],
'urls': ['/userinfo/', '/userinfo/add/']
},
2: {
'codes': ['list'],
'urls': ['/order/']
}
}
"""
for group_id, values in permission_dict.items():
for url in values['urls']:
# 必须精确匹配 URL : "^{0}$"
patten = settings.URL_FORMAT.format(url)
if re.match(patten, current_request_url):
flag = True
break
if flag:
break
if not flag:
return HttpResponse("无权访问")

  

# s17crm\rbac\service\init_permission.py
# 这是用户登录后初始化用户权限信息的模块 #!/usr/bin/python
# -*- coding:utf-8 -*- from django.conf import settings def init_permission(request,user):
# 获取当前用户的权限信息
"""
外键和多对多 都可以用 __(双下划线) 跨表获取对应字段
[].distinct() 进行去重
"""
permission_list = user.roles.filter(permissions__id__isnull=False).values(
'permissions__id',
'permissions__title',
'permissions__url',
'permissions__code',
'permissions__group',
'permissions__is_menu',
'permissions__group__parent_id', # 即:当前权限所在组的所属菜单ID
'permissions__group__parent__title', # 即:当前权限所在组的所属菜单名称
).distinct() # 格式化当前用户的权限信息
"""
{
1: {
'codes': ['list', 'add'],
'urls': ['/userinfo/', '/userinfo/add/']
},
2: {
'codes': ['list'],
'urls': ['/order/']
}
}
"""
permission_dict = {}
for item in permission_list:
url = item.get('permissions__url')
code = item.get('permissions__code')
group_id = item.get('permissions__group')
if group_id in permission_dict:
permission_dict[group_id]['urls'].append(url)
permission_dict[group_id]['codes'].append(code)
else:
permission_dict[group_id] = {'codes': [code, ], 'urls': [url, ]}
# 把当前用户权限信息存储到session中
request.session[settings.PERMISSION_DICT] = permission_dict # 格式化当前用户的菜单列表信息
# 最终的目的就是要把菜单和具体的is_menu=True的权限item关联起来并在前端构成 两级菜单
'''
[
{'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/userinfo/', 'permission_title': '用户列表'},
{'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/userinfo/add/', 'permission_title': '添加用户'},
{'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/order/', 'permission_title': '订单列表'}
]
'''
permission_menu_list = []
for item in permission_list:
if item['permissions__is_menu']:
tmp = {
'menu_title':item['permissions__group__parent__title'],
'menu_id':item['permissions__group__parent_id'],
'permission_url':item['permissions__url'],
'permission_title':item['permissions__title'],
}
permission_menu_list.append(tmp)
# 把当前用户菜单信息存储到session中
request.session[settings.PERMISSION_MENU_LIST] = permission_menu_list # 设置session的超时时间:30min
request.session.set_expiry(1800) # 为了要在前端构造出两级菜单,还需要对上面拿到的菜单列表做一下格式转换
'''
{
4:{
'opened':False,
'menu_title':'用户管理菜单',
'children': [
{'title': '用户列表', 'url': '/userinfo/', 'opened':False},
{'title': '订单列表', 'url': '/order/', 'opened':False,}
]
},
6: {
'opened':False,
'menu_title':'权限管理菜单',
'children': [
{'title': '权限列表', 'url': '/xxxinfo/', 'opened':False},
{'title': '分类列表', 'url': '/xxxxxxxx/', 'opened':False,}
]
}
}
'''
# s17crm\rbac\templatetags\menu_gennerator.py
# 使用inclusion_tag渲染菜单显示在前端页面 #!/usr/bin/python
# -*- coding:utf-8 -*- from django import template
register = template.Library() import re
from django.conf import settings '''
[
{'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/userinfo/', 'permission_title': '用户列表'},
{'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/userinfo/add/', 'permission_title': '添加用户'},
{'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/order/', 'permission_title': '订单列表'},
...
] 转换成下面的结构,然后再前端进行展示 {
4:{
'opened':False,
'menu_title':'用户管理菜单',
'children': [
{'title': '用户列表', 'url': '/userinfo/', 'opened':False},
{'title': '订单列表', 'url': '/order/', 'opened':False,}
]
},
6: {
'opened':False,
'menu_title':'权限管理菜单',
'children': [
{'title': '权限列表', 'url': '/xxxinfo/', 'opened':False},
{'title': '分类列表', 'url': '/xxxxxxxx/', 'opened':False,}
]
},
...
}
''' @register.inclusion_tag('menu_tpl.html')
def menu_show(request):
permission_menu_dict = {}
current_request_url = request.path_info
permission_menu_list = request.session.get(settings.PERMISSION_MENU_LIST) for item in permission_menu_list:
url = item['permission_url']
patten = settings.URL_FORMAT.format(url)
# 首先遍历所有的具体权限,与当前请求url做比较,匹配则把 opened置为 active,用于配合前端的 .active 属性
opened = "active" if re.match(patten, current_request_url) else "" menu_id = item['menu_id']
child = {'opened': opened, 'title': item['permission_title'], 'url': item['permission_url']}
if menu_id in permission_menu_dict:
# 更新已有menu
permission_menu_dict[menu_id]['children'].append(child)
if opened:
permission_menu_dict[menu_id]['opened'] = opened
else:
# 初始化一个menu
permission_menu_dict[menu_id] = {
'opened': opened,
'menu_title': item['menu_title'],
'children': [child,]
}
return {'permission_menu_dict':permission_menu_dict} # s17crm\templates\menu_tpl.html {% for menu_id,item_dict in permission_menu_dict.items %}
<div class="item">
<div class="menu_title">
<a href="#" class="{{ item_dict.opened }}">{{ item_dict.menu_title }}</a>
</div>
<div class="menu_items {{ item_dict.opened }}">
{% for permission in item_dict.children %}
<a href={{ permission.url }} class="{{ permission.opened }}">{{ permission.title }}</a>
{% endfor %}
</div>
</div>
{% endfor %}

  

# s17crm\templates\login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> <form method="post" novalidate>
{% csrf_token %}
<P>
{{ form.username }} {{ form.errors.username.0 }}
</P>
<p>
{{ form.password }} {{ form.errors.password.0 }}
</p> <input type="submit" value="提交">
</form> </body>
</html>
# s17crm\templates\tpl.html

{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>###CRM</title>
<link rel="Shortcut Icon" href="{% static "image/header.png" %}">
<link rel="stylesheet" href="{% static "css/bootstrap.css" %}">
<script src="{% static "js/jquery-3.2.1.min.js" %}"></script>
<script src="{% static "js/bootstrap.js" %}"></script> <style>
body {
margin: 0;
padding: 0;
}
.header {
height: 40px;
background-color: lightgreen;
text-align: center;
line-height: 40px;
}
.menu {
float: left;
width: 16%;
background-color: wheat;
min-height: 500px
}
.right_body {
float: left;
width: 84%;
min-height: 500px;
}
.item .menu_title {
font-size: 20px;
}
.item .menu_title a.active {
color: green;
}
.item .menu_items {
display: none;
}
.item .menu_items.active {
display: block !important;
}
.item .menu_items a {
font-size: 15px;
display: block;
padding-left: 20px;
}
.item .menu_items a.active {
color: red;
}
</style>
</head>
<body> <div class="header">
<h2>头部文字水平垂直居中显示...</h2>
</div> {% load menu_gennerator %}
<div class="content"> <div class="menu">
{% menu_show request %}
</div> {% block content %} <h1>这个是模板页面...</h1> {% endblock %} </div> </body>
<script>
$(function () {
menu_swith();
}); function menu_swith() {
$(".menu_title").click(function () {
if($(this).children().hasClass("active")) {
$(this).next().removeClass("active");
$(this).children().removeClass("active");
}else {
$(this).children().addClass("active");
$(this).next().addClass("active");
}
})
} </script> </html>

  

# s17crm\templates\index.html

{% extends "tpl.html" %}

{% block content %}

<div class="right_body">
<h1>这是首页...</h1>
</div> {% endblock %} # s17crm\templates\order.html {% extends "tpl.html" %} {% block content %} <div class="right_body">
<h1>订单列表...</h1>
</div> {% endblock %} # s17crm\templates\order_add.html {% extends "tpl.html" %} {% block content %} <div class="right_body">
<h1>新增订单...</h1>
</div> {% endblock %} ...

  

# s17crm\s17crm\urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.login),
url(r'^index/', views.index),
url(r'^clear/', views.clear),
url(r'^userinfo/$', views.user),
url(r'^userinfo/add/$', views.user_add),
url(r'^order/$', views.order),
url(r'^order/add/$', views.order_add),
]

  

# \s17crm\s17crm\settings.py

"""
Django settings for s17crm project. Generated by 'django-admin startproject' using Django 1.11.3. For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/ For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
""" import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '-dulev94(7c=_e_s!@ww937pu3rqiiszw1y(eyl3*mp$&5h_e2' # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01',
'rbac',
] MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'rbac.middleware.rbac.RbacMiddleware'
] ROOT_URLCONF = 's17crm.urls' TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
] WSGI_APPLICATION = 's17crm.wsgi.application' # Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
} # Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
] # Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/ STATIC_URL = '/static/' #引用名
# 配置STATICFILES_DIRS,指定额外的静态文件存储位置
STATICFILES_DIRS = (
os.path.join(BASE_DIR,"statics"), #实际名 ,即实际文件夹的名字
) ########################## 自定义权限相关配置 ################################## PERMISSION_DICT = "permission_dict"
PERMISSION_MENU_LIST = "permission_menu_list"
URL_FORMAT = "^{0}$"
RBAC_LOGIN_URL = "/login/"
VALID_URL_LIST = [
"^/login/$",
"^/admin.*",
"^/clear/$",
]

  

CRM项目之RBAC权限组件-day26的更多相关文章

  1. rbac权限组件整合到实际项目的全过程详述

    rbac简介 项目的GitHub地址 欢迎Download&Fork&Star:https://github.com/Wanghongw/CombineRbac 另外,本文只简单介绍一 ...

  2. 1、rbac权限组件-初识, 中间件校验1

    1.权限组件rbac 1.什么是权限 1 项目与应用 2 什么是权限? 一个包含正则表达式url就是一个权限 who what how ---------->True or Flase 2.版本 ...

  3. CRM第一篇:权限组件之权限控制

    一.权限组件(1):一级菜单 二.权限组件(2):二级菜单 三.权限组件(3):默认选中非菜单(二级菜单) 四.权限组件(4):给动态菜单增加面包屑导航 五.权限组件(5):权限粒度控制到按钮 六.权 ...

  4. django自定义rbac权限组件(二级菜单)

    一.目录结构 二.表结构设计 model.py from django.db import models # Create your models here. class Menu(models.Mo ...

  5. day28 CRM万能权限组件开发 && 主机管理-堡垒机

    1,CRM项目实战-万能权限组件开发参考博客:http://www.cnblogs.com/alex3714/articles/6661911.html 参考代码:https://github.com ...

  6. Django-CRM项目学习(六)-rbac模块(权限组件)

    1.rbac权限组件 1.1 模板分析(五表结构) 1.2 模板构建 人物和角色进行多对多绑定,角色与权限进行多对多绑定.其中人物和角色的多对多绑定的操作可以避免相同的人物多重权限的操作. 1.3 数 ...

  7. python 全栈开发,Day107(CRM初始,权限组件之权限控制,权限系统表设计)

    一.CRM初始 CRM,客户关系管理系统(Customer Relationship Management).企业用CRM技术来管理与客户之间的关系,以求提升企业成功的管理方式,其目的是协助企业管理销 ...

  8. CRM【第一篇】: 权限组件之权限控制

    1. 问:为什么程序需要权限控制? 答:生活中的权限限制,① 看灾难片电影<2012>中富人和权贵有权登上诺亚方舟,穷苦老百姓只有等着灾难的来临:② 屌丝们,有没有想过为什么那些长得漂亮身 ...

  9. django——CRM项目

    1.引言 CRM,客户关系管理系统(Customer Relationship Management).企业用CRM技术来管理与客户之间的关系,以求提升企业成功的管理方式,其目的是协助企业管理销售循环 ...

随机推荐

  1. LOJ# 572. 「LibreOJ Round #11」Misaka Network 与求和(min25筛,杜教筛,莫比乌斯反演)

    题意 求 \[ \sum_{i = 1}^{n} \sum_{i = 1}^{n} f(\gcd(i, j))^k \pmod {2^{32}} \] 其中 \(f(x)\) 为 \(x\) 的次大质 ...

  2. Hdoj 2563.统计问题 题解

    Problem Description 在一无限大的二维平面中,我们做如下假设: 1. 每次只能移动一格: 2. 不能向后走(假设你的目的地是"向上",那么你可以向左走,可以向右走 ...

  3. Android平台如何获得屏幕尺寸?

    本文选自StackOverflow(简称:SOF)精选问答汇总系列文章之一,本系列文章将为读者分享国外最优质的精彩问与答,供读者学习和了解国外最新技术,本文为大家讲解在Android平台上如何获得屏幕 ...

  4. 【UOJ#236】[IOI2016]railroad(欧拉回路,最小生成树)

    [UOJ#236][IOI2016]railroad(欧拉回路,最小生成树) 题面 UOJ 题解 把速度看成点,给定的路段看成边,那么现在就有了若干边,然后现在要补上若干边,以及一条\([inf,\) ...

  5. 【BZOJ5316】[JSOI2018]绝地反击(网络流,计算几何,二分)

    [BZOJ5316][JSOI2018]绝地反击(网络流,计算几何,二分) 题面 BZOJ 洛谷 题解 很明显需要二分一个答案. 那么每个点可以确定的范围就是以当前点为圆心,二分出来的答案为半径画一个 ...

  6. push的时候报错:Permission denied (publickey)

    最近,在push的时候遇到一个问题,简单描述下过程(git客户端命令行操作) 我先在本地建了一个文件夹,mkdir dubbodemo 然后进入到这个文件夹,cd dubbodemo 添加我的内容 初 ...

  7. HEOI2016解题报告

    树 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记 ...

  8. nuxt.js实战之开发环境配置

    一.创建项目 1.使用如下命令生成项目 vue init nuxt-community/starter-template testPro --testPro为项目名称 2.进入到项目根目录下,使用np ...

  9. Go实战--golang中使用JWT(JSON Web Token)

    http://blog.csdn.net/wangshubo1989/article/details/74529333 之前写过关于golang中如何使用cookie的博客: 实战–go中使用cook ...

  10. io系列之其他事项

    二.对IO异常的处理. io操作中,只要涉及到底层操作的就必须进行 io异常处理. IOException 是IO操作中必须处理的异常. 示例: class IOExceptionTest { pub ...