perms data

This commit is contained in:
caoqianming 2020-05-26 20:30:17 +08:00
parent ddcbcdf98a
commit d9b700dfe0
10 changed files with 283 additions and 72 deletions

View File

@ -137,20 +137,24 @@ export default {
label: '全部'
},
{
value: '本级',
label: '本级'
value: '自定义',
label: '自定义'
},
{
value: '同级及以下',
label: '同级及以下'
},
{
value: '本级及以下',
label: '本级及以下'
},
{
value: '仅本人',
label: '仅本人'
value: '本级',
label: '本级'
},
{
value: '自定义',
label: '自定义'
value: '仅本人',
label: '仅本人'
}
]
}

View File

@ -226,7 +226,7 @@ export default {
dept: null,
avatar: ""
},
myHeaders: { Authorization: "JWT " + getToken() },
myHeaders: { Authorization: "Bearer " + getToken() },
uploadUrl: uploadUrl(),
userList: {count:0},
roles: [],

View File

@ -1,4 +1,5 @@
from django.contrib import admin
from simple_history.admin import SimpleHistoryAdmin
from .models import User, Organization, Role, Permission, DictType, Dict
# Register your models here.
admin.site.register(User)
@ -6,4 +7,4 @@ admin.site.register(Organization)
admin.site.register(Role)
admin.site.register(Permission)
admin.site.register(DictType)
admin.site.register(Dict)
admin.site.register(Dict, SimpleHistoryAdmin)

View File

@ -0,0 +1,44 @@
# Generated by Django 3.0.5 on 2020-05-26 02:57
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import simple_history.models
class Migration(migrations.Migration):
dependencies = [
('system', '0004_auto_20200520_0930'),
]
operations = [
migrations.CreateModel(
name='HistoricalDict',
fields=[
('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(blank=True, editable=False, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('name', models.CharField(db_index=True, max_length=30, verbose_name='名称')),
('code', models.CharField(blank=True, max_length=30, null=True, verbose_name='代码')),
('desc', models.TextField(blank=True, null=True, verbose_name='描述')),
('enabled', models.BooleanField(default=True, verbose_name='是否有效')),
('sort', models.IntegerField(default=1, verbose_name='排序')),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
('pid', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='system.Dict', verbose_name='')),
('type', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='system.DictType', verbose_name='类型')),
],
options={
'verbose_name': 'historical 字典',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
]

View File

@ -4,43 +4,9 @@ import django.utils.timezone as timezone
from django.db.models.query import QuerySet
from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords
class DictType(SoftModel):
"""
数据字典类型
"""
name = models.CharField('名称', max_length=30)
code = models.CharField('代号', unique=True, max_length=30)
pid = models.ForeignKey('self', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='')
class Meta:
verbose_name = '字典类型'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class Dict(SoftModel):
"""
数据字典
"""
name = models.CharField('名称', max_length=30, unique=True)
code = models.CharField('代码', max_length=30, null=True, blank=True)
desc = models.TextField('描述', blank=True, null=True)
enabled = models.BooleanField('是否有效', default=True)
type = models.ForeignKey(
DictType, on_delete=models.CASCADE, verbose_name='类型')
sort = models.IntegerField('排序', default=1)
pid = models.ForeignKey('self', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='')
class Meta:
verbose_name = '字典'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class Position(BaseModel):
"""
@ -73,7 +39,8 @@ class Permission(SoftModel):
sort = models.IntegerField('排序标记', default=1)
pid = models.ForeignKey('self', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='')
method = models.CharField('方法/代号', max_length=50, unique=True, null=True, blank=True)
method = models.CharField('方法/代号', max_length=50,
unique=True, null=True, blank=True)
def __str__(self):
return self.name
@ -112,10 +79,11 @@ class Role(SoftModel):
"""
data_type_choices = (
('全部', '全部'),
('本级', '本级'),
('自定义', '自定义'),
('同级及以下', '同级及以下'),
('本级及以下', '本级及以下'),
('仅本人', '仅本人'),
('自定义', '自定义')
('本级', '本级'),
('仅本人', '仅本人')
)
name = models.CharField('角色', max_length=32, unique=True)
perms = models.ManyToManyField(Permission, blank=True, verbose_name='功能权限')
@ -157,12 +125,53 @@ class User(AbstractUser):
def __str__(self):
return self.username
class DictType(SoftModel):
"""
数据字典类型
"""
name = models.CharField('名称', max_length=30)
code = models.CharField('代号', unique=True, max_length=30)
pid = models.ForeignKey('self', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='')
class Meta:
verbose_name = '字典类型'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class Dict(SoftModel):
"""
数据字典
"""
name = models.CharField('名称', max_length=30, unique=True)
code = models.CharField('代码', max_length=30, null=True, blank=True)
desc = models.TextField('描述', blank=True, null=True)
enabled = models.BooleanField('是否有效', default=True)
type = models.ForeignKey(
DictType, on_delete=models.CASCADE, verbose_name='类型')
sort = models.IntegerField('排序', default=1)
pid = models.ForeignKey('self', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='')
history = HistoricalRecords()
class Meta:
verbose_name = '字典'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class CommonModel(SoftModel):
"""
业务用基本表
"""
create_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='创建人', related_name='create_by')
update_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='最后编辑人', related_name='update_by')
create_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='创建人', related_name='create_by')
update_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='最后编辑人', related_name='update_by')
class Meta:
abstract = True

