Skip to content

Commit

Permalink
feat: rebuild api permission control (#1378)
Browse files Browse the repository at this point in the history
  • Loading branch information
narasux authored Nov 13, 2023
1 parent a852eb7 commit 049be01
Show file tree
Hide file tree
Showing 16 changed files with 291 additions and 77 deletions.
3 changes: 3 additions & 0 deletions src/bk-user/bkuser/apis/web/basic/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
"""
from rest_framework import serializers

from bkuser.apps.permission.constants import UserRole


class CurrentUserRetrieveOutputSLZ(serializers.Serializer):
username = serializers.CharField(help_text="用户名")
tenant_id = serializers.CharField(help_text="租户 ID")
role = serializers.ChoiceField(help_text="用户角色", choices=UserRole.get_choices())
7 changes: 6 additions & 1 deletion src/bk-user/bkuser/apis/web/basic/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from rest_framework import generics, status
from rest_framework.response import Response

from bkuser.apps.permission.permissions import get_user_role

from .serializers import CurrentUserRetrieveOutputSLZ


Expand All @@ -24,9 +26,12 @@ class CurrentUserRetrieveApi(generics.RetrieveAPIView):
def get(self, request, *args, **kwargs):
# FIXME: 待新版登录后重构,return更多信息
current_user = request.user
current_tenant_id = current_user.get_property("tenant_id")

info = {
"username": current_user.username,
"tenant_id": current_user.get_property("tenant_id"),
"tenant_id": current_tenant_id,
"role": get_user_role(current_tenant_id, current_user.username),
}

return Response(CurrentUserRetrieveOutputSLZ(instance=info).data)
14 changes: 14 additions & 0 deletions src/bk-user/bkuser/apis/web/data_source/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from django.utils.translation import gettext_lazy as _
from drf_yasg.utils import swagger_auto_schema
from rest_framework import generics, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from bkuser.apis.web.data_source.mixins import CurrentUserTenantDataSourceMixin
Expand All @@ -42,6 +43,8 @@
from bkuser.apis.web.mixins import CurrentUserTenantMixin
from bkuser.apps.data_source.constants import DataSourceStatus
from bkuser.apps.data_source.models import DataSource, DataSourcePlugin, DataSourceSensitiveInfo
from bkuser.apps.permission.constants import PermAction
from bkuser.apps.permission.permissions import perm_class
from bkuser.apps.sync.constants import SyncTaskTrigger
from bkuser.apps.sync.data_models import DataSourceSyncOptions
from bkuser.apps.sync.managers import DataSourceSyncManager
Expand Down Expand Up @@ -91,6 +94,7 @@ def get(self, request, *args, **kwargs):

class DataSourceListCreateApi(CurrentUserTenantMixin, generics.ListCreateAPIView):
pagination_class = None
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]
serializer_class = DataSourceSearchOutputSLZ

def get_serializer_context(self):
Expand Down Expand Up @@ -154,6 +158,7 @@ class DataSourceRetrieveUpdateApi(
CurrentUserTenantDataSourceMixin, ExcludePatchAPIViewMixin, generics.RetrieveUpdateAPIView
):
pagination_class = None
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]
serializer_class = DataSourceRetrieveOutputSLZ

@swagger_auto_schema(
Expand Down Expand Up @@ -250,6 +255,7 @@ def post(self, request, *args, **kwargs):
class DataSourceSwitchStatusApi(CurrentUserTenantDataSourceMixin, ExcludePutAPIViewMixin, generics.UpdateAPIView):
"""切换数据源状态(启/停)"""

permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]
serializer_class = DataSourceSwitchStatusOutputSLZ

@swagger_auto_schema(
Expand All @@ -274,6 +280,7 @@ class DataSourceTemplateApi(CurrentUserTenantDataSourceMixin, generics.ListAPIVi
"""获取本地数据源数据导入模板"""

pagination_class = None
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]

@swagger_auto_schema(
tags=["data_source"],
Expand All @@ -295,6 +302,7 @@ class DataSourceExportApi(CurrentUserTenantDataSourceMixin, generics.ListAPIView
"""本地数据源用户导出"""

pagination_class = None
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]

@swagger_auto_schema(
tags=["data_source"],
Expand All @@ -317,6 +325,8 @@ def get(self, request, *args, **kwargs):
class DataSourceImportApi(CurrentUserTenantDataSourceMixin, generics.CreateAPIView):
"""从 Excel 导入数据源用户数据"""

permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]

@swagger_auto_schema(
tags=["data_source"],
operation_description="本地数据源用户数据导入",
Expand Down Expand Up @@ -371,6 +381,8 @@ def post(self, request, *args, **kwargs):
class DataSourceSyncApi(CurrentUserTenantDataSourceMixin, generics.CreateAPIView):
"""数据源同步"""

permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]

@swagger_auto_schema(
tags=["data_source"],
operation_description="数据源数据同步",
Expand Down Expand Up @@ -412,6 +424,7 @@ def post(self, request, *args, **kwargs):
class DataSourceSyncRecordListApi(CurrentUserTenantMixin, generics.ListAPIView):
"""数据源同步记录列表"""

permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]
serializer_class = DataSourceSyncRecordListOutputSLZ

def get_queryset(self):
Expand Down Expand Up @@ -449,6 +462,7 @@ class DataSourceSyncRecordRetrieveApi(CurrentUserTenantMixin, generics.RetrieveA
"""数据源同步记录详情"""

lookup_url_kwarg = "id"
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]

def get_queryset(self):
return DataSourceSyncTask.objects.filter(data_source__owner_tenant_id=self.get_current_tenant_id())
Expand Down
7 changes: 7 additions & 0 deletions src/bk-user/bkuser/apis/web/data_source_organization/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from django.db.models import Q
from drf_yasg.utils import swagger_auto_schema
from rest_framework import generics, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from bkuser.apis.web.data_source_organization.serializers import (
Expand All @@ -26,6 +27,8 @@
UserUpdateInputSLZ,
)
from bkuser.apps.data_source.models import DataSource, DataSourceDepartment, DataSourceUser
from bkuser.apps.permission.constants import PermAction
from bkuser.apps.permission.permissions import perm_class
from bkuser.biz.data_source_organization import (
DataSourceOrganizationHandler,
DataSourceUserBaseInfo,
Expand All @@ -39,6 +42,7 @@
class DataSourceUserListCreateApi(generics.ListCreateAPIView):
serializer_class = UserSearchOutputSLZ
lookup_url_kwarg = "id"
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]

def get_queryset(self):
slz = UserSearchInputSLZ(data=self.request.query_params)
Expand Down Expand Up @@ -111,6 +115,7 @@ def post(self, request, *args, **kwargs):

class DataSourceLeadersListApi(generics.ListAPIView):
serializer_class = LeaderSearchOutputSLZ
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]

def get_queryset(self):
slz = LeaderSearchInputSLZ(data=self.request.query_params)
Expand Down Expand Up @@ -139,6 +144,7 @@ def get(self, request, *args, **kwargs):


class DataSourceDepartmentsListApi(generics.ListAPIView):
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]
serializer_class = DepartmentSearchOutputSLZ

def get_queryset(self):
Expand Down Expand Up @@ -171,6 +177,7 @@ def get(self, request, *args, **kwargs):
class DataSourceUserRetrieveUpdateApi(ExcludePatchAPIViewMixin, generics.RetrieveUpdateAPIView):
queryset = DataSourceUser.objects.all()
lookup_url_kwarg = "id"
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]
serializer_class = UserRetrieveOutputSLZ

def get_serializer_context(self):
Expand Down
24 changes: 14 additions & 10 deletions src/bk-user/bkuser/apis/web/organization/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from django.db.models import Q
from drf_yasg.utils import swagger_auto_schema
from rest_framework import generics, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from bkuser.apis.web.mixins import CurrentUserTenantMixin
Expand All @@ -25,6 +26,8 @@
TenantUserSearchInputSLZ,
)
from bkuser.apis.web.tenant.serializers import TenantRetrieveOutputSLZ, TenantUpdateInputSLZ
from bkuser.apps.permission.constants import PermAction
from bkuser.apps.permission.permissions import perm_class
from bkuser.apps.tenant.models import Tenant, TenantUser
from bkuser.biz.tenant import (
TenantDepartmentHandler,
Expand All @@ -33,7 +36,6 @@
TenantHandler,
TenantUserHandler,
)
from bkuser.common.error_codes import error_codes
from bkuser.common.views import ExcludePatchAPIViewMixin

logger = logging.getLogger(__name__)
Expand All @@ -42,6 +44,7 @@
class TenantDepartmentUserListApi(CurrentUserTenantMixin, generics.ListAPIView):
queryset = TenantUser.objects.all()
lookup_url_kwarg = "id"
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]
serializer_class = TenantUserListOutputSLZ

def get_serializer_context(self):
Expand Down Expand Up @@ -100,6 +103,7 @@ def get(self, request, *args, **kwargs):
class TenantUserRetrieveApi(generics.RetrieveAPIView):
queryset = TenantUser.objects.all()
lookup_url_kwarg = "id"
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]
serializer_class = TenantUserRetrieveOutputSLZ

@swagger_auto_schema(
Expand All @@ -113,6 +117,7 @@ def get(self, request, *args, **kwargs):

class TenantListApi(CurrentUserTenantMixin, generics.ListAPIView):
pagination_class = None
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]

@swagger_auto_schema(
tags=["tenant-organization"],
Expand Down Expand Up @@ -145,6 +150,7 @@ def get(self, request, *args, **kwargs):
class TenantRetrieveUpdateApi(ExcludePatchAPIViewMixin, CurrentUserTenantMixin, generics.RetrieveUpdateAPIView):
queryset = Tenant.objects.all()
pagination_class = None
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]
serializer_class = TenantRetrieveOutputSLZ
lookup_url_kwarg = "id"

Expand All @@ -164,28 +170,25 @@ def get(self, request, *args, **kwargs):
tags=["tenant-organization"],
operation_description="更新租户",
request_body=TenantUpdateInputSLZ(),
responses={status.HTTP_200_OK: ""},
responses={status.HTTP_204_NO_CONTENT: ""},
)
def put(self, request, *args, **kwargs):
slz = TenantUpdateInputSLZ(data=request.data)
slz.is_valid(raise_exception=True)
data = slz.validated_data

instance = self.get_object()
# NOTE 非当前租户, 无权限做更新操作
if self.get_current_tenant_id() != instance.id:
raise error_codes.NO_PERMISSION

should_updated_info = TenantEditableBaseInfo(
tenant = self.get_object()
tenant_info = TenantEditableBaseInfo(
name=data["name"], logo=data["logo"] or "", feature_flags=TenantFeatureFlag(**data["feature_flags"])
)

TenantHandler.update_with_managers(instance.id, should_updated_info, data["manager_ids"])
return Response()
TenantHandler.update_with_managers(tenant.id, tenant_info, data["manager_ids"])
return Response(status=status.HTTP_204_NO_CONTENT)


class TenantDepartmentChildrenListApi(generics.ListAPIView):
pagination_class = None
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]
serializer_class = TenantDepartmentChildrenListOutputSLZ

@swagger_auto_schema(
Expand All @@ -204,6 +207,7 @@ def get(self, request, *args, **kwargs):
class TenantUserListApi(CurrentUserTenantMixin, generics.ListAPIView):
queryset = TenantUser.objects.all()
lookup_url_kwarg = "id"
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]
serializer_class = TenantUserListOutputSLZ

def get_tenant_user_ids(self, tenant_id):
Expand Down
53 changes: 14 additions & 39 deletions src/bk-user/bkuser/apis/web/personal_center/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from drf_yasg.utils import swagger_auto_schema
from rest_framework import generics, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from bkuser.apis.web.personal_center.serializers import (
Expand All @@ -20,15 +21,17 @@
TenantUserEmailUpdateInputSLZ,
TenantUserPhoneUpdateInputSLZ,
)
from bkuser.apps.permission.constants import PermAction
from bkuser.apps.permission.permissions import perm_class
from bkuser.apps.tenant.models import TenantUser
from bkuser.biz.natural_user import NatureUserHandler
from bkuser.biz.tenant import TenantUserEmailInfo, TenantUserHandler, TenantUserPhoneInfo
from bkuser.common.error_codes import error_codes
from bkuser.common.views import ExcludePutAPIViewMixin


class NaturalUserTenantUserListApi(generics.ListAPIView):
pagination_class = None
permission_classes = [IsAuthenticated, perm_class(PermAction.USE_PLATFORM)]

@swagger_auto_schema(
tags=["personal_center"],
Expand Down Expand Up @@ -70,6 +73,7 @@ def get(self, request, *args, **kwargs):
class TenantUserRetrieveApi(generics.RetrieveAPIView):
queryset = TenantUser.objects.all()
lookup_url_kwarg = "id"
permission_classes = [IsAuthenticated, perm_class(PermAction.USE_PLATFORM)]
serializer_class = PersonalCenterTenantUserRetrieveOutputSLZ

@swagger_auto_schema(
Expand All @@ -78,22 +82,13 @@ class TenantUserRetrieveApi(generics.RetrieveAPIView):
responses={status.HTTP_200_OK: PersonalCenterTenantUserRetrieveOutputSLZ()},
)
def get(self, request, *args, **kwargs):
instance: TenantUser = self.get_object()

# 获取当前登录的租户用户的自然人
nature_user = NatureUserHandler.get_nature_user_by_tenant_user_id(request.user.username)

# 边界限制
# 该租户用户的数据源用户,不属于当前自然人
if instance.data_source_user_id not in nature_user.data_source_user_ids:
raise error_codes.NO_PERMISSION

return Response(PersonalCenterTenantUserRetrieveOutputSLZ(instance).data)
return Response(PersonalCenterTenantUserRetrieveOutputSLZ(self.get_object()).data)


class TenantUserPhoneUpdateApi(ExcludePutAPIViewMixin, generics.UpdateAPIView):
queryset = TenantUser.objects.all()
lookup_url_kwarg = "id"
permission_classes = [IsAuthenticated, perm_class(PermAction.USE_PLATFORM)]

@swagger_auto_schema(
tags=["personal_center"],
Expand All @@ -102,33 +97,23 @@ class TenantUserPhoneUpdateApi(ExcludePutAPIViewMixin, generics.UpdateAPIView):
responses={status.HTTP_200_OK: ""},
)
def patch(self, request, *args, **kwargs):
instance: TenantUser = self.get_object()

# 获取当前登录的租户用户的自然人
nature_user = NatureUserHandler.get_nature_user_by_tenant_user_id(request.user.username)

# 边界限制
# 该租户用户的数据源用户,不属于当前自然人
if instance.data_source_user_id not in nature_user.data_source_user_ids:
raise error_codes.NO_PERMISSION

slz = TenantUserPhoneUpdateInputSLZ(data=request.data)
slz.is_valid(raise_exception=True)

data = slz.validated_data

phone_info = TenantUserPhoneInfo(
is_inherited_phone=data["is_inherited_phone"],
custom_phone=data.get("custom_phone", ""),
custom_phone_country_code=data["custom_phone_country_code"],
)
TenantUserHandler.update_tenant_user_phone(instance, phone_info)

TenantUserHandler.update_tenant_user_phone(self.get_object(), phone_info)
return Response()


class TenantUserEmailUpdateApi(ExcludePutAPIViewMixin, generics.UpdateAPIView):
queryset = TenantUser.objects.all()
lookup_url_kwarg = "id"
permission_classes = [IsAuthenticated, perm_class(PermAction.USE_PLATFORM)]

@swagger_auto_schema(
tags=["personal_center"],
Expand All @@ -137,23 +122,13 @@ class TenantUserEmailUpdateApi(ExcludePutAPIViewMixin, generics.UpdateAPIView):
responses={status.HTTP_200_OK: ""},
)
def patch(self, request, *args, **kwargs):
instance: TenantUser = self.get_object()

# 获取当前登录的租户用户的自然人
nature_user = NatureUserHandler.get_nature_user_by_tenant_user_id(request.user.username)

# 边界限制
# 该租户用户的数据源用户,不属于当前自然人下的
if instance.data_source_user_id not in nature_user.data_source_user_ids:
raise error_codes.NO_PERMISSION

slz = TenantUserEmailUpdateInputSLZ(data=request.data)
slz.is_valid(raise_exception=True)

data = slz.validated_data

email_info = TenantUserEmailInfo(
is_inherited_email=data["is_inherited_email"], custom_email=data.get("custom_email", "")
is_inherited_email=data["is_inherited_email"],
custom_email=data.get("custom_email", ""),
)
TenantUserHandler.update_tenant_user_email(instance, email_info)

TenantUserHandler.update_tenant_user_email(self.get_object(), email_info)
return Response()
Loading

0 comments on commit 049be01

Please sign in to comment.