权限管理组件:rbac
2024-08-26 17:21:02
rbac: Role_Based Access Control,基于角色的权限控制
权限:一个包含正则表达式 的url就是一个权限
目录结构:
rbac这个app中的文件代码如下:
rbac/models.py
from django.db import models # Create your models here. class User(models.Model):
# 这个User要和 app 中的 用户信息表 一对一关联; from rbac.models import *
name = models.CharField(max_length=32)
roles = models.ManyToManyField(to="Role") def __str__(self):
return self.name class Role(models.Model):
title = models.CharField(max_length=32)
permissions = models.ManyToManyField(to="Permission") def __str__(self):
return self.title class Permission(models.Model):
title = models.CharField(max_length=32)
url = models.CharField(max_length=128)
actions = models.CharField(max_length=32) # 用于标识“增删改查”某一操作 --- "add","delete","edit","list"
group = models.ForeignKey(to="PermissionGroup",on_delete=models.CASCADE) # 能够避免页面渲染时,判断 <a>标签是否存在时的 url 带有表名 """
所要得到的数据结构 permission_dict :
{
1:{
url:[...],
actions:[...]
}
2:{
url:[...],
actions:[...]
},
...
}
# 字典中的数字键代表 permission_group,即权限分类(角色或者表名分类)
""" def __str__(self):
return self.title class PermissionGroup(models.Model):
"""
作用:标识哪个权限属于哪个组(或者说是哪个表的增删改查)
"""
title = models.CharField(max_length=32) def __str__(self):
return self.title
rbac/service/register_permissions.py
def initiate_permissions_session(request,user):
""" 登陆后把权限注册到session中 """ # 方式一:只包含 url 的列表
"""
permissions = user.roles.all().values("permissions__url").distinct() # 取出当前用户的所有权限(QuerySet;要去重) permission_list = []
for item in permissions:
permission_list.append(item["permissions__url"]) request.session["permission_list"] = permission_list # 把权限列表注册到session 中,以后直接从 session 中去取
""" # 方式二:字典
permissions = user.roles.all().values("permissions__url","permissions__actions","permissions__group_id").distinct() permissions_dict = {}
for item in permissions:
pgid = item.get("permissions__group_id")
if pgid not in permissions_dict:
permissions_dict[pgid] = {
"actions":[item["permissions__actions"]],
"urls":[item["permissions__url"]]
}
else:
permissions_dict[pgid]["actions"].append(item["permissions__actions"])
permissions_dict[pgid]["urls"].append(item["permissions__url"]) request.session["permissions_dict"] = permissions_dict """
方式二得到的 permissions_dict 数据结构形式:
{
1:{
url:[...],
actions:[...]
}
2:{
url:[...],
actions:[...]
},
...
}
""" """
登陆验证成功后要调用这个函数
"""
rbac/service/rbac.py
from django.utils.deprecation import MiddlewareMixin
import re
from django.shortcuts import redirect,HttpResponse class PermissionValid(MiddlewareMixin):
"""
通过中间件校验用户是否有权限访问某个url
""" def process_request(self,request): current_path = request.path url_white_list = ["/login/","/reg/","/admin/.*"] # /admin/.*" 表示 所有 以 admin 开关的url # 先校验当前的 url 是否在 白名单中 (url_white_list中有正则,不能直接用 in 判断)
for url in url_white_list:
ret = re.match(url,current_path)
if ret:
return None # 通过校验 # 再校验当前用户是否已经登陆(根据具体的登陆验证逻辑来重构这块的代码)
if request.user.is_anonymous:
return redirect("/login/") # 跳转到登陆页面 """
def reg(request,current_path):
permission_list = request.session.get("permission_list", [])
flag = False
for permission in permission_list: permission = "^%s$" % permission ret = re.match(permission, current_path)
if ret:
flag = True
break
return flag #校验权限1(permission_list)
permission_list = request.session.get("permission_list",[]) # ['/users/', '/users/add', '/users/delete/(\\d+)', 'users/edit/(\\d+)']
flag=reg(request,current_path) if not flag:
return HttpResponse("没有访问权限!") return None
""" # 校验权限2:(permission_dict) 最后判断用户是否有当前url 的权限
permissions_dict = request.session["permissions_dict"]
for item in permissions_dict.values():
for url in item["urls"]:
ret = "^%s$"%url # 为了让 url 和 current_path 完全匹配,需要在其前后加上 ^$
ret = re.match(url,current_path)
if ret:
request.actions = item["actions"] # 如果匹配成功,就把该当前用户对该表的所有能进行的操作添加到 request中; # Permission表中 actions & group字段,和 PermissionGroup这个表都是为了这一步
return None
return HttpResponse("您没有这个url的权限!")
rbac组件小结:
权限粒度控制 简单控制:
{% if "users/add" in permissions_list%} 摆脱表控制 更改数据库结构
class Permission(models.Model):
title=models.CharField(max_length=32)
url=models.CharField(max_length=32) action=models.CharField(max_length=32,default="")
group=models.ForeignKey("PermissionGroup",default=1)
def __str__(self):return self.title class PermissionGroup(models.Model):
title = models.CharField(max_length=32) def __str__(self): return self.title 登录验证:
permissions = user.roles.all().values("permissions__url","permissions__group_id","permissions__action").distinct() 构建permission_dict permissions:
[ {'permissions__url': '/users/add/',
'permissions__group_id': 1,
'permissions__action': 'add'}, {'permissions__url': '/roles/',
'permissions__group_id': 2,
'permissions__action': 'list'}, {'permissions__url': '/users/delete/(\\d+)',
'permissions__group_id': 1,
'permissions__action': 'delete'}, {'permissions__url': 'users/edit/(\\d+)',
'permissions__group_id': 1,
'permissions__action': 'edit'}
] permission_dict { 1: {
'urls': ['/users/', '/users/add/', '/users/delete/(\\d+)', 'users/edit/(\\d+)'],
'actions': ['list', 'add', 'delete', 'edit']}, 2: {
'urls': ['/roles/'],
'actions': ['list']} } 中间价校验权限:
permission_dict=request.session.get("permission_dict") for item in permission_dict.values():
urls=item['urls']
for reg in urls:
reg="^%s$"%reg
ret=re.match(reg,current_path)
if ret:
print("actions",item['actions'])
request.actions=item['actions']
return None return HttpResponse("没有访问权限!")
最新文章
- PHP新手常见的一些不好习惯(抄的 有待理解)
- ZOJ Problem Set - 1078 Palindrom Numbers
- docker&#39;部署
- [算法][LeetCode]Linked List Cycle &; Linked List Cycle II——单链表中的环
- HackRF实现ADS-B飞机信号跟踪定位
- awk中文手册
- 设计模式_Adapt
- shell脚本练习(autocert)
- AndroidUI组件之ListView小技巧
- SpannableString可以被点击的文字
- DailyTick 开发实录 —— UI 设计
- 使用git工具将项目上传到github
- 五分钟学习React(四):什么是JSX
- Typora - Markdown 语法说明
- cdnbest如何在站点里开启强制缓存
- wampserver 的默认首页设置
- ssh采用expect实现自动输入密码登录、拷贝
- Centos7部署kubernetes准备工作(一)
- 07.linux系统管理命令
- 【LeetCode题解】225_用队列实现栈(Implement-Stack-using-Queues)