普通rbac
用户 角色 角色资源表 资源
二进制权限
用户表
张三 1
角色表
id 名称 resource(int)
1 总经理 7资源表 resource(int)
1 添加用户 1
2 添加部门 2
3 订单管理 4
4 用户管理 8
5 产品管理 16
基本原理
位&运算 :对比权限
位 | 运算 :添加权限
异或 ^:删除权限
可见用二进制权限比普通的rbac少一张表
建表
这里用户表省略 class Role(db.Model): __tablename__ = "role" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(20)) resource = db.Column(db.Integer) class Resourse(db.Model): __tablename__ = 'rosourse' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(20)) resource = db.Column(db.Integer)
原生sql
import pymysql import threading lock = threading.Lock() class DB: def __init__(self) -> None: self.conn = pymysql.connect(host='localhost',port=3306,user='root',password='2743655496',db='social',cursorclass=pymysql.cursors.DictCursor) self.cursor = self.conn.cursor() def reConnect(self): try: self.conn.ping() except: self.conn() #更新添加 def update(self,sql): self.cursor.execute(sql) # self.conn.commit() #获取一条 def findOne(self,sql): self.cursor.execute(sql) res = self.cursor.fetchone() return res #获取多条 def findAll(self,sql): self.reConnect() lock.acquire() self.cursor.execute(sql) res = self.cursor.fetchall() lock.release() return res # 提交方法 def commit(self): self.conn.commit() # 回滚方法 def rollback(self): self.conn.rollback() db1 = DB()
用户表和角色表一对一(此例子中的表和刚刚创的表无关,仅参考代码)
# 封装二进制角色权限管理 from common.util.db import db1 class BinPro: # 给角色授权,添加资源 def set_permission(self, role_id, resource_ids): print('参数》》》》', role_id, resource_ids, type(eval(resource_ids))) for resource_id in eval(resource_ids): # 通过资源id获取资源的二进制权限 sql = "select * from resources where id=%d" % (int(resource_id)) res = db1.get_one(sql) resource = res['resources_id'] print('resource>>>>>', resource) # 根据角色id更新角色的二进制权限 sql1 = "select * from role where id=%d" % (int(role_id)) res1 = db1.get_one(sql1) role = res1['resources_id'] print('role>>>>>', role) # 二进制位运算位或 | 添加 res2 = resource | role print('res2>>>>', res2) sql3 = "update role set resources_id=%d where id=%d" % (int(res2), int(role_id)) db1.update(sql3) return {'message': 'ok'} # 添加角色资源时,权限资源互斥 def set_permission_mutual(self, role_id, resource_ids): print('参数》》》》', role_id, resource_ids, type(eval(resource_ids))) list5 = [] for resource_id in eval(resource_ids): print('resource_id>>>', resource_id) # 通过资源id获取资源的二进制权限 sql = "select * from resources where id=%d" % (int(resource_id)) res = db1.get_one(sql) resource = res['resources_id'] print('resource>>>>>', resource) list5.append(resource) if list5: print('list5>>>>>', list5) sql5 = "select * from resources_mutual" res5 = db1.get_all(sql5) print('res5>>>>>', res5) for i in res5: re_id = i['resource_id'] mutual_id = i['mutual_id'] print('互斥id数据》》》》》', re_id, mutual_id, type(re_id)) # 如果互斥数据在要添加的资源id列表中,就说明有资源互斥问题 if re_id and mutual_id in list5: return {'message': '资源互斥问题!', 'code': 507} # 根据角色id更新角色的二进制权限 sql1 = "select * from role where id=%d" % (int(role_id)) res1 = db1.get_one(sql1) role = res1['resources_id'] print('role>>>>>', role) # 二进制位运算位或 | 添加 res2 = resource | role print('res2>>>>', res2) sql3 = "update role set resources_id=%d where id=%d" % (int(res2), int(role_id)) db1.update(sql3) return {'message': 'ok'} # 鉴权,判断此用户有没有某个单一权限 def check_permission(self, role_id, resource_id): print('获取参数》》》》', role_id, resource_id) # 通过资源id获取资源的二进制权限 sql = "select * from resources where resources_id=%d" % (int(resource_id)) res = db1.get_one(sql) resource = res['resources_id'] print('resource>>>>>', resource) sql2 = "select * from role where id=%d" % int(role_id) res2 = db1.get_one(sql2) print('res2>>>>>>>', res2) resource_ids = res2['resources_id'] print('resource_ids>>>>>', resource_ids) result = resource_ids & resource print('result>>>>>', result) return result # 获取用户的权限列表 使用&来对比权限 def get_permission(self, role_id): # 根据userid查询roleid user和role表连接查询 print('获取参数》》》', role_id) # 根据角色id查询角色的二进制权限 sql = "select resources_id from role where id=%d" % int(role_id) res = db1.get_one(sql) role = res['resources_id'] print('role>>>>>', role) # 查询所有资源 sql2 = "select * from resources" res2 = db1.get_all(sql2) print('res2>>>>>', res2) list1 = [] # 遍历资源,用角色的二进制权限 & 资源的二进制权限 for i in res2: res_id = i['resources_id'] if res_id != None: print('res_id>>>>>', res_id) result = role & res_id print('result>>>>>>', result) if result > 0: list1.append(res_id) print('list1>>>>>', list1, len(list1)) return list1 # 删除某个权限 使用位运算符异或^来删除 def del_permission(self, role_id, resource_id): print('获取参数》》》》', role_id, resource_id) # 根据角色id查询角色的二进制权限 sql = "select resources_id from role where id=%d" % int(role_id) res = db1.get_one(sql) role = res['resources_id'] print('role>>>>', role) # 通过资源id获取资源的二进制权限 sql2 = "select resources_id from resources where resources_id=%d" % int(resource_id) res2 = db1.get_one(sql2) res_id = res2['resources_id'] print('res2>>>>', res2) print('res_id>>>>', res_id) # 删除某个权限 result = role ^ res_id print('result>>>>>', result) # 修改数据库 sql3 = "update role set resources_id=%d where id=%d" % (int(result), int(role_id)) db1.update(sql3) return {'message': 'ok'} # 删除角色对应的所有资源 def del_all_permission(self, role_id): # 给角色添加资源,就要先将该角色的资源进行删除 # 根据角色id更新角色的二进制权限为0 sql = "update role set resources_id=%d where id=%d" % (0, int(role_id)) db1.update(sql) return {'message': 'ok'} # 角色添加资源时选择继承基础角色并且进行资源互斥 def role_add_permission_mutual(self, role_id, resource_ids, inherit_id): print('获取参数》》》》》》', role_id, resource_ids, inherit_id) sql = "select resources_id from role where id=%d" % (int(inherit_id)) res = db1.get_one(sql) # 获取基础角色资源 inherit = res['resources_id'] list5 = [] for resource_id in eval(resource_ids): print('resource_id>>>', resource_id) # 通过资源id获取资源的二进制权限 sql6 = "select * from resources where id=%d" % (int(resource_id)) res = db1.get_one(sql6) resource = res['resources_id'] print('resource>>>>>', resource) list5.append(resource) if list5: print('list5>>>>>', list5) sql5 = "select * from resources_mutual" res5 = db1.get_all(sql5) print('res5>>>>>', res5) for i in res5: re_id = i['resource_id'] mutual_id = i['mutual_id'] print('互斥id数据》》》》》', re_id, mutual_id, type(re_id)) # 如果互斥数据在要添加的资源id列表中,就说明有资源互斥问题 if re_id and mutual_id in list5: return {'message': '资源互斥问题!', 'code': 507} # 根据角色id更新角色的二进制权限 sql1 = "select * from role where id=%d" % (int(role_id)) res1 = db1.get_one(sql1) role = res1['resources_id'] print('role>>>>>', role) # 二进制位运算位或 | 添加 # 1.先将基础角色资源和所选资源相加 inherit_ids = resource | inherit print('inherit_ids>>>>>>', inherit_ids) # 2.在添加到角色资源中 res2 = inherit_ids | role print('res2>>>>', res2) sql3 = "update role set resources_id=%d where id=%d" % (int(res2), int(role_id)) db1.update(sql3) return {'message': 'ok'}
用户和角色多对多
from common.models.cart_model import Resourse,Role
class BinPro:
#授权
def set_promition(self,userid,resourceid,role_id):
"""
:param userid: 用户id
:param resourceid: 资源id
:param role_id: 要填权限的角色id
:return:
"""
# 先获取用户的所有角色
role_all = [1, 3, 4]
# 查询资源信息
resourse = Resourse.query.get(resourceid)
#判断要添加的权限的角色是否在角色列表中
if role_id not in role_all:
return {'msg':'用户所要填权限的角色不存在'}
#查询角色信息
role = Role.query.get(role_id)
# 更新权限
result = role.resource | resourse.resource
role.resource = result
db.session.add(role)
db.session.commit()
# role['binpromition'] | resource['binpromition']
return 'ok'
#鉴权,判断此用户有没有某个单一权限
@classmethod
def check_promition(cls,userid,resourceid):
"""
:param userid: 用户id
:param resourceid: 资源id
:return:
"""
# 方法一
##获取用户所有角色
# role_id = [1, 3, 4]
##获取资源信息
# resourse = Resourse.query.get(resourceid)
# for i in role_id:
# role = Role.query.get(i)
##判断是否拥有权限
# result = role.resource & resourse.resource
# if result != 0:
# return 'ok'
# return 'no'
#方法二:
#获取用户所有角色
role_id = [1, 3, 4]
#获取所有用户角色信息
permission = []
for i in role_id:
role = Role.query.get(i)
permission.append(role)
# 查询所有资源
rosourse = Resourse.query.all()
print(rosourse)
# 遍历资源,用角色的二进制权限 & 资源的二进制权限
list1 = []
print(permission)
for n in permission:
if n:
for i in rosourse:
result = n.resource & (i.resource)
#判断是否有该权限
if result > 0:
print(i.id)
_id = i.id
list1.append(i.id)
# 权限去重
list2 = list(set(list1))
if resourceid in list1:
return 'ok'
return 'no'
#获取用户的权限列表
@staticmethod
def get_promition(userid):
#根据userid查询roleid user和role表连接查询
# , 角色和用户使用了多对多所有查询到多个角色
# 根据角色id查询角色的二进制权限
role_id = [1, 3, 4]
permission = []
for i in role_id:
role = Role.query.get(i)
permission.append(role)
#查询所有资源
rosourse = Resourse.query.all()
print(rosourse)
#遍历资源,用角色的二进制权限 & 资源的二进制权限
list1 = []
print(permission)
for n in permission:
if n:
for i in rosourse:
result = n.resource & (i.resource)
if result > 0:
print(i.id)
_id = i.id
list1.append(i.id)
#权限去重
list2 = list(set(list1))
print('>>>',list2)
list3 = []
for i in list2:
list3.append(Resourse.query.get(i))
return list3
#删除某个权限
@staticmethod
def del_promition(roleid,resourceid):
# 要删除的单个权限
del_source = Resourse.query.get(resourceid)
promition = del_source.resource
permission = []
#获取所有权限
rosourse = Resourse.query.all()
for i in roleid:
role = Role.query.get(i)
permission.append(role)
# 删除单个权限
for n in permission:
if n:
list1 = []
for i in rosourse:
result = n.resource & (i.resource)
if result > 0:
list1.append(i.resource)
if promition in list1:
result = n.resource ^ promition
n.resource = result
db.session.add(n)
db.session.commit()
return 'ok'
#删除角色对应的所有资源
#删除某个权限
@staticmethod
def del_allpromition(roleid):
for i in roleid:
# 根据角色id更新角色的二进制权限为0
role = Role.query.get(i)
role.resource =0
db.session.add(role)
db.session.commit()
return 'ok'
bin = BinPro()
调用测试代码
@test_bp.route('/testabc')
def binary_authority():
# permission = BinPro.del_promition([1, 3, 4],3)
# permission = BinPro.del_allpromition([1, 3, 4])
# permission = BinPro.get_promition(3)
# permission = BinPro.check_promition(1,2)
permission = bin.set_promition(1, 3, 4)
print(permission)
return str(permission)
注意
资源表中的resource是二的倍数
角色后面的resource则是所拥有权限后面resource的和
例如角色 搜索 resource是3 那么他就有id为1,2两个权限
角色 踩踩踩 resource是8 那么他就有id为8这个权限
二进制做奇偶数判断
alist = []
blist = []
for i in range(11):
result = i & 1等于0为偶数,非0为奇数
if result == 0:
alist.append(i)
else:
blist.append(i)
print(alist)
print(blist)