feat(perms): 添加ApplicationPermission API(包含用户/用户组/授权/校验等API)

pull/4886/head
Bai 2020-10-22 17:05:47 +08:00 committed by 老广
parent 4847b7a680
commit 1d550cbe64
18 changed files with 374 additions and 26 deletions

View File

@ -1,4 +1,5 @@
from .application import * from .application import *
from .mixin import *
from .remote_app import * from .remote_app import *
from .database_app import * from .database_app import *
from .k8s_app import * from .k8s_app import *

View File

@ -0,0 +1,49 @@
class SerializeApplicationToTreeNodeMixin:
@staticmethod
def _serialize_db(db):
return {
'id': db.id,
'name': db.name,
'title': db.name,
'pId': '',
'open': False,
'iconSkin': 'database',
'meta': {'type': 'database_app'}
}
@staticmethod
def _serialize_remote_app(remote_app):
return {
'id': remote_app.id,
'name': remote_app.name,
'title': remote_app.name,
'pId': '',
'open': False,
'isParent': False,
'iconSkin': 'chrome',
'meta': {'type': 'remote_app'}
}
@staticmethod
def _serialize_cloud(cloud):
return {
'id': cloud.id,
'name': cloud.name,
'title': cloud.name,
'pId': '',
'open': False,
'isParent': False,
'iconSkin': 'k8s',
'meta': {'type': 'k8s_app'}
}
def dispatch_serialize(self, application):
method_name = f'_serialize_{application.category}'
data = getattr(self, method_name)(application)
return data
def serialize_applications(self, applications):
data = [self.dispatch_serialize(application) for application in applications]
return data

View File

@ -113,3 +113,6 @@ class Application(CommonModelMixin, OrgModelMixin):
class Meta: class Meta:
unique_together = [('org_id', 'name')] unique_together = [('org_id', 'name')]
ordering = ('name',) ordering = ('name',)
def __str__(self):
return '{}({})'.format(self.name, self.get_category_display())

View File

@ -4,9 +4,11 @@
from .asset_permission import * from .asset_permission import *
from .application_permission import * from .application_permission import *
from .user_permission import * from .user_permission import *
from .user_permission_application import *
from .asset_permission_relation import * from .asset_permission_relation import *
from .application_permission_relation import * from .application_permission_relation import *
from .user_group_permission import * from .user_group_permission import *
from .user_group_permission_application import *
from .remote_app_permission import * from .remote_app_permission import *
from .remote_app_permission_relation import * from .remote_app_permission_relation import *
from .user_remote_app_permission import * from .user_remote_app_permission import *

View File

@ -1,18 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.db.models import Q
from common.permissions import IsOrgAdmin from common.permissions import IsOrgAdmin
from orgs.mixins.api import OrgModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from common.utils import get_object_or_none
from ..models import ApplicationPermission from ..models import ApplicationPermission
from ..hands import (
User, UserGroup, Asset, Node, SystemUser,
)
from .. import serializers from .. import serializers
class ApplicationPermissionViewSet(OrgModelViewSet): class ApplicationPermissionViewSet(OrgBulkModelViewSet):
""" """
应用授权列表的增删改查API 应用授权列表的增删改查API
""" """

View File

