扩展django 自带权限
说明
在不重写 自带权限的基础上,完成支持对象权限,适用于小型项目。
欢迎提出修改意见
软件支持
jsonfield
数据库
新建3个表
from django.db import models
from django.contrib.auth.models import AbstractUser, Group ,User
from jsonfield import JSONField
class Request(models.Model):
request = models.CharField(max_length=16, verbose_name='请求类型(大写)')
class Meta:
db_table = "request"
verbose_name = "请求类型"
verbose_name_plural = verbose_name
def __str__(self):
return self.request
class RolePermission(models.Model):
role = models.CharField(max_length=32, verbose_name='角色组')
table = models.CharField(max_length=32, verbose_name='表名字')
request = models.ManyToManyField(Request, verbose_name='请求', related_name='re', )
permission = JSONField(max_length=1024, verbose_name='权限条件')
class Meta:
db_table = "role_permission"
verbose_name = "角色组权限"
verbose_name_plural = verbose_name
def __str__(self):
return self.role
class Role(models.Model):
group = models.ForeignKey(Group, verbose_name='用户组', on_delete=models.CASCADE)
roles = models.ManyToManyField(RolePermission, verbose_name='角色组权限', blank=True,related_name='roles' )
class Meta:
db_table = "role"
verbose_name = "角色组关系"
verbose_name_plural = verbose_name
def __str__(self):
return self.group.name
system/models
Role 角色组关系 : 系统用户组 <--> 角色组权限
Request 请求类型 : GET ,POST
RolePermission 角色组权限 : 角色 表名字 请求 权限条件(JSON类型)
重点为 RolePermission 表。
例子
-
以常见的资产 asset 为例
表名字 asset 字段 groups (分组 为 dev,ops)
- 权限划分
- 新建用户 hequan
-
新建组 dev
-
在Request 表 添加
GET (代表只读)
POST (代表更新 删除) -
在RolePermission 添加
角色 asset-dev只读
表名字assset
请求 GET
权限条件 {"groups":'dev'} - 在Role 表中 添加
系统用户组 dev
角色组权限 asset-dev只读
权限验证代码
import json
from system.models import Role
from functools import wraps
from django.shortcuts import HttpResponse
def role_permission_get_list(function):
"""
列表页面 控制权限
:param function:
:return:
"""
@wraps(function)
def wrapped(self):
user = self.request.user
groups = [x['name'] for x in self.request.user.groups.values()]
request_type = self.request.method
model = str(self.model._meta).split(".")[1]
filter_dict = {}
not_list = ['page', 'order_by', 'csrfmiddlewaretoken']
for k, v in dict(self.request.GET).items():
if [i for i in v if i != ''] and (k not in not_list):
if '__in' in k:
filter_dict[k] = v
else:
filter_dict[k] = v[0]
if not user.is_superuser:
role_groups = Role.objects.filter(group__name__in=groups).values_list('roles__table',
'roles__request__request',
'roles__permission')
permission_dict = {}
for i in role_groups:
if i[0] == model and i[1] == request_type:
permission_dict = json.loads(i[2])
if permission_dict:
if filter_dict:
for k, v in permission_dict.items():
if '__in' in k:
k1 = k.replace('__in', '')
if '__gt' in k:
k1 = k.replace('__gt', '')
if '__lt' in k:
k1 = k.replace('__lt', '')
else:
k1 = k
if k1 in list(filter_dict.keys()):
del filter_dict[k1]
if filter_dict:
filter_dict.update(**permission_dict)
else:
print('查询条件处理后为空,默认权限')
filter_dict = permission_dict
else:
print('查询条件为空,默认权限')
filter_dict = permission_dict
else:
print('没有权限')
filter_dict = {'id': -1}
self.filter_dict = filter_dict
result = function(self)
return result
return wrapped
def role_permission_detail(function):
"""
详情页面 控制权限
:param function:
:return:
"""
@wraps(function)
def wrapped(self, request, *args, **kwargs):
user = self.request.user
if not user.is_superuser:
groups = [x['name'] for x in self.request.user.groups.values()]
request_type = self.request.method
model = str(self.model._meta).split(".")[1]
pk = self.kwargs.get(self.pk_url_kwarg, None)
role_groups = Role.objects.filter(group__name__in=groups).values_list('roles__table',
'roles__request__request',
'roles__permission')
permission_dict = {}
for i in role_groups:
if i[0] == model and i[1] == request_type:
permission_dict = json.loads(i[2])
permission_dict['id'] = pk
obj = self.model.objects.filter(**permission_dict).count()
if not obj:
return HttpResponse(status=403)
result = function(self, request, *args, **kwargs)
return result
return wrapped
def role_permission_update_delete(function):
"""
详情页面 控制权限
:param function:
:return:
"""
@wraps(function)
def wrapped(self, request):
user = self.request.user
if not user.is_superuser:
groups = [x['name'] for x in self.request.user.groups.values()]
request_type = self.request.method
model = str(self.model._meta).split(".")[1]
pk = self.request.POST.get('nid', None)
role_groups = Role.objects.filter(group__name__in=groups).values_list('roles__table',
'roles__request__request',
'roles__permission')
permission_dict = {}
for i in role_groups:
if i[0] == model and i[1] == request_type:
permission_dict = json.loads(i[2])
permission_dict['id'] = pk
obj = self.model.objects.filter(**permission_dict).count()
if not obj:
ret = {'status': None, 'error': "没有权限,拒绝", 'msg': 'Without permission, rejected'}
return HttpResponse(json.dumps(ret))
result = function(self, request)
return result
return wrapped
CBV 例子
- 省略部分代码
class AssetListAll(LoginRequiredMixin, ListView):
model = Ecs
@role_permission_get_list
def get_queryset(self):
filter_dict = self.filter_dict
self.queryset = self.model.objects.filter(**filter_dict)
return self.queryset
class AssetChange(LoginRequiredMixin, UpdateView):
model = Ecs
@role_permission_detail
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
@role_permission_update_delete
def form_valid(self, form):
self.object = form.save()
return super().form_valid(form)
class AssetDetail(LoginRequiredMixin, DetailView):
model = Ecs
@role_permission_detail
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
class AssetDel(LoginRequiredMixin, View):
model = Ecs
@role_permission_update_delete
def post(self, request):
pass