Role Based Access Control,基于角色的权限控制,用于计算机操作系统的安全性控制
组件
多个插件组合到一起的部件,用于实现一系列相关功能. 例如:form组件
插件
仅仅实现一个小功能 比如: 分页
权限组件
实现思路: 用户--->职位(角色)--->权限
表结构设计
1. 仅设计 权限表和用户表
权限表 id url
用户表 id name pwd .....
[ 关系:多对多, 一个人要有多个权限( 查看,修改的权限 ),且一个权限可以被多个人使用 ]
缺点:这种关系是繁琐的:一个职员的离职和入职,都需要删除和添加这个职员和权限的关系
2.我们引入了角色的概念
权限表 路由 标题
用户表 姓名 密码
角色表 名称
[ 用户和角色是多对多的关系(要有兼职的概念) ; 权限和角色也是多对多的关系(BOSS和销售都要有 查 的权限),而BOSS不可能只有 查 的权限 ]
一定要注意:权限的重叠
流程
- 首先要记录每个用户的权限
- 登录注册功能
- 用户登录的时候,校验用户的路由
- 登录完成时,将用户的权限储存到session中,方便快速获取校验
- 登录完成后,要校验用户访问的路由,不能超出权限,所以我们要利用中间件,在访问之前完成校验
- 如果超出权限,抛出异常
实践
记录用户权限
在 django 项目中创建并注册一个app
简单示例:
class Permission(models.Model):
'''
权限表
'''
url = models.CharField('权限', max_length=32)
title = models.CharField('标题', max_length=32)
def __str__(self):
return self.title
class Role(models.Model):
'''
角色表
'''
name = models.CharField('角色名称', max_length=32)
permissions = models.ManyToManyField('Permission', verbose_name='角色拥有的权限', blank=True)
def __str__(self):
return self.name
class User(models.Model):
'''
用户表
'''
name = models.CharField('用户名', max_length=32)
pwd = models.CharField('密码', max_length=32)
roles = models.ManyToManyField('Role', verbose_name='用户拥有的角色', blank=True)
def __str__(self):
return self.name
我们进入应用下的 admin 文件中,用Django 提供的基于 web 的管理工具
from django.contrib import admin
from rbac import models # 导入表结构
class PermissionAdmin(admin.ModelAdmin):
list_display = ['url', 'title', ] # 显示字段
list_editable = ['title', ] # 修改字段
# 创建的三个表
admin.site.register(models.Permission, PermissionAdmin)
admin.site.register(models.Role)
admin.site.register(models.User)
随后登录 admin 录入数据
登录
def login(request):
'''登录'''
msg = ''
if request.method == 'POST':
user = request.POST.get('username')
pwd = request.POST.get('pwd')
# 通过用户名和密码找到 用户对象
user_obj= models.User.objects.filter(name=user,pwd=pwd).first()
if user_obj:
# 进行 ORM 操作
通过对象找到角色,再通过角色找到权限.. '注意要去重:去除重复权限'
ret = obj.roles.filter(permissions__url__isnull=False).values( xxx ).distinct()
# 将权限列表保存到session中
request.session[settings.PERMISSION_SESSION_KEY] = permission_list
return redirect('customer_list')
msg = '用户名或密码错误'
return render(request,'login.html',{'msg':msg})
校验
在用户访问之前判断是否超出自己的权限,所以我们将权限的校验,放置到中间件中
- 获取当前访问的路由
- 设置白名单
- 判断是否登录,如果没有重定向到登录界面
- 免认证( 有一些页面,需要登录但是不需要校验,比如游客浏览的首页 )
- 获取当前用户的权限信息
- 循环校验
1)对比成功 有权限 return
2)不成功 没有权限 return HttpResponse(‘没有权限’)
其中第3、4 步可以省略不写;还有注意中间件的注册
from django.utils.deprecation import MiddlewareMixin # 导入中间件
from django.shortcuts import HttpResponse
from django.conf import settings # 将session的key保存到配置文件中,做常量,防止修改,而获取不到
import re # 进行正则匹配
class Rbac_Middlewar(MiddlewareMixin):
def process_request(self, request):
# 获取当前的路由
url = request.path_info
# 白名单( 在 settings 中)
for i in settings.WHITE_LIST:
if re.match(i, url):
retur
# 获取当前用户的权限
Permission_list = request.session.get(settings.PERMISSION_SESSION_KEY)
# 进行校验
for i in Permission_list:
if re.match('^{}$'.format(i["url"]), url):
return
return HttpResponse('校验shibai')
注意事项
- form表单的 input 框一定要有名字,否则你无法获取数据的内容
- ORM 的增删改查
- 在录入权限的路由时,注意输入含有正则的字符串
比如 修改权限: 路由可以写作 /customer/edit/(\d+)/ , \d+ 可以表示被修改者的id
- 中间件的注册
- re模块的应用 math( 正则,字符串 )
- 当将 session 的键,作为常量写到 settings 配置文件中时,那么在模板中,无法获取到用户的权限,因为 模板语法仅支持点语法,没有 [ ] 的概念 ,所以我们可以通过 inclusion_tag 来返回自定义标签
# 将权限列表保存到session中
request.session[settings.PERMISSION_SESSION_KEY] = permission_list
# inclusion_tag 流程
1. 创建一个
2. 创建一个 自定义py文件
3. 进行编写基础代码
from django import template
register = template.Library()
@register.inclusion_tag('menu.html')
def menu(request):
menu_dic = request.session.get(settings.MENU_SESSION_KEY)
print(menu_dic)
return {'menu_dic': menu_dic}