diff --git a/src/api/bkuser_core/audit/constants.py b/src/api/bkuser_core/audit/constants.py index e50e9efe5..50c0dac77 100644 --- a/src/api/bkuser_core/audit/constants.py +++ b/src/api/bkuser_core/audit/constants.py @@ -44,6 +44,10 @@ class OperationType(AutoLowerEnum): EXPORT = auto() RESTORATION = auto() + FORGET_PASSWORD = auto() # 用户通过 token 重置 + ADMIN_RESET_PASSWORD = auto() # 管理员重置密码 + MODIFY_PASSWORD = auto() # 用户通过旧密码修改 + _choices_labels = ( (CREATE, "创建"), (UPDATE, "更新"), @@ -53,6 +57,9 @@ class OperationType(AutoLowerEnum): (EXPORT, "导出"), (IMPORT, "导入"), (RESTORATION, "恢复"), + (FORGET_PASSWORD, "用户通过token重置密码"), + (ADMIN_RESET_PASSWORD, "管理员重置密码"), + (MODIFY_PASSWORD, "用户通过旧密码修改"), ) diff --git a/src/api/bkuser_core/profiles/v2/views.py b/src/api/bkuser_core/profiles/v2/views.py index 6b6451135..c83068de6 100644 --- a/src/api/bkuser_core/profiles/v2/views.py +++ b/src/api/bkuser_core/profiles/v2/views.py @@ -23,7 +23,7 @@ ) from bkuser_core.apis.v2.viewset import AdvancedBatchOperateViewSet, AdvancedListAPIView, AdvancedModelViewSet from bkuser_core.audit.constants import LogInFailReason, OperationType -from bkuser_core.audit.utils import audit_general_log, create_profile_log +from bkuser_core.audit.utils import audit_general_log, create_general_log, create_profile_log from bkuser_core.categories.constants import CategoryType from bkuser_core.categories.loader import get_plugin_by_category from bkuser_core.categories.models import ProfileCategory @@ -75,7 +75,6 @@ class ProfileViewSet(AdvancedModelViewSet, AdvancedListAPIView): serializer_class = local_serializers.ProfileSerializer lookup_field = "username" filter_backends = [ProfileSearchFilter, filters.OrderingFilter] - relation_fields = ["departments", "leader", "login_set"] def get_object(self): @@ -287,13 +286,13 @@ def create(self, request, *args, **kwargs): ) return Response(self.serializer_class(instance).data, status=status.HTTP_201_CREATED) - @audit_general_log(OperationType.UPDATE.value) @method_decorator(clear_cache_if_succeed) def _update(self, request, partial): instance = self.get_object() serializer = local_serializers.UpdateProfileSerializer(instance, data=request.data, partial=partial) serializer.is_valid(raise_exception=True) validated_data = serializer.validated_data + operate_type = OperationType.UPDATE.value # 只允许本地目录修改 if not ProfileCategory.objects.check_writable(instance.category_id): @@ -320,6 +319,12 @@ def _update(self, request, partial): update_summary = {"request": request} # 密码修改加密 if validated_data.get("password"): + operate_type = ( + OperationType.FORGET_PASSWORD.value + if request.headers.get("User-From-Token") + else OperationType.ADMIN_RESET_PASSWORD.value + ) + pending_password = validated_data.get("password") config_loader = ConfigProvider(category_id=instance.category_id) try: @@ -362,6 +367,13 @@ def _update(self, request, partial): operator=request.operator, extra_values=update_summary, ) + + create_general_log( + operator=request.operator, + operate_type=operate_type, + operator_obj=instance, + request=request, + ) return Response(self.serializer_class(instance).data) @swagger_auto_schema( @@ -389,6 +401,7 @@ def destroy(self, request, *args, **kwargs): """ return super().destroy(request, *args, **kwargs) + @audit_general_log(operate_type=OperationType.MODIFY_PASSWORD.value) @swagger_auto_schema( query_serializer=AdvancedRetrieveSerialzier(), request_body=local_serializers.ProfileModifyPasswordSerializer, diff --git a/src/api/bkuser_core/user_settings/constants.py b/src/api/bkuser_core/user_settings/constants.py index 96d00c81f..137473515 100644 --- a/src/api/bkuser_core/user_settings/constants.py +++ b/src/api/bkuser_core/user_settings/constants.py @@ -23,7 +23,7 @@ class SettingsEnableNamespaces(AutoLowerEnum): (GENERAL, "通用"), (PASSWORD, "密码"), (CONNECTION, "连接"), - (FIELDS, "连接"), + (FIELDS, "字段"), ) diff --git a/src/saas/bkuser_shell/apis/viewset.py b/src/saas/bkuser_shell/apis/viewset.py index ecb67a020..2e56a2892 100644 --- a/src/saas/bkuser_shell/apis/viewset.py +++ b/src/saas/bkuser_shell/apis/viewset.py @@ -73,7 +73,12 @@ def get_client_ip(request) -> Optional[str]: return ip - def _prepare_headers(self, request, force_action_id: str = "", no_auth: bool = False): + def _prepare_headers( + self, request, + force_action_id: str = "", + no_auth: bool = False, + user_from_token: bool = False + ): """构建通用 Headers""" headers = make_default_headers(request.user.username) ip = self.get_client_ip(request) @@ -90,12 +95,24 @@ def _prepare_headers(self, request, force_action_id: str = "", no_auth: bool = F settings.API_FORCE_NO_CACHE_HEADER_NAME: True, } ) + if user_from_token: + headers.update( + { + 'user_from_token': True, + } + ) return headers - def get_api_client_by_request(self, request, force_action_id: str = "", no_auth: bool = False): + def get_api_client_by_request( + self, + request, + force_action_id: str = "", + no_auth: bool = False, + user_from_token: bool = False + ): """从 request 中获取 api client""" - return get_api_client(self._prepare_headers(request, force_action_id, no_auth)) + return get_api_client(self._prepare_headers(request, force_action_id, no_auth, user_from_token)) @staticmethod def get_paging_results(list_func: Callable, page_size: int = 50, **kwargs) -> list: diff --git a/src/saas/bkuser_shell/audit/constants.py b/src/saas/bkuser_shell/audit/constants.py index 802555bde..9ef1b6752 100644 --- a/src/saas/bkuser_shell/audit/constants.py +++ b/src/saas/bkuser_shell/audit/constants.py @@ -32,6 +32,16 @@ ("export", _("导出")), ("import", _("导入")), ("restoration", _("恢复")), + ("forget_password", _("用户通过token重置密码")), + ("admin_reset_password", _("管理员重置密码")), + ("modify_password", _("用户通过旧密码修改")) + +) + +OPERATION_ABOUT_PASSWORD = ( + "forget_password", # 用户通过 token 重置密码 + "admin_reset_password", # 管理员重置密码 + "modify_password" # 用户通过旧密码修改 ) OPERATION_NAME_MAP = {x[0]: x[1] for x in OPERATION_NAME_TUPLE} diff --git a/src/saas/bkuser_shell/audit/serializers.py b/src/saas/bkuser_shell/audit/serializers.py index 32c374679..7936ffb07 100644 --- a/src/saas/bkuser_shell/audit/serializers.py +++ b/src/saas/bkuser_shell/audit/serializers.py @@ -14,7 +14,7 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers -from .constants import LOGIN_FAILED_REASON_MAP, OPERATION_NAME_MAP, OPERATION_OBJ_NAME_MAP +from .constants import LOGIN_FAILED_REASON_MAP, OPERATION_ABOUT_PASSWORD, OPERATION_NAME_MAP, OPERATION_OBJ_NAME_MAP PLACE_HOLDER = "--" @@ -48,7 +48,8 @@ def to_representation(self, instance): extra_value = instance["extra_value"] categories = self.context.get("categories") instance["target_obj"] = f"{extra_value['display_name']}<{extra_value['key']}>" - instance["operation"] = ( + instance["operation"] = f"{OPERATION_NAME_MAP[extra_value['operation']]}" \ + if extra_value['operation'] in OPERATION_ABOUT_PASSWORD else( f"{OPERATION_NAME_MAP[extra_value['operation']]}" f"{OPERATION_OBJ_NAME_MAP[extra_value.get('obj_type')]}" ) diff --git a/src/saas/bkuser_shell/password/views.py b/src/saas/bkuser_shell/password/views.py index 331a295aa..77f35ae3a 100644 --- a/src/saas/bkuser_shell/password/views.py +++ b/src/saas/bkuser_shell/password/views.py @@ -57,7 +57,7 @@ def reset_by_token(self, request, validated_data): # 由于该接口无登录态,我们只能认为访问该链接的人即用户所有者 request.user.username = profile.username - profiles_api_instance = bkuser_sdk.ProfilesApi(self.get_api_client_by_request(request)) + profiles_api_instance = bkuser_sdk.ProfilesApi(self.get_api_client_by_request(request, user_from_token=True)) body = {"password": password} # 调用后台接口重置密码 diff --git a/src/sdk/bkuser_sdk/api/profiles_api.py b/src/sdk/bkuser_sdk/api/profiles_api.py index 014f380b2..de807f042 100644 --- a/src/sdk/bkuser_sdk/api/profiles_api.py +++ b/src/sdk/bkuser_sdk/api/profiles_api.py @@ -6,7 +6,7 @@ 蓝鲸用户管理后台服务 API # noqa: E501 OpenAPI spec version: v2 - + Generated by: https://github.com/swagger-api/swagger-codegen.git """