@ -2,11 +2,10 @@
# #
from rest_framework import generics from rest_framework import generics
from django.db.models import F, Value from django.db.models import F, Value
from django.db.models import Q
from django.db.models.functions import Concat from django.db.models.functions import Concat
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from assets.models import Node, Asset from applications.models import Application
from orgs.mixins.api import OrgRelationMixin from orgs.mixins.api import OrgRelationMixin
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from orgs.utils import current_org from orgs.utils import current_org
@ -18,7 +17,9 @@ __all__ = [
'ApplicationPermissionUserRelationViewSet', 'ApplicationPermissionUserRelationViewSet',
'ApplicationPermissionUserGroupRelationViewSet', 'ApplicationPermissionUserGroupRelationViewSet',
'ApplicationPermissionApplicationRelationViewSet', 'ApplicationPermissionApplicationRelationViewSet',
'ApplicationPermissionSystemUserRelationViewSet' 'ApplicationPermissionSystemUserRelationViewSet',
'ApplicationPermissionAllApplicationListApi',
'ApplicationPermissionAllUserListApi',
] ]
@ -96,3 +97,32 @@ class ApplicationPermissionSystemUserRelationViewSet(RelationMixin):
Value(')') Value(')')
)) ))
return queryset return queryset
class ApplicationPermissionAllApplicationListApi(generics.ListAPIView):
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.ApplicationPermissionAllApplicationSerializer
only_fields = serializers.ApplicationPermissionAllApplicationSerializer.Meta.only_fields
filter_fields = ('name',)
search_fields = filter_fields
def get_queryset(self):
pk = self.kwargs.get('pk')
perm = get_object_or_404(models.ApplicationPermission, pk=pk)
applications = Application.objects.filter(granted_by_permissions=perm)\
.only(*self.only_fields).distinct()
return applications
class ApplicationPermissionAllUserListApi(generics.ListAPIView):
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.ApplicationPermissionAllUserSerializer
only_fields = serializers.ApplicationPermissionAllUserSerializer.Meta.only_fields
filter_fields = ('username', 'name')
search_fields = filter_fields
def get_queryset(self):
pk = self.kwargs.get('pk')
perm = get_object_or_404(models.ApplicationPermission, pk=pk)
users = perm.get_all_users().only(*self.only_fields).distinct()
return users

View File

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
#
from django.db.models import Q
from rest_framework.generics import ListAPIView
from common.permissions import IsOrgAdminOrAppUser
from applications.models import Application
from perms import serializers
__all__ = [
'UserGroupGrantedApplicationsApi'
]
class UserGroupGrantedApplicationsApi(ListAPIView):
"""
获取用户组直接授权的资产
"""
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = serializers.ApplicationGrantedSerializer
only_fields = serializers.ApplicationGrantedSerializer.Meta.only_fields
filter_fields = ['id', 'name', 'comment']
search_fields = ['name', 'comment']
def get_queryset(self):
user_group_id = self.kwargs.get('pk', '')
queryset = Application.objects\
.filter(Q(granted_by_permissions__user_groups__id=user_group_id))\
.distinct().only(*self.only_fields)
return queryset

View File

@ -0,0 +1,2 @@
from .user_permission_applications import *
from .common import *

View File

@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
#
import uuid
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView, Response
from rest_framework.generics import (
ListAPIView, get_object_or_404
)
from applications.models import Application
from perms.utils.application_permission import (
get_application_system_users_id
)
from perms.api.user_permission.mixin import ForAdminMixin, ForUserMixin
from common.permissions import IsOrgAdminOrAppUser
from ...hands import User, SystemUser
from ... import serializers
__all__ = [
'UserGrantedApplicationSystemUsersApi',
'MyGrantedApplicationSystemUsersApi',
'ValidateUserApplicationPermissionApi'
]
class GrantedApplicationSystemUsersMixin(ListAPIView):
serializer_class = serializers.ApplicationSystemUserSerializer
only_fields = serializers.ApplicationSystemUserSerializer.Meta.only_fields
user: None
def get_application_system_users_id(self, application):
return get_application_system_users_id(self.user, application)
def get_queryset(self):
application_id = self.kwargs.get('application_id')
application = get_object_or_404(Application, id=application_id)
system_users_id = self.get_application_system_users_id(application)
system_users = SystemUser.objects.filter(id__in=system_users_id)\
.only(*self.only_fields).order_by('priority')
return system_users
class UserGrantedApplicationSystemUsersApi(ForAdminMixin, GrantedApplicationSystemUsersMixin):
pass
class MyGrantedApplicationSystemUsersApi(ForUserMixin, GrantedApplicationSystemUsersMixin):
pass
class ValidateUserApplicationPermissionApi(APIView):
permission_classes = (IsOrgAdminOrAppUser,)
def get(self, request, *args, **kwargs):
user_id = request.query_params.get('user_id', '')
application_id = request.query_params.get('application_id', '')
system_user_id = request.query_params.get('system_user_id', '')
try:
user_id = uuid.UUID(user_id)
application_id = uuid.UUID(application_id)
system_user_id = uuid.UUID(system_user_id)
except ValueError:
return Response({'msg': False}, status=403)
user = get_object_or_404(User, id=user_id)
application = get_object_or_404(Application, id=application_id)
system_user = get_object_or_404(SystemUser, id=system_user_id)
system_users_id = get_application_system_users_id(user, application)
if system_user.id in system_users_id:
return Response({'msg': True}, status=200)
return Response({'msg': False}, status=403)