View File

@ -1,8 +1,8 @@
from django.core.cache import cache
from rest_framework.permissions import BasePermission
from utils.queryset import get_child_queryset2
from .models import Permission
from django.db.models import Q
def get_permission_list(user):
"""
@ -54,3 +54,39 @@ class RbacPermission(BasePermission):
return False
else:
return False
def has_object_permission(self, request, view, obj):
"""
Return `True` if permission is granted, `False` otherwise.
"""
has_obj_perm(request.user, obj)
return True
def has_obj_perm(user, obj):
"""
数据权限控权
返回对象的是否可以操作
需要控数据权限的表需有belong_to, create_by, update_by字段(部门, 创建人, 编辑人)
传入user, obj实例
"""
roles = user.roles
data_range = roles.values_list('datas', flat=True)
if '全部' in data_range:
return True
elif '自定义' in data_range:
if roles.depts.exists():
if obj.belong_to not in roles.depts:
return False
elif '同级及以下' in data_range:
if user.dept.pid:
belong_tos = get_child_queryset2(user.dept.pid)
if obj.belong_to not in belong_tos:
return False
elif '本级及以下' in data_range:
belong_tos = get_child_queryset2(user.dept)
if obj.belong_to not in belong_tos:
return False
elif '本级' in data_range:
if obj.belong_to is not user.dept:
return False
return True

View File

@ -0,0 +1,84 @@
from django.db.models import Q
from django.db.models.query import QuerySet
from rest_framework.generics import GenericAPIView
from utils.queryset import get_child_queryset2
class RbacFilterSet(GenericAPIView):
"""
数据权限控权返回的queryset
在必须的View下继承
需要控数据权限的表需有belong_to, create_by, update_by字段(部门, 创建人, 编辑人)
"""
def get_queryset(self):
assert self.queryset is not None, (
"'%s' should either include a `queryset` attribute, "
"or override the `get_queryset()` method."
% self.__class__.__name__
)
queryset = self.queryset
if isinstance(queryset, QuerySet):
# Ensure queryset is re-evaluated on each request.
queryset = queryset.all()
if hasattr(queryset.model, 'belong_to'):
user = self.request.user
roles = user.roles
data_range = roles.values_list('datas', flat=True)
if '全部' in data_range:
return queryset
elif '自定义' in data_range:
if roles.depts.exists():
queryset = queryset.filter(belong_to__in = roles.depts)
return queryset
elif '同级及以下' in data_range:
if user.dept.pid:
belong_tos = get_child_queryset2(user.dept.pid)
queryset = queryset.filter(belong_to__in = belong_tos)
return queryset
elif '本级及以下' in data_range:
belong_tos = get_child_queryset2(user.dept)
queryset = queryset.filter(belong_to__in = belong_tos)
return queryset
elif '本级' in data_range:
queryset = queryset.filter(belong_to = user.dept)
return queryset
elif '仅本人' in data_range:
queryset = queryset.filter(Q(create_by=user)|Q(update_by=user))
return queryset
return queryset
def rbac_filter_queryset(user, queryset):
"""
数据权限控权返回的queryset方法
需要控数据权限的表需有belong_to, create_by, update_by字段(部门, 创建人, 编辑人)
传入user实例,queryset
"""
roles = user.roles
data_range = roles.values_list('datas', flat=True)
if '全部' in data_range:
return queryset
elif '自定义' in data_range:
if roles.depts.exists():
queryset = queryset.filter(belong_to__in = roles.depts)
return queryset
elif '同级及以下' in data_range:
if user.dept.pid:
belong_tos = get_child_queryset2(user.dept.pid)
queryset = queryset.filter(belong_to__in = belong_tos)
return queryset
elif '本级及以下' in data_range:
belong_tos = get_child_queryset2(user.dept)
queryset = queryset.filter(belong_to__in = belong_tos)
return queryset
elif '本级' in data_range:
queryset = queryset.filter(belong_to = user.dept)
return queryset
elif '仅本人' in data_range:
queryset = queryset.filter(Q(create_by=user)|Q(update_by=user))
return queryset
return queryset

View File

@ -1,3 +1,5 @@
import logging
from django.contrib.auth.hashers import check_password, make_password
from django.core.cache import cache
from django_filters.rest_framework import DjangoFilterBackend
@ -12,18 +14,20 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from rest_framework_simplejwt.tokens import RefreshToken
from utils.queryset import get_child_queryset
from .models import Organization, Permission, Position, Role, User, DictType, Dict
from utils.queryset import get_child_queryset2
from .filters import UserFilter
from .models import (Dict, DictType, Organization, Permission, Position, Role,
User)
from .permission import RbacPermission, get_permission_list
from .serializers import (OrganizationSerializer, PermissionSerializer,
from .permission_data import RbacFilterSet
from .serializers import (DictSerializer, DictTypeSerializer,
OrganizationSerializer, PermissionSerializer,
PositionSerializer, RoleSerializer,
UserCreateSerializer, UserListSerializer,
UserModifySerializer, DictSerializer, DictTypeSerializer)
from .filters import UserFilter
import logging
UserModifySerializer)
logger = logging.getLogger('log')
# logger.info('请求成功! response_code:{}response_headers:{}response_body:{}'.format(response_code, response_headers, response_body[:251]))
@ -36,11 +40,13 @@ class LogoutView(APIView):
def get(self, request, *args, **kwargs): # 可将token加入黑名单
return Response(status=status.HTTP_200_OK)
class DictTypeViewSet(ModelViewSet):
"""
数据字典类型增删改查
"""
perms_map = {'get': '*', 'post': 'dicttype_create', 'put': 'dicttype_update','delete': 'dicttype_delete'}
perms_map = {'get': '*', 'post': 'dicttype_create',
'put': 'dicttype_update', 'delete': 'dicttype_delete'}
queryset = DictType.objects.all()
serializer_class = DictTypeSerializer
pagination_class = None
@ -53,18 +59,21 @@ class DictViewSet(ModelViewSet):
"""
数据字典增删改查
"""
perms_map = {'get': '*', 'post': 'dict_create', 'put': 'dict_update','delete': 'dict_delete'}
perms_map = {'get': '*', 'post': 'dict_create',
'put': 'dict_update', 'delete': 'dict_delete'}
queryset = Dict.objects.all()
serializer_class = DictSerializer
search_fields = ['^name']
ordering_fields = ['id']
ordering = 'id'
class PositionViewSet(ModelViewSet):
"""
岗位增删改查
"""
perms_map = {'get': '*', 'post': 'position_create', 'put': 'position_update','delete': 'position_delete'}
perms_map = {'get': '*', 'post': 'position_create',
'put': 'position_update', 'delete': 'position_delete'}
queryset = Position.objects.all()
serializer_class = PositionSerializer
pagination_class = None
@ -74,7 +83,7 @@ class PositionViewSet(ModelViewSet):
class TestView(APIView):
perms_map = {'get':'test_view'} # 单个API控权
perms_map = {'get': 'test_view'} # 单个API控权
pass
@ -82,7 +91,8 @@ class PermissionViewSet(ModelViewSet):
"""
权限增删改查
"""
perms_map = {'get': '*', 'post': 'perm_create', 'put': 'perm_update','delete': 'perm_delete'}
perms_map = {'get': '*', 'post': 'perm_create',
'put': 'perm_update', 'delete': 'perm_delete'}
queryset = Position.objects.all()
queryset = Permission.objects.all()
serializer_class = PermissionSerializer
@ -96,11 +106,12 @@ class OrganizationViewSet(ModelViewSet):
"""
组织机构增删改查
"""
perms_map = {'get': '*', 'post': 'org_create', 'put': 'org_update','delete': 'org_delete'}
perms_map = {'get': '*', 'post': 'org_create',
'put': 'org_update', 'delete': 'org_delete'}
queryset = Organization.objects.all()
serializer_class = OrganizationSerializer
pagination_class = None
search_fields = ['^name','^method']
search_fields = ['^name', '^method']
ordering_fields = ['id']
ordering = 'id'
@ -109,7 +120,8 @@ class RoleViewSet(ModelViewSet):
"""
角色增删改查
"""
perms_map = {'get': '*', 'post': 'role_create', 'put': 'role_update','delete': 'role_delete'}
perms_map = {'get': '*', 'post': 'role_create',
'put': 'role_update', 'delete': 'role_delete'}
queryset = Role.objects.all()
serializer_class = RoleSerializer
pagination_class = None
@ -122,7 +134,8 @@ class UserViewSet(ModelViewSet):
"""
用户管理增删改查
"""
perms_map = {'get': '*', 'post': 'user_create', 'put': 'user_update','delete': 'user_delete'}
perms_map = {'get': '*', 'post': 'user_create',
'put': 'user_update', 'delete': 'user_delete'}
queryset = User.objects.all().order_by('-id')
serializer_class = UserListSerializer
filterset_class = UserFilter
@ -134,7 +147,7 @@ class UserViewSet(ModelViewSet):
queryset = self.get_serializer_class().setup_eager_loading(queryset) # 性能优化
dept = self.request.query_params.get('dept', None) # 该部门及其子部门所有员工
if dept is not None:
deptqueryset = get_child_queryset('rbac.Organization', dept)
deptqueryset = get_child_queryset2(Organization.objects.get(pk=dept))
queryset = queryset.filter(dept__in=deptqueryset)
return queryset
@ -155,7 +168,7 @@ class UserViewSet(ModelViewSet):
password = make_password('0000')
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save(password = password)
serializer.save(password=password)
return Response(serializer.data)
@action(methods=['put'], detail=True, permission_classes=[IsAuthenticated],

View File

@ -43,6 +43,7 @@ INSTALLED_APPS = [
"django_filters",
'apps.system',
'apps.crm',
'simple_history'
]
MIDDLEWARE = [
@ -54,6 +55,7 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'simple_history.middleware.HistoryRequestMiddleware',
]
ROOT_URLCONF = 'server.urls'

View File

@ -2,7 +2,7 @@ from django.db import models
from django.apps import apps
def get_child_queryset_x(checkQueryset, fatherQueryset, noneQueryset, hasParent=True):
def get_child_queryset_u(checkQueryset, fatherQueryset, noneQueryset, hasParent=True):
'''
获取所有子集
查checkQueryset
@ -40,3 +40,21 @@ def get_child_queryset(name, pk, hasParent=True):
queryset = queryset | child_queryset
child_queryset = cls.objects.filter(pid__in=child_queryset)
return queryset
def get_child_queryset2(obj, hasParent=True):
'''
获取所有子集
app.model实例
是否包含父默认True
'''
cls = type(obj)
queryset = cls.objects.none()
fatherQueryset = cls.objects.filter(pk=obj.id)
if fatherQueryset.exists():
if hasParent:
queryset = queryset | fatherQueryset
child_queryset = cls.objects.filter(pid=fatherQueryset.first())
while child_queryset:
queryset = queryset | child_queryset
child_queryset = cls.objects.filter(pid__in=child_queryset)
return queryset