diff --git a/apollo-audit/apollo-audit-impl/src/main/java/com/ctrip/framework/apollo/audit/aop/ApolloAuditSpanAspect.java b/apollo-audit/apollo-audit-impl/src/main/java/com/ctrip/framework/apollo/audit/aop/ApolloAuditSpanAspect.java index 535a07dfda6..054d637139b 100644 --- a/apollo-audit/apollo-audit-impl/src/main/java/com/ctrip/framework/apollo/audit/aop/ApolloAuditSpanAspect.java +++ b/apollo-audit/apollo-audit-impl/src/main/java/com/ctrip/framework/apollo/audit/aop/ApolloAuditSpanAspect.java @@ -21,16 +21,16 @@ import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLogDataInfluenceTable; import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLogDataInfluenceTableField; import com.ctrip.framework.apollo.audit.api.ApolloAuditLogApi; +import com.ctrip.framework.apollo.audit.constants.ApolloAuditConstants; import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Objects; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; @Aspect public class ApolloAuditSpanAspect { @@ -48,40 +48,46 @@ public void setAuditSpan(ApolloAuditLog auditLog) { @Around(value = "setAuditSpan(auditLog)") public Object around(ProceedingJoinPoint pjp, ApolloAuditLog auditLog) throws Throwable { String opName = auditLog.name(); - if (opName.equals("") && RequestContextHolder.getRequestAttributes() != null) { - ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); - opName = servletRequestAttributes.getRequest().getRequestURI(); - } - try (AutoCloseable scope = api.appendAuditLog(auditLog.type(), opName, auditLog.description())) { - Object[] args = pjp.getArgs(); - Method method = findMethod(pjp.getTarget().getClass(), pjp.getSignature().getName()); - for (int i = 0; i < args.length; i++) { - Object arg = args[i]; - Annotation[] annotations = method.getParameterAnnotations()[i]; - if (Arrays.stream(annotations).anyMatch(anno -> anno instanceof ApolloAuditLogDataInfluence)) { - String entityName = null; - String fieldName = null; - for(int j = 0; j < annotations.length; j++) { - if(annotations[j] instanceof ApolloAuditLogDataInfluenceTable) { - entityName = ((ApolloAuditLogDataInfluenceTable) annotations[j]).tableName(); - } - if(annotations[j] instanceof ApolloAuditLogDataInfluenceTableField) { - fieldName = ((ApolloAuditLogDataInfluenceTableField) annotations[j]).fieldName(); - } - } - if (entityName != null && fieldName != null) { - String matchedValue = String.valueOf(arg); - api.appendDataInfluence("AnyMatched", entityName, fieldName, matchedValue); - } + Object proceed = pjp.proceed(); + auditDataInfluenceArg(pjp); + return proceed; + } + } + + void auditDataInfluenceArg(ProceedingJoinPoint pjp) { + Method method = findMethod(pjp); + Object[] args = pjp.getArgs(); + for (int i = 0; i < args.length; i++) { + Object arg = args[i]; + Annotation[] annotations = method.getParameterAnnotations()[i]; + + boolean needAudit = false; + String entityName = null; + String fieldName = null; + + for (Annotation annotation : annotations) { + if (annotation instanceof ApolloAuditLogDataInfluence) { + needAudit = true; + } + if (annotation instanceof ApolloAuditLogDataInfluenceTable) { + entityName = ((ApolloAuditLogDataInfluenceTable) annotation).tableName(); } + if (annotation instanceof ApolloAuditLogDataInfluenceTableField) { + fieldName = ((ApolloAuditLogDataInfluenceTableField) annotation).fieldName(); + } + } + + if (needAudit) { + parseArgAndAppend(entityName, fieldName, arg); } - return pjp.proceed(); } } - Method findMethod(Class clazz, String methodName) { + Method findMethod(ProceedingJoinPoint pjp) { + Class clazz = pjp.getTarget().getClass(); + String methodName = pjp.getSignature().getName(); for (Method method : clazz.getDeclaredMethods()) { if (method.getName().equals(methodName)) { return method; @@ -90,4 +96,19 @@ Method findMethod(Class clazz, String methodName) { return null; } + void parseArgAndAppend(String entityName, String fieldName, Object arg) { + if (entityName == null || fieldName == null || arg == null) { + return; + } + + if (arg instanceof Collection) { + for (Object o : (Collection) arg) { + String matchedValue = String.valueOf(o); + api.appendDataInfluence(entityName, ApolloAuditConstants.ANY_MATCHED_ID, fieldName, matchedValue); + } + } else { + String matchedValue = String.valueOf(arg); + api.appendDataInfluence(entityName, ApolloAuditConstants.ANY_MATCHED_ID, fieldName, matchedValue); + } + } } diff --git a/apollo-audit/apollo-audit-impl/src/main/java/com/ctrip/framework/apollo/audit/component/ApolloAuditLogApiJpaImpl.java b/apollo-audit/apollo-audit-impl/src/main/java/com/ctrip/framework/apollo/audit/component/ApolloAuditLogApiJpaImpl.java index d7c1baab2a4..742fe593222 100644 --- a/apollo-audit/apollo-audit-impl/src/main/java/com/ctrip/framework/apollo/audit/component/ApolloAuditLogApiJpaImpl.java +++ b/apollo-audit/apollo-audit-impl/src/main/java/com/ctrip/framework/apollo/audit/component/ApolloAuditLogApiJpaImpl.java @@ -78,6 +78,9 @@ public void appendDataInfluence(String entityName, String entityId, String field OpType type = traceContext.tracer().getActiveSpan().getOpType(); ApolloAuditLogDataInfluence.Builder builder = ApolloAuditLogDataInfluence.builder().spanId(spanId) .entityName(entityName).entityId(entityId).fieldName(fieldName); + if (type == null) { + return; + } switch (type) { case CREATE: case UPDATE: @@ -106,7 +109,7 @@ public void appendDataInfluences(List entities, Class beanDefinition) f.setAccessible(true); String val = String.valueOf(f.get(e)); String fieldName = f.getAnnotation(ApolloAuditLogDataInfluenceTableField.class).fieldName(); - appendDataInfluence(tableId, tableName, fieldName, val); + appendDataInfluence(tableName, tableId, fieldName, val); } } catch (IllegalAccessException ex) { throw new IllegalArgumentException("failed append data influence, " diff --git a/apollo-audit/apollo-audit-impl/src/main/java/com/ctrip/framework/apollo/audit/constants/ApolloAuditConstants.java b/apollo-audit/apollo-audit-impl/src/main/java/com/ctrip/framework/apollo/audit/constants/ApolloAuditConstants.java index 602dbd1bff1..1c0b0c75ec4 100644 --- a/apollo-audit/apollo-audit-impl/src/main/java/com/ctrip/framework/apollo/audit/constants/ApolloAuditConstants.java +++ b/apollo-audit/apollo-audit-impl/src/main/java/com/ctrip/framework/apollo/audit/constants/ApolloAuditConstants.java @@ -24,4 +24,6 @@ public interface ApolloAuditConstants { String FOLLOWS_FROM_ID = "Apollo-Audit-FollowsFromId"; String TRACER = "Apollo-Audit-Tracer"; + + String ANY_MATCHED_ID = "AnyMatched"; } diff --git a/apollo-audit/apollo-audit-impl/src/test/java/com/ctrip/framework/apollo/audit/aop/ApolloAuditSpanAspectTest.java b/apollo-audit/apollo-audit-impl/src/test/java/com/ctrip/framework/apollo/audit/aop/ApolloAuditSpanAspectTest.java new file mode 100644 index 00000000000..303a4f07df3 --- /dev/null +++ b/apollo-audit/apollo-audit-impl/src/test/java/com/ctrip/framework/apollo/audit/aop/ApolloAuditSpanAspectTest.java @@ -0,0 +1,159 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.audit.aop; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLog; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLogDataInfluence; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLogDataInfluenceTable; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLogDataInfluenceTableField; +import com.ctrip.framework.apollo.audit.annotation.OpType; +import com.ctrip.framework.apollo.audit.api.ApolloAuditLogApi; +import com.ctrip.framework.apollo.audit.constants.ApolloAuditConstants; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@ContextConfiguration(classes = ApolloAuditSpanAspect.class) +public class ApolloAuditSpanAspectTest { + + @SpyBean + ApolloAuditSpanAspect aspect; + + @MockBean + ApolloAuditLogApi api; + + @Test + public void testAround() throws Throwable { + final OpType opType = OpType.CREATE; + final String opName = "App.create"; + final String description = "no description"; + + ProceedingJoinPoint mockPJP = mock(ProceedingJoinPoint.class); + ApolloAuditLog mockAnnotation = mock(ApolloAuditLog.class); + AutoCloseable mockScope = mock(AutoCloseable.class); + { + when(mockAnnotation.type()).thenReturn(opType); + when(mockAnnotation.name()).thenReturn(opName); + when(mockAnnotation.description()).thenReturn(description); + when(api.appendAuditLog(eq(opType), eq(opName), eq(description))) + .thenReturn(mockScope); + doNothing().when(aspect).auditDataInfluenceArg(mockPJP); + } + + aspect.around(mockPJP, mockAnnotation); + verify(api, times(1)) + .appendAuditLog(eq(opType), eq(opName), eq(description)); + verify(mockScope, times(1)) + .close(); + verify(aspect, times(1)) + .auditDataInfluenceArg(eq(mockPJP)); + } + + @Test + public void testAuditDataInfluenceArg() throws NoSuchMethodException { + ProceedingJoinPoint mockPJP = mock(ProceedingJoinPoint.class); + Object[] args = new Object[]{new Object(), new Object()}; + Method method = MockAuditClass.class.getMethod("mockAuditMethod", Object.class, Object.class); + { + doReturn(method).when(aspect).findMethod(any()); + when(mockPJP.getArgs()).thenReturn(args); + } + aspect.auditDataInfluenceArg(mockPJP); + verify(aspect, times(1)) + .parseArgAndAppend(eq("App"), eq("Name"), eq(args[0])); + } + + @Test + public void testFindMethod() throws NoSuchMethodException { + ProceedingJoinPoint mockPJP = mock(ProceedingJoinPoint.class); + MockAuditClass mockAuditClass = new MockAuditClass(); + Signature signature = mock(Signature.class); + Method method = MockAuditClass.class.getMethod("mockAuditMethod", Object.class, Object.class); + { + when(mockPJP.getTarget()).thenReturn(mockAuditClass); + when(mockPJP.getSignature()).thenReturn(signature); + when(signature.getName()).thenReturn("mockAuditMethod"); + } + Method methodFounded = aspect.findMethod(mockPJP); + + assertEquals(method, methodFounded); + } + + @Test + public void testParseArgAndAppendCaseNullName() { + Object somewhat = new Object(); + aspect.parseArgAndAppend(null, null, somewhat); + verify(api, times(0)) + .appendDataInfluence(any(), any(), any(), any()); + } + + @Test + public void testParseArgAndAppendCaseCollectionTypeArg() { + final String entityName = "App"; + final String fieldName = "Name"; + List list = Arrays.asList(new Object(), new Object(), new Object()); + + { + doNothing().when(api).appendDataInfluence(any(), any(), any(), any()); + } + aspect.parseArgAndAppend(entityName, fieldName, list); + verify(api, times(list.size())).appendDataInfluence(eq(entityName), + eq(ApolloAuditConstants.ANY_MATCHED_ID), eq(fieldName), any()); + } + + @Test + public void testParseArgAndAppendCaseNormalTypeArg() { + final String entityName = "App"; + final String fieldName = "Name"; + Object arg = new Object(); + + { + doNothing().when(api).appendDataInfluence(any(), any(), any(), any()); + } + aspect.parseArgAndAppend(entityName, fieldName, arg); + verify(api, times(1)).appendDataInfluence(eq(entityName), + eq(ApolloAuditConstants.ANY_MATCHED_ID), eq(fieldName), any()); + } + + public class MockAuditClass { + + public void mockAuditMethod( + @ApolloAuditLogDataInfluence + @ApolloAuditLogDataInfluenceTable(tableName = "App") + @ApolloAuditLogDataInfluenceTableField(fieldName = "Name") Object val1, + Object val2) { + } + } +} diff --git a/apollo-audit/apollo-audit-impl/src/test/java/com/ctrip/framework/apollo/audit/component/ApolloAuditLogApiJpaImplTest.java b/apollo-audit/apollo-audit-impl/src/test/java/com/ctrip/framework/apollo/audit/component/ApolloAuditLogApiJpaImplTest.java index f1ddd8e8f30..728b9689712 100644 --- a/apollo-audit/apollo-audit-impl/src/test/java/com/ctrip/framework/apollo/audit/component/ApolloAuditLogApiJpaImplTest.java +++ b/apollo-audit/apollo-audit-impl/src/test/java/com/ctrip/framework/apollo/audit/component/ApolloAuditLogApiJpaImplTest.java @@ -185,7 +185,7 @@ public void testAppendDataInfluences() { api.appendDataInfluences(entities, MockDataInfluenceEntity.class); Mockito.verify(api, Mockito.times(entityNum)) - .appendDataInfluence(Mockito.anyString(), Mockito.eq("MockTableName"), Mockito.eq("MarkedAttribute"), + .appendDataInfluence(Mockito.eq("MockTableName"), Mockito.any(), Mockito.eq("MarkedAttribute"), Mockito.any()); } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/AppNamespaceService.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/AppNamespaceService.java index 66d7bb63b08..27a16ed326d 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/AppNamespaceService.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/AppNamespaceService.java @@ -16,6 +16,8 @@ */ package com.ctrip.framework.apollo.biz.service; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLog; +import com.ctrip.framework.apollo.audit.annotation.OpType; import com.ctrip.framework.apollo.biz.entity.Audit; import com.ctrip.framework.apollo.biz.entity.Cluster; import com.ctrip.framework.apollo.biz.entity.Namespace; @@ -102,6 +104,7 @@ public List findByAppIdAndNamespaces(String appId, Set nam } @Transactional + @ApolloAuditLog(type = OpType.CREATE, name = "AppNamespace.createDefault") public void createDefaultAppNamespace(String appId, String createBy) { if (!isAppNamespaceNameUnique(appId, ConfigConsts.NAMESPACE_APPLICATION)) { throw new ServiceException("appnamespace not unique"); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/api/AdminServiceAPI.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/api/AdminServiceAPI.java index fcd46a32fa1..aecc4fe07a8 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/api/AdminServiceAPI.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/api/AdminServiceAPI.java @@ -118,17 +118,20 @@ public NamespaceDTO findPublicNamespaceForAssociatedNamespace(Env env, String ap NamespaceDTO.class, appId, clusterName, namespaceName); } + @ApolloAuditLog(type = OpType.RPC, name = "Namespace.createInRemote") public NamespaceDTO createNamespace(Env env, NamespaceDTO namespace) { return restTemplate .post(env, "apps/{appId}/clusters/{clusterName}/namespaces", namespace, NamespaceDTO.class, namespace.getAppId(), namespace.getClusterName()); } + @ApolloAuditLog(type = OpType.RPC, name = "AppNamespace.createInRemote") public AppNamespaceDTO createAppNamespace(Env env, AppNamespaceDTO appNamespace) { return restTemplate .post(env, "apps/{appId}/appnamespaces", appNamespace, AppNamespaceDTO.class, appNamespace.getAppId()); } + @ApolloAuditLog(type = OpType.RPC, name = "AppNamespace.createMissingAppNamespaceInRemote") public AppNamespaceDTO createMissingAppNamespace(Env env, AppNamespaceDTO appNamespace) { return restTemplate .post(env, "apps/{appId}/appnamespaces?silentCreation=true", appNamespace, AppNamespaceDTO.class, @@ -140,6 +143,7 @@ public List getAppNamespaces(String appId, Env env) { return Arrays.asList(appNamespaceDTOs); } + @ApolloAuditLog(type = OpType.RPC, name = "Namespace.deleteInRemote") public void deleteNamespace(Env env, String appId, String clusterName, String namespaceName, String operator) { restTemplate .delete(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}?operator={operator}", appId, @@ -167,6 +171,7 @@ public int countPublicAppNamespaceAssociatedNamespaces(Env env, String publicNam return count == null ? 0 : count; } + @ApolloAuditLog(type = OpType.RPC, name = "AppNamespace.deleteInRemote") public void deleteAppNamespace(Env env, String appId, String namespaceName, String operator) { restTemplate.delete(env, "/apps/{appId}/appnamespaces/{namespaceName}?operator={operator}", appId, namespaceName, operator); @@ -266,12 +271,13 @@ public boolean isClusterUnique(String appId, Env env, String clusterName) { } + @ApolloAuditLog(type = OpType.RPC, name = "Cluster.createInRemote") public ClusterDTO create(Env env, ClusterDTO cluster) { return restTemplate.post(env, "apps/{appId}/clusters", cluster, ClusterDTO.class, cluster.getAppId()); } - + @ApolloAuditLog(type = OpType.RPC, name = "Cluster.deleteInRemote") public void delete(Env env, String appId, String clusterName, String operator) { restTemplate.delete(env, "apps/{appId}/clusters/{clusterName}?operator={operator}", appId, clusterName, operator); } @@ -280,6 +286,7 @@ public void delete(Env env, String appId, String clusterName, String operator) { @Service public static class AccessKeyAPI extends API { + @ApolloAuditLog(type = OpType.RPC, name = "AccessKey.createInRemote") public AccessKeyDTO create(Env env, AccessKeyDTO accessKey) { return restTemplate.post(env, "apps/{appId}/accesskeys", accessKey, AccessKeyDTO.class, accessKey.getAppId()); @@ -291,16 +298,19 @@ public List findByAppId(Env env, String appId) { return Arrays.asList(accessKeys); } + @ApolloAuditLog(type = OpType.RPC, name = "AccessKey.deleteInRemote") public void delete(Env env, String appId, long id, String operator) { restTemplate.delete(env, "apps/{appId}/accesskeys/{id}?operator={operator}", appId, id, operator); } + @ApolloAuditLog(type = OpType.RPC, name = "AccessKey.enableInRemote") public void enable(Env env, String appId, long id, String operator) { restTemplate.put(env, "apps/{appId}/accesskeys/{id}/enable?operator={operator}", null, appId, id, operator); } + @ApolloAuditLog(type = OpType.RPC, name = "AccessKey.disableInRemote") public void disable(Env env, String appId, long id, String operator) { restTemplate.put(env, "apps/{appId}/accesskeys/{id}/disable?operator={operator}", null, appId, id, operator); @@ -513,6 +523,7 @@ public int getInstanceCountByNamespace(String appId, Env env, String clusterName @Service public static class NamespaceBranchAPI extends API { + @ApolloAuditLog(type = OpType.RPC, name = "NamespaceBranch.createInRemote") public NamespaceDTO createBranch(String appId, Env env, String clusterName, String namespaceName, String operator) { return restTemplate @@ -534,6 +545,7 @@ public GrayReleaseRuleDTO findBranchGrayRules(String appId, Env env, String clus } + @ApolloAuditLog(type = OpType.RPC, name = "NamespaceBranch.updateInRemote") public void updateBranchGrayRules(String appId, Env env, String clusterName, String namespaceName, String branchName, GrayReleaseRuleDTO rules) { restTemplate @@ -542,6 +554,7 @@ public void updateBranchGrayRules(String appId, Env env, String clusterName, } + @ApolloAuditLog(type = OpType.RPC, name = "NamespaceBranch.deleteInRemote") public void deleteBranch(String appId, Env env, String clusterName, String namespaceName, String branchName, String operator) { restTemplate.delete(env, @@ -587,6 +600,7 @@ public List findAllConfigDBConfig(Env env){ }).getBody(); } + @ApolloAuditLog(type = OpType.RPC, name = "ServerConfig.createOrUpdateConfigDBConfigInRemote") public ServerConfig createOrUpdateConfigDBConfig(Env env, ServerConfig serverConfig){ return restTemplate.post(env, "/server/config", serverConfig, ServerConfig.class); } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/AccessKeyController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/AccessKeyController.java index 127cd063f82..1e764b3b353 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/AccessKeyController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/AccessKeyController.java @@ -16,6 +16,8 @@ */ package com.ctrip.framework.apollo.portal.controller; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLog; +import com.ctrip.framework.apollo.audit.annotation.OpType; import com.ctrip.framework.apollo.common.dto.AccessKeyDTO; import com.ctrip.framework.apollo.portal.environment.Env; import com.ctrip.framework.apollo.portal.service.AccessKeyService; @@ -44,6 +46,7 @@ public AccessKeyController( @PreAuthorize(value = "@permissionValidator.isAppAdmin(#appId)") @PostMapping(value = "/apps/{appId}/envs/{env}/accesskeys") + @ApolloAuditLog(type = OpType.CREATE, name = "AccessKey.create") public AccessKeyDTO save(@PathVariable String appId, @PathVariable String env, @RequestBody AccessKeyDTO accessKeyDTO) { String secret = UUID.randomUUID().toString().replaceAll("-", ""); @@ -61,6 +64,7 @@ public List findByAppId(@PathVariable String appId, @PreAuthorize(value = "@permissionValidator.isAppAdmin(#appId)") @DeleteMapping(value = "/apps/{appId}/envs/{env}/accesskeys/{id}") + @ApolloAuditLog(type = OpType.DELETE, name = "AccessKey.delete") public void delete(@PathVariable String appId, @PathVariable String env, @PathVariable long id) { @@ -70,6 +74,7 @@ public void delete(@PathVariable String appId, @PreAuthorize(value = "@permissionValidator.isAppAdmin(#appId)") @PutMapping(value = "/apps/{appId}/envs/{env}/accesskeys/{id}/enable") + @ApolloAuditLog(type = OpType.UPDATE, name = "AccessKey.enable") public void enable(@PathVariable String appId, @PathVariable String env, @PathVariable long id) { @@ -79,6 +84,7 @@ public void enable(@PathVariable String appId, @PreAuthorize(value = "@permissionValidator.isAppAdmin(#appId)") @PutMapping(value = "/apps/{appId}/envs/{env}/accesskeys/{id}/disable") + @ApolloAuditLog(type = OpType.UPDATE, name = "AccessKey.disable") public void disable(@PathVariable String appId, @PathVariable String env, @PathVariable long id) { diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/AppController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/AppController.java index 1a171b5bb50..4005f011acb 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/AppController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/AppController.java @@ -121,7 +121,7 @@ public List findAppsByOwner(@RequestParam("owner") String owner, Pageable p @PreAuthorize(value = "@permissionValidator.hasCreateApplicationPermission()") @PostMapping - @ApolloAuditLog(type = OpType.CREATE) + @ApolloAuditLog(type = OpType.CREATE, name = "App.create") public App create(@Valid @RequestBody AppModel appModel) { App app = transformToApp(appModel); @@ -130,7 +130,7 @@ public App create(@Valid @RequestBody AppModel appModel) { @PreAuthorize(value = "@permissionValidator.isAppAdmin(#appId)") @PutMapping("/{appId:.+}") - @ApolloAuditLog(type = OpType.UPDATE) + @ApolloAuditLog(type = OpType.UPDATE, name = "App.update") public void update(@PathVariable String appId, @Valid @RequestBody AppModel appModel) { if (!Objects.equals(appId, appModel.getAppId())) { throw new BadRequestException("The App Id of path variable and request body is different"); @@ -161,6 +161,7 @@ public MultiResponseEntity nav(@PathVariable String appId) { } @PostMapping(value = "/envs/{env}", consumes = {"application/json"}) + @ApolloAuditLog(type = OpType.CREATE, name = "App.create.forEnv") public ResponseEntity create(@PathVariable String env, @Valid @RequestBody App app) { appService.createAppInRemote(Env.valueOf(env), app); @@ -182,7 +183,7 @@ public AppDTO load(@PathVariable String appId) { @PreAuthorize(value = "@permissionValidator.isSuperAdmin()") @DeleteMapping("/{appId:.+}") - @ApolloAuditLog(type = OpType.RPC, name = "App.delete.request") + @ApolloAuditLog(type = OpType.RPC, name = "App.delete") public void deleteApp(@PathVariable String appId) { App app = appService.deleteAppInLocal(appId); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ClusterController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ClusterController.java index 27c2306509b..cc670ff49b0 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ClusterController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ClusterController.java @@ -16,6 +16,8 @@ */ package com.ctrip.framework.apollo.portal.controller; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLog; +import com.ctrip.framework.apollo.audit.annotation.OpType; import com.ctrip.framework.apollo.common.dto.ClusterDTO; import com.ctrip.framework.apollo.portal.environment.Env; import com.ctrip.framework.apollo.portal.service.ClusterService; @@ -44,6 +46,7 @@ public ClusterController(final ClusterService clusterService, final UserInfoHold @PreAuthorize(value = "@permissionValidator.hasCreateClusterPermission(#appId)") @PostMapping(value = "apps/{appId}/envs/{env}/clusters") + @ApolloAuditLog(type = OpType.CREATE, name = "Cluster.create") public ClusterDTO createCluster(@PathVariable String appId, @PathVariable String env, @Valid @RequestBody ClusterDTO cluster) { String operator = userInfoHolder.getUser().getUserId(); @@ -55,6 +58,7 @@ public ClusterDTO createCluster(@PathVariable String appId, @PathVariable String @PreAuthorize(value = "@permissionValidator.isSuperAdmin()") @DeleteMapping(value = "apps/{appId}/envs/{env}/clusters/{clusterName:.+}") + @ApolloAuditLog(type = OpType.DELETE, name = "Cluster.delete") public ResponseEntity deleteCluster(@PathVariable String appId, @PathVariable String env, @PathVariable String clusterName){ clusterService.deleteCluster(Env.valueOf(env), appId, clusterName); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/NamespaceBranchController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/NamespaceBranchController.java index 75adb257466..4afd9920b09 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/NamespaceBranchController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/NamespaceBranchController.java @@ -16,6 +16,8 @@ */ package com.ctrip.framework.apollo.portal.controller; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLog; +import com.ctrip.framework.apollo.audit.annotation.OpType; import com.ctrip.framework.apollo.common.dto.GrayReleaseRuleDTO; import com.ctrip.framework.apollo.common.dto.NamespaceDTO; import com.ctrip.framework.apollo.common.dto.ReleaseDTO; @@ -78,6 +80,7 @@ public NamespaceBO findBranch(@PathVariable String appId, @PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env)") @PostMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches") + @ApolloAuditLog(type = OpType.CREATE, name = "NamespaceBranch.create") public NamespaceDTO createBranch(@PathVariable String appId, @PathVariable String env, @PathVariable String clusterName, @@ -87,6 +90,7 @@ public NamespaceDTO createBranch(@PathVariable String appId, } @DeleteMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}") + @ApolloAuditLog(type = OpType.DELETE, name = "NamespaceBranch.delete") public void deleteBranch(@PathVariable String appId, @PathVariable String env, @PathVariable String clusterName, @@ -113,6 +117,7 @@ public void deleteBranch(@PathVariable String appId, @PreAuthorize(value = "@permissionValidator.hasReleaseNamespacePermission(#appId, #namespaceName, #env)") @PostMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/merge") + @ApolloAuditLog(type = OpType.UPDATE, name = "NamespaceBranch.merge") public ReleaseDTO merge(@PathVariable String appId, @PathVariable String env, @PathVariable String clusterName, @PathVariable String namespaceName, @PathVariable String branchName, @RequestParam(value = "deleteBranch", defaultValue = "true") boolean deleteBranch, @@ -152,6 +157,7 @@ public GrayReleaseRuleDTO getBranchGrayRules(@PathVariable String appId, @PathVa @PreAuthorize(value = "@permissionValidator.hasOperateNamespacePermission(#appId, #namespaceName, #env)") @PutMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/rules") + @ApolloAuditLog(type = OpType.UPDATE, name = "NamespaceBranch.updateBranchRules") public void updateBranchRules(@PathVariable String appId, @PathVariable String env, @PathVariable String clusterName, @PathVariable String namespaceName, @PathVariable String branchName, @RequestBody GrayReleaseRuleDTO rules) { diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/NamespaceController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/NamespaceController.java index c3bbbcadad8..6a29a2f5f0d 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/NamespaceController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/NamespaceController.java @@ -16,6 +16,8 @@ */ package com.ctrip.framework.apollo.portal.controller; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLog; +import com.ctrip.framework.apollo.audit.annotation.OpType; import com.ctrip.framework.apollo.common.dto.AppNamespaceDTO; import com.ctrip.framework.apollo.common.dto.NamespaceDTO; import com.ctrip.framework.apollo.common.entity.AppNamespace; @@ -141,6 +143,7 @@ public NamespaceBO findPublicNamespaceForAssociatedNamespace(@PathVariable Strin @PreAuthorize(value = "@permissionValidator.hasCreateNamespacePermission(#appId)") @PostMapping("/apps/{appId}/namespaces") + @ApolloAuditLog(type = OpType.CREATE, name = "Namespace.create") public ResponseEntity createNamespace(@PathVariable String appId, @RequestBody List models) { @@ -171,6 +174,7 @@ public ResponseEntity createNamespace(@PathVariable String appId, @PreAuthorize(value = "@permissionValidator.hasDeleteNamespacePermission(#appId)") @DeleteMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/linked-namespaces/{namespaceName:.+}") + @ApolloAuditLog(type = OpType.DELETE, name = "Namespace.deleteLinkedNamespace") public ResponseEntity deleteLinkedNamespace(@PathVariable String appId, @PathVariable String env, @PathVariable String clusterName, @PathVariable String namespaceName) { @@ -193,6 +197,7 @@ public List findNamespaceUsage(@PathVariable String appId, @Path @PreAuthorize(value = "@permissionValidator.hasDeleteNamespacePermission(#appId)") @DeleteMapping("/apps/{appId}/appnamespaces/{namespaceName:.+}") + @ApolloAuditLog(type = OpType.DELETE, name = "AppNamespace.delete") public ResponseEntity deleteAppNamespace(@PathVariable String appId, @PathVariable String namespaceName) { AppNamespace appNamespace = appNamespaceService.deleteAppNamespace(appId, namespaceName); @@ -215,6 +220,7 @@ public AppNamespaceDTO findAppNamespace(@PathVariable String appId, @PathVariabl @PreAuthorize(value = "@permissionValidator.hasCreateAppNamespacePermission(#appId, #appNamespace)") @PostMapping("/apps/{appId}/appnamespaces") + @ApolloAuditLog(type = OpType.CREATE, name = "AppNamespace.create") public AppNamespace createAppNamespace(@PathVariable String appId, @RequestParam(defaultValue = "true") boolean appendNamespacePrefix, @Valid @RequestBody AppNamespace appNamespace) { @@ -272,6 +278,7 @@ public MultiResponseEntity findMissingNamespaces(@PathVariable String ap } @PostMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/missing-namespaces") + @ApolloAuditLog(type = OpType.CREATE, name = "Namespace.createMissingNamespaces") public ResponseEntity createMissingNamespaces(@PathVariable String appId, @PathVariable String env, @PathVariable String clusterName) { Set missingNamespaces = findMissingNamespaceNames(appId, env, clusterName); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/PermissionController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/PermissionController.java index 9cb4eb54ca8..6ba5f5080af 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/PermissionController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/PermissionController.java @@ -16,6 +16,8 @@ */ package com.ctrip.framework.apollo.portal.controller; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLog; +import com.ctrip.framework.apollo.audit.annotation.OpType; import com.ctrip.framework.apollo.common.exception.BadRequestException; import com.ctrip.framework.apollo.common.utils.RequestPrecondition; import com.ctrip.framework.apollo.portal.component.PermissionValidator; @@ -148,6 +150,7 @@ public NamespaceEnvRolesAssignedUsers getNamespaceEnvRoles(@PathVariable String @PreAuthorize(value = "@permissionValidator.hasAssignRolePermission(#appId)") @PostMapping("/apps/{appId}/envs/{env}/namespaces/{namespaceName}/roles/{roleType}") + @ApolloAuditLog(type = OpType.CREATE, name = "Auth.assignNamespaceEnvRoleToUser") public ResponseEntity assignNamespaceEnvRoleToUser(@PathVariable String appId, @PathVariable String env, @PathVariable String namespaceName, @PathVariable String roleType, @RequestBody String user) { checkUserExists(user); @@ -172,6 +175,7 @@ public ResponseEntity assignNamespaceEnvRoleToUser(@PathVariable String ap @PreAuthorize(value = "@permissionValidator.hasAssignRolePermission(#appId)") @DeleteMapping("/apps/{appId}/envs/{env}/namespaces/{namespaceName}/roles/{roleType}") + @ApolloAuditLog(type = OpType.DELETE, name = "Auth.removeNamespaceEnvRoleFromUser") public ResponseEntity removeNamespaceEnvRoleFromUser(@PathVariable String appId, @PathVariable String env, @PathVariable String namespaceName, @PathVariable String roleType, @RequestParam String user) { RequestPrecondition.checkArgumentsNotEmpty(user); @@ -208,6 +212,7 @@ public NamespaceRolesAssignedUsers getNamespaceRoles(@PathVariable String appId, @PreAuthorize(value = "@permissionValidator.hasAssignRolePermission(#appId)") @PostMapping("/apps/{appId}/namespaces/{namespaceName}/roles/{roleType}") + @ApolloAuditLog(type = OpType.CREATE, name = "Auth.assignNamespaceRoleToUser") public ResponseEntity assignNamespaceRoleToUser(@PathVariable String appId, @PathVariable String namespaceName, @PathVariable String roleType, @RequestBody String user) { checkUserExists(user); @@ -227,6 +232,7 @@ public ResponseEntity assignNamespaceRoleToUser(@PathVariable String appId @PreAuthorize(value = "@permissionValidator.hasAssignRolePermission(#appId)") @DeleteMapping("/apps/{appId}/namespaces/{namespaceName}/roles/{roleType}") + @ApolloAuditLog(type = OpType.DELETE, name = "Auth.removeNamespaceRoleFromUser") public ResponseEntity removeNamespaceRoleFromUser(@PathVariable String appId, @PathVariable String namespaceName, @PathVariable String roleType, @RequestParam String user) { RequestPrecondition.checkArgumentsNotEmpty(user); @@ -252,6 +258,7 @@ public AppRolesAssignedUsers getAppRoles(@PathVariable String appId) { @PreAuthorize(value = "@permissionValidator.hasManageAppMasterPermission(#appId)") @PostMapping("/apps/{appId}/roles/{roleType}") + @ApolloAuditLog(type = OpType.CREATE, name = "Auth.assignAppRoleToUser") public ResponseEntity assignAppRoleToUser(@PathVariable String appId, @PathVariable String roleType, @RequestBody String user) { checkUserExists(user); @@ -271,6 +278,7 @@ public ResponseEntity assignAppRoleToUser(@PathVariable String appId, @Pat @PreAuthorize(value = "@permissionValidator.hasManageAppMasterPermission(#appId)") @DeleteMapping("/apps/{appId}/roles/{roleType}") + @ApolloAuditLog(type = OpType.DELETE, name = "Auth.removeAppRoleFromUser") public ResponseEntity removeAppRoleFromUser(@PathVariable String appId, @PathVariable String roleType, @RequestParam String user) { RequestPrecondition.checkArgumentsNotEmpty(user); @@ -291,6 +299,7 @@ private void checkUserExists(String userId) { @PreAuthorize(value = "@permissionValidator.isSuperAdmin()") @PostMapping("/system/role/createApplication") + @ApolloAuditLog(type = OpType.CREATE, name = "Auth.addCreateApplicationRoleToUser") public ResponseEntity addCreateApplicationRoleToUser(@RequestBody List userIds) { userIds.forEach(this::checkUserExists); @@ -302,6 +311,7 @@ public ResponseEntity addCreateApplicationRoleToUser(@RequestBody List deleteCreateApplicationRoleFromUser(@PathVariable("userId") String userId) { checkUserExists(userId); Set userIds = new HashSet<>(); @@ -327,6 +337,7 @@ public JsonObject hasCreateApplicationPermission(@PathVariable String userId) { @PreAuthorize(value = "@permissionValidator.isSuperAdmin()") @PostMapping("/apps/{appId}/system/master/{userId}") + @ApolloAuditLog(type = OpType.CREATE, name = "Auth.addManageAppMasterRoleToUser") public ResponseEntity addManageAppMasterRoleToUser(@PathVariable String appId, @PathVariable String userId) { checkUserExists(userId); roleInitializationService.initManageAppMasterRole(appId, userInfoHolder.getUser().getUserId()); @@ -339,6 +350,7 @@ public ResponseEntity addManageAppMasterRoleToUser(@PathVariable String ap @PreAuthorize(value = "@permissionValidator.isSuperAdmin()") @DeleteMapping("/apps/{appId}/system/master/{userId}") + @ApolloAuditLog(type = OpType.DELETE, name = "Auth.forbidManageAppMaster") public ResponseEntity forbidManageAppMaster(@PathVariable String appId, @PathVariable String userId) { checkUserExists(userId); roleInitializationService.initManageAppMasterRole(appId, userInfoHolder.getUser().getUserId()); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ServerConfigController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ServerConfigController.java index bf2a65857f4..99f5941d37f 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ServerConfigController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ServerConfigController.java @@ -17,6 +17,8 @@ package com.ctrip.framework.apollo.portal.controller; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLog; +import com.ctrip.framework.apollo.audit.annotation.OpType; import com.ctrip.framework.apollo.portal.entity.po.ServerConfig; import com.ctrip.framework.apollo.portal.environment.Env; import com.ctrip.framework.apollo.portal.service.ServerConfigService; @@ -42,12 +44,14 @@ public ServerConfigController(final ServerConfigService serverConfigService) { @PreAuthorize(value = "@permissionValidator.isSuperAdmin()") @PostMapping("/server/portal-db/config") + @ApolloAuditLog(type = OpType.CREATE, name = "ServerConfig.createOrUpdatePortalDBConfig") public ServerConfig createOrUpdatePortalDBConfig(@Valid @RequestBody ServerConfig serverConfig) { return serverConfigService.createOrUpdatePortalDBConfig(serverConfig); } @PreAuthorize(value = "@permissionValidator.isSuperAdmin()") @PostMapping("/server/envs/{env}/config-db/config") + @ApolloAuditLog(type = OpType.CREATE, name = "ServerConfig.createOrUpdateConfigDBConfig") public ServerConfig createOrUpdateConfigDBConfig(@Valid @RequestBody ServerConfig serverConfig, @PathVariable String env) { return serverConfigService.createOrUpdateConfigDBConfig(Env.transformEnv(env), serverConfig); } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/Role.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/Role.java index 6c2bb2cd687..29a0b1b542e 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/Role.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/Role.java @@ -16,6 +16,8 @@ */ package com.ctrip.framework.apollo.portal.entity.po; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLogDataInfluenceTable; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLogDataInfluenceTableField; import com.ctrip.framework.apollo.common.entity.BaseEntity; import org.hibernate.annotations.SQLDelete; @@ -32,7 +34,9 @@ @Table(name = "`Role`") @SQLDelete(sql = "Update Role set IsDeleted = true, DeletedAt = ROUND(UNIX_TIMESTAMP(NOW(4))*1000) where Id = ?") @Where(clause = "`IsDeleted` = false") +@ApolloAuditLogDataInfluenceTable(tableName = "Role") public class Role extends BaseEntity { + @ApolloAuditLogDataInfluenceTableField(fieldName = "RoleName") @Column(name = "`RoleName`", nullable = false) private String roleName; diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/ServerConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/ServerConfig.java index 3363a2a9683..690c9a749d6 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/ServerConfig.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/ServerConfig.java @@ -16,6 +16,8 @@ */ package com.ctrip.framework.apollo.portal.entity.po; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLogDataInfluenceTable; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLogDataInfluenceTableField; import com.ctrip.framework.apollo.common.entity.BaseEntity; import javax.validation.constraints.NotBlank; @@ -33,13 +35,16 @@ @Table(name = "`ServerConfig`") @SQLDelete(sql = "Update ServerConfig set IsDeleted = true, DeletedAt = ROUND(UNIX_TIMESTAMP(NOW(4))*1000) where Id = ?") @Where(clause = "`IsDeleted` = false") +@ApolloAuditLogDataInfluenceTable(tableName = "ServerConfig") public class ServerConfig extends BaseEntity { @NotBlank(message = "ServerConfig.Key cannot be blank") @Column(name = "`Key`", nullable = false) + @ApolloAuditLogDataInfluenceTableField(fieldName = "Key") private String key; @NotBlank(message = "ServerConfig.Value cannot be blank") @Column(name = "`Value`", nullable = false) + @ApolloAuditLogDataInfluenceTableField(fieldName = "Value") private String value; @Column(name = "`Comment`", nullable = false) diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/UserRole.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/UserRole.java index aa6ab8b28cb..222804e29ac 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/UserRole.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/UserRole.java @@ -16,6 +16,8 @@ */ package com.ctrip.framework.apollo.portal.entity.po; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLogDataInfluenceTable; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLogDataInfluenceTableField; import com.ctrip.framework.apollo.common.entity.BaseEntity; import org.hibernate.annotations.SQLDelete; @@ -32,10 +34,13 @@ @Table(name = "`UserRole`") @SQLDelete(sql = "Update UserRole set IsDeleted = true, DeletedAt = ROUND(UNIX_TIMESTAMP(NOW(4))*1000) where Id = ?") @Where(clause = "`IsDeleted` = false") +@ApolloAuditLogDataInfluenceTable(tableName = "UserRole") public class UserRole extends BaseEntity { + @ApolloAuditLogDataInfluenceTableField(fieldName = "UserId") @Column(name = "`UserId`", nullable = false) private String userId; + @ApolloAuditLogDataInfluenceTableField(fieldName = "RoleId") @Column(name = "`RoleId`", nullable = false) private long roleId; diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/defaultimpl/DefaultRolePermissionService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/defaultimpl/DefaultRolePermissionService.java index ef48d436fc0..d7697650b08 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/defaultimpl/DefaultRolePermissionService.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/defaultimpl/DefaultRolePermissionService.java @@ -16,6 +16,11 @@ */ package com.ctrip.framework.apollo.portal.spi.defaultimpl; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLog; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLogDataInfluence; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLogDataInfluenceTable; +import com.ctrip.framework.apollo.audit.annotation.ApolloAuditLogDataInfluenceTableField; +import com.ctrip.framework.apollo.audit.annotation.OpType; import com.ctrip.framework.apollo.openapi.repository.ConsumerRoleRepository; import com.ctrip.framework.apollo.portal.component.config.PortalConfig; import com.ctrip.framework.apollo.portal.entity.bo.UserInfo; @@ -107,6 +112,7 @@ public Role createRoleWithPermissions(Role role, Set permissionIds) { * @return the users assigned roles */ @Transactional + @ApolloAuditLog(type = OpType.CREATE, name = "Auth.assignRoleToUsers") public Set assignRoleToUsers(String roleName, Set userIds, String operatorUserId) { Role role = findRoleByRoleName(roleName); @@ -136,7 +142,14 @@ public Set assignRoleToUsers(String roleName, Set userIds, * Remove role from users */ @Transactional - public void removeRoleFromUsers(String roleName, Set userIds, String operatorUserId) { + @ApolloAuditLog(type = OpType.DELETE, name = "Auth.removeRoleFromUsers") + public void removeRoleFromUsers( + @ApolloAuditLogDataInfluence + @ApolloAuditLogDataInfluenceTable(tableName = "UserRole") + @ApolloAuditLogDataInfluenceTableField(fieldName = "RoleName") String roleName, + @ApolloAuditLogDataInfluence + @ApolloAuditLogDataInfluenceTable(tableName = "UserRole") + @ApolloAuditLogDataInfluenceTableField(fieldName = "UserId") Set userIds, String operatorUserId) { Role role = findRoleByRoleName(roleName); Preconditions.checkState(role != null, "Role %s doesn't exist!", roleName); diff --git a/apollo-portal/src/main/resources/static/audit_log_trace_detail.html b/apollo-portal/src/main/resources/static/audit_log_trace_detail.html index f66bc60b213..2fd446b479f 100644 --- a/apollo-portal/src/main/resources/static/audit_log_trace_detail.html +++ b/apollo-portal/src/main/resources/static/audit_log_trace_detail.html @@ -99,31 +99,35 @@

- {{'ApolloAuditLog.DataInfluence.EntityName' | translate}}: {{dataInfluenceEntity[0].name}} + {{'ApolloAuditLog.DataInfluence.EntityName' | translate}}: {{dataInfluenceEntity[1].name}}
-
- {{'ApolloAuditLog.DataInfluence.EntityId' | translate}}: {{dataInfluenceEntity[0].id}} +
+ {{'ApolloAuditLog.DataInfluence.EntityId' | translate}}: {{dataInfluenceEntity[1].id}}
-
+
{{'ApolloAuditLog.DataInfluence.AnyMatchedEntityId' | translate}}

-
+
{{'ApolloAuditLog.DataInfluence.Fields' | translate}}:
-
+
{{'ApolloAuditLog.DataInfluence.MatchedFields' | translate}}:
-
+ ng-show="dataInfluenceEntity[1].id != 'AnyMatched' && dataInfluence.fieldNewValue"> {{dataInfluence.fieldName}} ==> {{dataInfluence.fieldNewValue}}
+ ng-show="dataInfluenceEntity[1].id != 'AnyMatched' && !dataInfluence.fieldNewValue"> + {{dataInfluence.fieldName}} : {{dataInfluence.fieldOldValue}} ==> (deleted) +
+
{{dataInfluence.fieldName}} <== {{showingDetail.logDTO.opType == 'DELETE' ? dataInfluence.fieldOldValue : dataInfluence.fieldNewValue}}
@@ -158,7 +162,7 @@

- {{ di.fieldNewValue }} + {{ di.fieldNewValue ? di.fieldNewValue : '(deleted)' }} {{ di.happenedTime | date: 'yyyy-MM-dd HH:mm:ss' }} diff --git a/apollo-portal/src/main/resources/static/scripts/controller/AuditLogTraceDetailController.js b/apollo-portal/src/main/resources/static/scripts/controller/AuditLogTraceDetailController.js index 43b56f196a1..b2887964bce 100644 --- a/apollo-portal/src/main/resources/static/scripts/controller/AuditLogTraceDetailController.js +++ b/apollo-portal/src/main/resources/static/scripts/controller/AuditLogTraceDetailController.js @@ -136,10 +136,16 @@ function auditLogTraceDetailController($scope, $location, $window, $translate, t name: dto.influenceEntityName, id: dto.influenceEntityId }; - if (!entityMap.has(key)) { - entityMap.set(key, []); + var keyString = JSON.stringify(key); + var value = { + name: dto.influenceEntityName, + id: dto.influenceEntityId, + dtoList: [] + }; + if (!entityMap.has(keyString)) { + entityMap.set(keyString, value); } - entityMap.get(key).push(dto); + entityMap.get(keyString).dtoList.push(dto); }); $scope.dataInfluenceEntities = Array.from(entityMap); }