View File

@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
#
from rest_framework.generics import ListAPIView
from rest_framework.response import Response
from applications.api.mixin import SerializeApplicationToTreeNodeMixin
from perms import serializers
from perms.api.user_permission.mixin import ForAdminMixin, ForUserMixin
from perms.utils.user_application_permission import (
get_user_granted_all_applications
)
__all__ = [
'UserAllGrantedApplicationsApi',
'MyAllGrantedApplicationsApi',
'UserAllGrantedApplicationsAsTreeApi',
'MyAllGrantedApplicationsAsTreeApi',
]
class AllGrantedApplicationsMixin(ListAPIView):
only_fields = serializers.ApplicationGrantedSerializer.Meta.only_fields
serializer_class = serializers.ApplicationGrantedSerializer
filter_fields = ['id', 'name', 'comment']
search_fields = ['name', 'comment']
user: None
def get_queryset(self):
queryset = get_user_granted_all_applications(self.user)
return queryset.only(*self.only_fields)
class UserAllGrantedApplicationsApi(ForAdminMixin, AllGrantedApplicationsMixin):
only_fields = serializers.ApplicationGrantedSerializer.Meta.only_fields
serializer_class = serializers.ApplicationGrantedSerializer
filter_fields = ['id', 'name', 'comment']
search_fields = ['name', 'comment']
def get_queryset(self):
queryset = get_user_granted_all_applications(self.user)
return queryset.only(*self.only_fields)
class MyAllGrantedApplicationsApi(ForUserMixin, AllGrantedApplicationsMixin):
pass
class ApplicationsAsTreeMixin(SerializeApplicationToTreeNodeMixin):
"""
将应用序列化成树的结构返回
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
data = self.serialize_applications(queryset)
return Response(data=data)
class UserAllGrantedApplicationsAsTreeApi(ApplicationsAsTreeMixin, UserAllGrantedApplicationsApi):
pass
class MyAllGrantedApplicationsAsTreeApi(ApplicationsAsTreeMixin, MyAllGrantedApplicationsApi):
pass

View File

@ -2,10 +2,12 @@
# #
from django.db import models from django.db import models
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from common.utils import lazyproperty from common.utils import lazyproperty
from .base import BasePermission from .base import BasePermission
from users.models import User
__all__ = [ __all__ = [
'ApplicationPermission', 'ApplicationPermission',
@ -36,3 +38,11 @@ class ApplicationPermission(BasePermission):
@lazyproperty @lazyproperty
def system_users_amount(self): def system_users_amount(self):
return self.system_users.count() return self.system_users.count()
def get_all_users(self):
users_id = self.users.all().values_list('id', flat=True)
user_groups_id = self.user_groups.all().values_list('id', flat=True)
users = User.objects.filter(
Q(id__in=users_id) | Q(groups__id__in=user_groups_id)
)
return users

View File

@ -3,7 +3,6 @@
from rest_framework import serializers from rest_framework import serializers
from django.db.models import Count
from orgs.mixins.serializers import BulkOrgResourceModelSerializer from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from perms.models import ApplicationPermission from perms.models import ApplicationPermission

View File

@ -4,15 +4,15 @@ from rest_framework import serializers
from common.mixins import BulkSerializerMixin from common.mixins import BulkSerializerMixin
from common.serializers import AdaptedBulkListSerializer from common.serializers import AdaptedBulkListSerializer
from assets.models import Asset, Node
from ..models import ApplicationPermission from ..models import ApplicationPermission
from users.models import User
__all__ = [ __all__ = [
'ApplicationPermissionUserRelationSerializer', 'ApplicationPermissionUserRelationSerializer',
'ApplicationPermissionUserGroupRelationSerializer', 'ApplicationPermissionUserGroupRelationSerializer',
'ApplicationPermissionApplicationRelationSerializer', 'ApplicationPermissionApplicationRelationSerializer',
'ApplicationPermissionSystemUserRelationSerializer' 'ApplicationPermissionSystemUserRelationSerializer',
'ApplicationPermissionAllApplicationSerializer',
'ApplicationPermissionAllUserSerializer'
] ]
@ -67,3 +67,26 @@ class ApplicationPermissionSystemUserRelationSerializer(RelationMixin, serialize
'id', 'systemuser', 'systemuser_display' 'id', 'systemuser', 'systemuser_display'
] ]
class ApplicationPermissionAllApplicationSerializer(serializers.Serializer):
application = serializers.UUIDField(read_only=True, source='id')
application_display = serializers.SerializerMethodField()
class Meta:
only_fields = ['id', 'name']
@staticmethod
def get_application_display(obj):
return str(obj)
class ApplicationPermissionAllUserSerializer(serializers.Serializer):
user = serializers.UUIDField(read_only=True, source='id')
user_display = serializers.SerializerMethodField()
class Meta:
only_fields = ['id', 'username', 'name']
@staticmethod
def get_user_display(obj):
return str(obj)

View File

@ -7,6 +7,7 @@ from django.utils.translation import ugettext_lazy as _
from assets.models import Node, SystemUser, Asset from assets.models import Node, SystemUser, Asset
from assets.serializers import ProtocolsField from assets.serializers import ProtocolsField
from .asset_permission import ActionsField from .asset_permission import ActionsField
from applications.models import Application
__all__ = [ __all__ = [
'NodeGrantedSerializer', 'NodeGrantedSerializer',
@ -15,6 +16,8 @@ __all__ = [
'RemoteAppSystemUserSerializer', 'RemoteAppSystemUserSerializer',
'DatabaseAppSystemUserSerializer', 'DatabaseAppSystemUserSerializer',
'K8sAppSystemUserSerializer', 'K8sAppSystemUserSerializer',
'ApplicationGrantedSerializer',
'ApplicationSystemUserSerializer'
] ]
@ -34,6 +37,19 @@ class AssetSystemUserSerializer(serializers.ModelSerializer):
read_only_fields = fields read_only_fields = fields
class ApplicationSystemUserSerializer(serializers.ModelSerializer):
"""
查看授权的应用系统用户的数据结构这个和SystemUserSerializer不同字段少
"""
class Meta:
model = SystemUser
only_fields = (
'id', 'name', 'username', 'priority', 'protocol', 'login_mode'
)
fields = list(only_fields)
read_only_fields = fields
class RemoteAppSystemUserSerializer(serializers.ModelSerializer): class RemoteAppSystemUserSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = SystemUser model = SystemUser
@ -92,3 +108,16 @@ class NodeGrantedSerializer(serializers.ModelSerializer):
class ActionsSerializer(serializers.Serializer): class ActionsSerializer(serializers.Serializer):
actions = ActionsField(read_only=True) actions = ActionsField(read_only=True)
class ApplicationGrantedSerializer(serializers.ModelSerializer):
"""
被授权应用的数据结构
"""
class Meta:
model = Application
only_fields = [
'id', 'name', 'domain', 'category', 'type', 'comment', 'org_id'
]
fields = only_fields + ['org_name']
read_only_fields = fields

View File

@ -13,17 +13,17 @@ router.register('application-permissions-user-groups-relations', api.Application
router.register('application-permissions-applications-relations', api.ApplicationPermissionApplicationRelationViewSet, 'application-permissions-application-relation') router.register('application-permissions-applications-relations', api.ApplicationPermissionApplicationRelationViewSet, 'application-permissions-application-relation')
router.register('application-permissions-system-users-relations', api.ApplicationPermissionSystemUserRelationViewSet, 'application-permissions-system-users-relation') router.register('application-permissions-system-users-relations', api.ApplicationPermissionSystemUserRelationViewSet, 'application-permissions-system-users-relation')
"""
user_permission_urlpatterns = [ user_permission_urlpatterns = [
path('<uuid:pk>/applications/', api.UserGrantedApplicationsApi.as_view(), name='user-applications'), path('<uuid:pk>/applications/', api.UserAllGrantedApplicationsApi.as_view(), name='user-applications'),
path('applications/', api.UserGrantedApplicationsApi.as_view(), name='my-applications'), path('applications/', api.MyAllGrantedApplicationsApi.as_view(), name='my-applications'),
# Application as tree # Application As Tree
path('<uuid:pk>/applications/tree/', api.UserGrantedApplicationsAsTreeApi.as_view(), name='user-applications-as-tree'), path('<uuid:pk>/applications/tree/', api.UserAllGrantedApplicationsAsTreeApi.as_view(), name='user-applications-as-tree'),
path('applications/tree/', api.UserGrantedApplicationsAsTreeApi.as_view(), name='my-applications-as-tree'), path('applications/tree/', api.MyAllGrantedApplicationsAsTreeApi.as_view(), name='my-applications-as-tree'),
# Application System Users
path('<uuid:pk>/applications/<uuid:application_id>/system-users/', api.UserGrantedApplicationSystemUsersApi.as_view(), name='user-application-system-users'), path('<uuid:pk>/applications/<uuid:application_id>/system-users/', api.UserGrantedApplicationSystemUsersApi.as_view(), name='user-application-system-users'),
path('applications/<uuid:application_id>/system-users/', api.UserGrantedApplicationSystemUsersApi.as_view(), name='user-application-system-users'), path('applications/<uuid:application_id>/system-users/', api.MyGrantedApplicationSystemUsersApi.as_view(), name='my-application-system-users'),
] ]
user_group_permission_urlpatterns = [ user_group_permission_urlpatterns = [
@ -31,11 +31,11 @@ user_group_permission_urlpatterns = [
] ]
permission_urlpatterns = [ permission_urlpatterns = [
# 授权规则中授权的用户和数据库应用 # 授权规则中授权的用户和应用
path('<uuid:pk>/applications/all/', api.ApplicationPermissionAllApplicationListApi.as_view(), name='application-permission-all-applications'), path('<uuid:pk>/applications/all/', api.ApplicationPermissionAllApplicationListApi.as_view(), name='application-permission-all-applications'),
path('<uuid:pk>/users/all/', api.ApplicationPermissionAllUserListApi.as_view(), name='application-permission-all-users'), path('<uuid:pk>/users/all/', api.ApplicationPermissionAllUserListApi.as_view(), name='application-permission-all-users'),
# 验证用户是否有某个数据库应用的权限 # 验证用户是否有某个应用的权限
path('user/validate/', api.ValidateUserApplicationPermissionApi.as_view(), name='validate-user-application-permission'), path('user/validate/', api.ValidateUserApplicationPermissionApi.as_view(), name='validate-user-application-permission'),
] ]
@ -46,5 +46,3 @@ application_permission_urlpatterns = [
] ]
application_permission_urlpatterns += router.urls application_permission_urlpatterns += router.urls
"""
application_permission_urlpatterns = router.urls

View File

@ -2,7 +2,9 @@
# #
from .asset_permission import * from .asset_permission import *
from .application_permission import *
from .remote_app_permission import * from .remote_app_permission import *
from .database_app_permission import * from .database_app_permission import *
from .k8s_app_permission import * from .k8s_app_permission import *
from .user_asset_permission import * from .user_asset_permission import *
from .user_application_permission import *

View File

@ -0,0 +1,14 @@
from django.db.models import Q
from common.utils import get_logger
from ..models import ApplicationPermission
logger = get_logger(__file__)
def get_application_system_users_id(user, application):
queryset = ApplicationPermission.objects\
.filter(Q(users=user) | Q(user_groups__users=user), Q(applications=application))\
.valid()\
.values_list('system_users', flat=True)
return queryset

View File

@ -0,0 +1,21 @@
from perms.models import ApplicationPermission
from applications.models import Application
def get_user_all_applicationpermission_ids(user):
application_perm_ids = set()
application_perm_ids.update(
ApplicationPermission.objects.valid().filter(users=user).distinct().values_list('id', flat=True)
)
application_perm_ids.update(
ApplicationPermission.objects.valid().filter(user_groups__users=user).distinct().values_list('id', flat=True)
)
return application_perm_ids
def get_user_granted_all_applications(user):
application_perm_ids = get_user_all_applicationpermission_ids(user)
applications = Application.objects.filter(
granted_by_permissions__id__in=application_perm_ids
).distinct()
return applications