You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by xi...@apache.org on 2023/05/04 07:49:00 UTC

[shenyu] branch master updated: 【Type:Feature】Super admin forces password change (#4603)

This is an automated email from the ASF dual-hosted git repository.

xiaoyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new d6067f4bc 【Type:Feature】Super admin forces password change (#4603)
d6067f4bc is described below

commit d6067f4bce8033f93fd6268cf2da36553ec3eb22
Author: likeguo <33...@users.noreply.github.com>
AuthorDate: Thu May 4 15:48:51 2023 +0800

    【Type:Feature】Super admin forces password change (#4603)
    
    * super admin password safe
    
    * super admin password safe
    
    * super admin password safe
    
    * super admin password safe
    
    * super admin password safe
    
    * super admin password safe
    
    * super admin password safe
    
    * super admin password safe
    
    * super admin password safe
    
    * super admin password safe
    
    ---------
    
    Co-authored-by: xiaoyu <xi...@apache.org>
---
 .../aspect/controller/ControllerMethodAdvice.java  | 65 +++++++++++++++
 .../PrintLogControllerMethodAdviceImpl.java        | 59 ++++++++++++++
 .../RestControllerAspect.java}                     | 61 ++++++++------
 .../controller/SuperAdminPasswordSafeAdvice.java   | 93 ++++++++++++++++++++++
 .../config/properties/DashboardProperties.java     | 49 ++++++++++++
 .../admin/controller/DashboardUserController.java  |  1 -
 .../shenyu/admin/model/vo/AlertTemplateVO.java     |  3 +
 .../org/apache/shenyu/admin/model/vo/ApiVO.java    |  5 +-
 .../org/apache/shenyu/admin/model/vo/DetailVO.java |  8 +-
 .../org/apache/shenyu/admin/model/vo/FieldVO.java  |  8 +-
 .../apache/shenyu/admin/model/vo/MetaDataVO.java   |  3 +
 .../shenyu/admin/model/vo/MockRequestRecordVO.java |  5 +-
 .../shenyu/admin/model/vo/PermissionMenuVO.java    | 15 +++-
 .../apache/shenyu/admin/model/vo/RoleEditVO.java   | 20 ++++-
 .../shenyu/admin/aspect/PrintApiLogAspectTest.java | 60 +++++++++++---
 15 files changed, 405 insertions(+), 50 deletions(-)

diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/controller/ControllerMethodAdvice.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/controller/ControllerMethodAdvice.java
new file mode 100644
index 000000000..f40b6569e
--- /dev/null
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/controller/ControllerMethodAdvice.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shenyu.admin.aspect.controller;
+
+import com.google.common.base.Stopwatch;
+import org.apache.shenyu.common.exception.ShenyuException;
+
+import java.lang.reflect.Method;
+
+/**
+ * ControllerMethodAdvice.
+ */
+public interface ControllerMethodAdvice {
+    
+    /**
+     * Before the method executes.<br>
+     * If you want to prevent the method from executing, throw an exception in the method<br>
+     *
+     * @param bean      controller instance
+     * @param method    method
+     * @param stopwatch stopwatch
+     * @see ShenyuException
+     */
+    default void doPreProcess(Object bean, Method method, Stopwatch stopwatch) {
+        // nothing
+    }
+    
+    /**
+     * method error.<br>
+     *
+     * @param bean      controller instance
+     * @param method    method
+     * @param stopwatch stopwatch
+     * @param throwable throwable
+     */
+    default void doThrowable(Object bean, Method method, Stopwatch stopwatch, Throwable throwable) {
+        // skip
+    }
+    
+    /**
+     * method after.<br>
+     *
+     * @param bean      controller instance
+     * @param method    method
+     * @param stopwatch stopwatch
+     */
+    default void doFinally(Object bean, Method method, Stopwatch stopwatch) {
+        // nothing
+    }
+}
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/controller/PrintLogControllerMethodAdviceImpl.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/controller/PrintLogControllerMethodAdviceImpl.java
new file mode 100644
index 000000000..62150ef99
--- /dev/null
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/controller/PrintLogControllerMethodAdviceImpl.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shenyu.admin.aspect.controller;
+
+import com.google.common.base.Stopwatch;
+import org.apache.shenyu.admin.config.properties.DashboardProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.shenyu.admin.utils.SessionUtil.visitorName;
+
+/**
+ * PrintLogControllerMethodAdviceImpl.
+ */
+@Component
+public class PrintLogControllerMethodAdviceImpl implements ControllerMethodAdvice {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(PrintLogControllerMethodAdviceImpl.class);
+    
+    private final DashboardProperties properties;
+    
+    public PrintLogControllerMethodAdviceImpl(final DashboardProperties properties) {
+        this.properties = properties;
+    }
+    
+    @Override
+    public void doPreProcess(final Object bean, final Method method, final Stopwatch stopwatch) {
+        if (Boolean.TRUE.equals(properties.getEnablePrintApiLog())) {
+            LOG.info("{} exec: method [{}.{}]", visitorName(), bean.getClass().getSimpleName(), method.getName());
+        }
+    }
+    
+    @Override
+    public void doFinally(final Object bean, final Method method, final Stopwatch stopwatch) {
+        if (Boolean.TRUE.equals(properties.getEnablePrintApiLog())) {
+            LOG.info("{} exec: method [{}.{}] over, time cost: {}", visitorName(),
+                    bean.getClass().getSimpleName(), method.getName(), stopwatch.elapsed(TimeUnit.MILLISECONDS));
+        }
+    }
+}
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/PrintApiLogAspect.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/controller/RestControllerAspect.java
similarity index 55%
rename from shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/PrintApiLogAspect.java
rename to shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/controller/RestControllerAspect.java
index 460aa07e6..cc14ffc42 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/PrintApiLogAspect.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/controller/RestControllerAspect.java
@@ -15,72 +15,81 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.admin.aspect;
+package org.apache.shenyu.admin.aspect.controller;
 
-import org.apache.shenyu.admin.config.properties.DashboardProperties;
+import com.google.common.base.Stopwatch;
 import org.apache.shenyu.admin.utils.SessionUtil;
 import org.apache.shenyu.common.exception.ShenyuException;
 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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.aspectj.lang.reflect.MethodSignature;
 import org.springframework.stereotype.Component;
 
+import java.lang.reflect.Method;
+import java.util.List;
+
 /**
- * print log aspect.
+ * RestControllerAspect.
  */
 @Aspect
 @Component
-public class PrintApiLogAspect {
-    
-    private static final Logger LOG = LoggerFactory.getLogger(PrintApiLogAspect.class);
+public class RestControllerAspect {
     
-    private final DashboardProperties properties;
+    private final List<ControllerMethodAdvice> methodAdviceList;
     
-    public PrintApiLogAspect(final DashboardProperties properties) {
-        this.properties = properties;
+    public RestControllerAspect(final List<ControllerMethodAdvice> methodAdviceList) {
+        this.methodAdviceList = methodAdviceList;
     }
     
     /**
      * cut.
      */
     @Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
-    public void pointCut() {
+    public void controller() {
     }
     
     /**
-     * log around.
+     * controller.
      *
      * @param point point {@link ProceedingJoinPoint}
      * @return result {@link Object}
      */
-    @Around("pointCut()")
+    @Around("controller()")
     public Object logAround(final ProceedingJoinPoint point) {
-        final long start = System.currentTimeMillis();
+        final Stopwatch stopwatch = Stopwatch.createStarted();
+        final Method method = ((MethodSignature) point.getSignature()).getMethod();
+        final Object target = point.getTarget();
         try {
-            preLog(point);
+            doExec(a -> a.doPreProcess(target, method, stopwatch));
             return point.proceed();
         } catch (final Throwable throwable) {
+            doExec(a -> a.doThrowable(target, method, stopwatch, throwable));
             throw new ShenyuException(throwable);
         } finally {
-            postLog(point, start);
-            SessionUtil.clean();
+            try {
+                doExec(a -> a.doFinally(target, method, stopwatch));
+            } finally {
+                SessionUtil.clean();
+            }
         }
     }
     
-    private void postLog(final ProceedingJoinPoint point, final long start) {
-        if (Boolean.TRUE.equals(properties.getEnablePrintApiLog())) {
-            LOG.info("{} exec: method [{}.{}] over, time cost: {}", SessionUtil.visitorName(),
-                    point.getTarget().getClass().getSimpleName(), point.getSignature().getName(), System.currentTimeMillis() - start);
+    void doExec(final Call call) {
+        for (ControllerMethodAdvice advice : methodAdviceList) {
+            call.call(advice);
         }
     }
     
-    private void preLog(final ProceedingJoinPoint point) {
-        if (Boolean.TRUE.equals(properties.getEnablePrintApiLog())) {
-            LOG.info("{} exec: method [{}.{}]", SessionUtil.visitorName(), point.getTarget().getClass().getSimpleName(), point.getSignature().getName());
-        }
+    interface Call {
+        
+        /**
+         * call.
+         *
+         * @param advice advice
+         */
+        void call(ControllerMethodAdvice advice);
     }
     
 }
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/controller/SuperAdminPasswordSafeAdvice.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/controller/SuperAdminPasswordSafeAdvice.java
new file mode 100644
index 000000000..a646c429a
--- /dev/null
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/aspect/controller/SuperAdminPasswordSafeAdvice.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shenyu.admin.aspect.controller;
+
+import com.google.common.base.Stopwatch;
+import org.apache.shenyu.admin.config.properties.DashboardProperties;
+import org.apache.shenyu.admin.mapper.DashboardUserMapper;
+import org.apache.shenyu.admin.model.entity.DashboardUserDO;
+import org.apache.shenyu.admin.utils.SessionUtil;
+import org.apache.shenyu.common.exception.ShenyuException;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * SuperAdminPasswordSafeAdvice.<br>
+ * <p>The Super Administrator account has some privileges that are dangerous and unique to the account</p>
+ * <p>This is implemented to ensure that the super administrator account password is secure</p>
+ * <p>1 The password is the initial password, which we consider dangerous and will force it to change the password if the user is so set</p>
+ * <p>2 If the password has not been changed for a long time, we consider this risky and will force the user to change the password</p>
+ */
+@Component
+public class SuperAdminPasswordSafeAdvice implements ControllerMethodAdvice {
+    
+    private final DashboardProperties properties;
+    
+    private final DashboardUserMapper userMapper;
+    
+    public SuperAdminPasswordSafeAdvice(final DashboardProperties properties,
+                                        final DashboardUserMapper userMapper) {
+        this.properties = properties;
+        this.userMapper = userMapper;
+    }
+    
+    @Override
+    public void doPreProcess(final Object bean, final Method method, final Stopwatch stopwatch) {
+        // If the Super Administrator privilege attribute is not enabled
+        if (!Boolean.TRUE.equals(properties.getEnableOnlySuperAdminPermission())) {
+            // skip
+            return;
+        }
+        if (!Boolean.TRUE.equals(properties.getEnableSuperAdminPasswordSafe())) {
+            return;
+        }
+        // if not supper admin
+        if (!SessionUtil.isAdmin()) {
+            // skip
+            return;
+        }
+        
+        final RequiresPermissions permissions = AnnotatedElementUtils.findMergedAnnotation(method, RequiresPermissions.class);
+        if (Objects.isNull(permissions) || Objects.isNull(permissions.value())) {
+            return;
+        }
+        // This method exists in the list of super administrator privileges
+        if (properties.getOnlySuperAdminPermission()
+                .stream()
+                .anyMatch(p -> Arrays.asList(permissions.value()).contains(p))) {
+            
+            final String userId = SessionUtil.visitor().getUserId();
+            final DashboardUserDO userDO = userMapper.selectById(userId);
+            if (Objects.equals(userDO.getDateCreated(), userDO.getDateUpdated())) {
+                throw new ShenyuException("The password is the default password and you must complete the change once");
+            }
+            // The password has not been changed for a long time
+            if (userDO.getDateUpdated().getTime() <= System.currentTimeMillis() - properties.getSuperAdminPasswordValidDuration()) {
+                throw new ShenyuException("If the password has not been changed for a long time, please use it after changing it to ensure the security of the super administrator account");
+            }
+            // Weak password blacklist
+        }
+        
+    }
+    
+}
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/config/properties/DashboardProperties.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/config/properties/DashboardProperties.java
index 18045d94f..d75d77b90 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/config/properties/DashboardProperties.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/config/properties/DashboardProperties.java
@@ -57,6 +57,19 @@ public class DashboardProperties implements InitializingBean {
      */
     private Boolean enableOnlySuperAdminPermission = true;
     
+    /**
+     * enable SuperAdminPasswordSafe.
+     * default is true
+     */
+    private Boolean enableSuperAdminPasswordSafe = true;
+    
+    
+    /**
+     * enable SuperAdminPassword valid duration.
+     * default is 30 day
+     */
+    private Long superAdminPasswordValidDuration = 30 * 24 * 60 * 60 * 1000L;
+    
     
     /**
      * Only the super administrator root user has the privileges.
@@ -156,6 +169,42 @@ public class DashboardProperties implements InitializingBean {
         this.onlySuperAdminPermission = onlySuperAdminPermission;
     }
     
+    /**
+     * get enableSuperAdminPasswordSafe.
+     *
+     * @return boolean
+     */
+    public Boolean getEnableSuperAdminPasswordSafe() {
+        return enableSuperAdminPasswordSafe;
+    }
+    
+    /**
+     * set enableSuperAdminPasswordSafe.
+     *
+     * @param enableSuperAdminPasswordSafe enableSuperAdminPasswordSafe
+     */
+    public void setEnableSuperAdminPasswordSafe(final Boolean enableSuperAdminPasswordSafe) {
+        this.enableSuperAdminPasswordSafe = enableSuperAdminPasswordSafe;
+    }
+    
+    /**
+     * get superAdminPasswordValidDuration.
+     *
+     * @return long
+     */
+    public Long getSuperAdminPasswordValidDuration() {
+        return superAdminPasswordValidDuration;
+    }
+    
+    /**
+     * set superAdminPasswordValidDuration.
+     *
+     * @param superAdminPasswordValidDuration superAdminPasswordValidDuration
+     */
+    public void setSuperAdminPasswordValidDuration(final Long superAdminPasswordValidDuration) {
+        this.superAdminPasswordValidDuration = superAdminPasswordValidDuration;
+    }
+    
     @Override
     public void afterPropertiesSet() {
         if (!Boolean.TRUE.equals(enableOnlySuperAdminPermission)) {
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/DashboardUserController.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/DashboardUserController.java
index 43c28ade5..a969ee39e 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/DashboardUserController.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/DashboardUserController.java
@@ -158,7 +158,6 @@ public class DashboardUserController {
      * @return {@linkplain ShenyuAdminResult}
      */
     @PutMapping("/modify-password/{id}")
-    @RequiresPermissions("system:manager:edit")
     public ShenyuAdminResult modifyPassword(@PathVariable("id")
                                             @Existed(provider = DashboardUserMapper.class,
                                                     message = "user is not found") final String id,
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/AlertTemplateVO.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/AlertTemplateVO.java
index 4a54f6ac6..ca22d480a 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/AlertTemplateVO.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/AlertTemplateVO.java
@@ -17,6 +17,9 @@
 
 package org.apache.shenyu.admin.model.vo;
 
+/**
+ * AlertTemplateVO.
+ */
 public class AlertTemplateVO {
 
     private Long id;
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/ApiVO.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/ApiVO.java
index c264e4a6b..f3245709f 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/ApiVO.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/ApiVO.java
@@ -482,7 +482,10 @@ public class ApiVO implements Serializable {
                 .tags(tags)
                 .build();
     }
-
+    
+    /**
+     * ApiVOBuilder.
+     */
     public static final class ApiVOBuilder {
 
         /**
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/DetailVO.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/DetailVO.java
index 0ba1fb98f..3963c5424 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/DetailVO.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/DetailVO.java
@@ -24,6 +24,9 @@ import org.apache.shenyu.admin.validation.annotation.Existed;
 import java.sql.Timestamp;
 import java.util.Objects;
 
+/**
+ * DetailVO.
+ */
 public class DetailVO {
 
     @Existed(provider = DetailMapper.class, nullOfIgnore = true, message = "detail is not existed")
@@ -233,7 +236,10 @@ public class DetailVO {
                 .dateCreated(detailDO.getDateCreated())
                 .build();
     }
-
+    
+    /**
+     * DetailVOBuilder.
+     */
     public static final class DetailVOBuilder {
 
         private String id;
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/FieldVO.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/FieldVO.java
index 13d384ced..e579d25eb 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/FieldVO.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/FieldVO.java
@@ -22,6 +22,9 @@ import org.apache.shenyu.admin.model.entity.FieldDO;
 import java.sql.Timestamp;
 import java.util.Objects;
 
+/**
+ * FieldVO.
+ */
 public class FieldVO {
 
     /**
@@ -283,7 +286,10 @@ public class FieldVO {
     public static FieldVO.FieldVOBuilder builder() {
         return new FieldVO.FieldVOBuilder();
     }
-
+    
+    /**
+     * FieldVOBuilder.
+     */
     public static final class FieldVOBuilder {
 
         private String id;
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/MetaDataVO.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/MetaDataVO.java
index 9412cc98a..5bfd6b476 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/MetaDataVO.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/MetaDataVO.java
@@ -20,6 +20,9 @@ package org.apache.shenyu.admin.model.vo;
 import java.io.Serializable;
 import java.util.Objects;
 
+/**
+ * MetaDataVO.
+ */
 public class MetaDataVO implements Serializable {
 
     private static final long serialVersionUID = -2658925954317878033L;
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/MockRequestRecordVO.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/MockRequestRecordVO.java
index f38bd5bff..fd7dce84a 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/MockRequestRecordVO.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/MockRequestRecordVO.java
@@ -327,7 +327,10 @@ public class MockRequestRecordVO implements Serializable {
                 .dateUpdated("")
                 .build();
     }
-
+    
+    /**
+     * MockRequestRecordVOBuilder.
+     */
     public static final class MockRequestRecordVOBuilder {
         /**
          * primary key id.
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/PermissionMenuVO.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/PermissionMenuVO.java
index f9643bd57..1d29351a2 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/PermissionMenuVO.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/PermissionMenuVO.java
@@ -135,7 +135,10 @@ public class PermissionMenuVO implements Serializable {
                 + ", allAuth=" + allAuth
                 + '}';
     }
-
+    
+    /**
+     * MenuInfo.
+     */
     public static class MenuInfo {
 
         /**
@@ -383,7 +386,10 @@ public class PermissionMenuVO implements Serializable {
                     + ", sort=" + sort
                     + '}';
         }
-
+        
+        /**
+         * MenuInfoBuilder.
+         */
         public static final class MenuInfoBuilder {
 
             /**
@@ -513,7 +519,10 @@ public class PermissionMenuVO implements Serializable {
             }
         }
     }
-
+    
+    /**
+     * AuthPerm.
+     */
     public static class AuthPerm {
 
         /**
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/RoleEditVO.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/RoleEditVO.java
index f6cd015d9..afcc4f2f4 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/RoleEditVO.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/RoleEditVO.java
@@ -106,7 +106,10 @@ public class RoleEditVO implements Serializable {
     public void setAllPermissionInfo(final PermissionInfo allPermissionInfo) {
         this.allPermissionInfo = allPermissionInfo;
     }
-
+    
+    /**
+     * PermissionInfo.
+     */
     public static class PermissionInfo {
 
         /**
@@ -171,7 +174,10 @@ public class RoleEditVO implements Serializable {
         public static PermissionInfo.PermissionInfoBuilder builder() {
             return new PermissionInfo.PermissionInfoBuilder();
         }
-
+        
+        /**
+         * PermissionInfoBuilder.
+         */
         public static final class PermissionInfoBuilder {
 
             /**
@@ -219,7 +225,10 @@ public class RoleEditVO implements Serializable {
             }
         }
     }
-
+    
+    /**
+     * ResourceInfo.
+     */
     public static class ResourceInfo {
 
         /**
@@ -402,7 +411,10 @@ public class RoleEditVO implements Serializable {
         public static ResourceInfo.ResourceInfoBuilder builder() {
             return new ResourceInfo.ResourceInfoBuilder();
         }
-
+        
+        /**
+         * ResourceInfoBuilder.
+         */
         public static final class ResourceInfoBuilder {
 
             /**
diff --git a/shenyu-admin/src/test/java/org/apache/shenyu/admin/aspect/PrintApiLogAspectTest.java b/shenyu-admin/src/test/java/org/apache/shenyu/admin/aspect/PrintApiLogAspectTest.java
index 5ddd618fc..ad98072dd 100644
--- a/shenyu-admin/src/test/java/org/apache/shenyu/admin/aspect/PrintApiLogAspectTest.java
+++ b/shenyu-admin/src/test/java/org/apache/shenyu/admin/aspect/PrintApiLogAspectTest.java
@@ -17,52 +17,88 @@
 
 package org.apache.shenyu.admin.aspect;
 
+import org.apache.shenyu.admin.aspect.controller.PrintLogControllerMethodAdviceImpl;
+import org.apache.shenyu.admin.aspect.controller.RestControllerAspect;
 import org.apache.shenyu.admin.config.properties.DashboardProperties;
+import org.apache.shenyu.admin.model.custom.UserInfo;
+import org.apache.shenyu.admin.utils.ListUtil;
+import org.apache.shenyu.admin.utils.SessionUtil;
 import org.apache.shenyu.common.exception.ShenyuException;
 import org.aspectj.lang.ProceedingJoinPoint;
-import org.aspectj.lang.Signature;
+import org.aspectj.lang.reflect.MethodSignature;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import java.lang.reflect.Method;
+
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 /**
- * Test cases for {@link PrintApiLogAspect}.
+ * Test cases for {@link PrintLogControllerMethodAdviceImpl}.
  */
 public class PrintApiLogAspectTest {
-
-    private PrintApiLogAspect printApiLogAspect;
-
+    
+    private RestControllerAspect printApiLogAspect;
+    
     private DashboardProperties dashboardProperties;
-
+    
+    private UserInfo visitor;
+    
     @BeforeEach
     public void setUp() {
         dashboardProperties = mock(DashboardProperties.class);
-        printApiLogAspect = new PrintApiLogAspect(dashboardProperties);
+        PrintLogControllerMethodAdviceImpl logControllerMethodAdvice = new PrintLogControllerMethodAdviceImpl(dashboardProperties);
+        printApiLogAspect = new RestControllerAspect(ListUtil.of(logControllerMethodAdvice));
+        visitor = UserInfo.builder()
+                .userId("1")
+                .userName("admin")
+                .build();
     }
-
+    
     @Test
-    public void testAround() throws ShenyuException {
+    public void testAround() throws ShenyuException, NoSuchMethodException {
+        addVisitor();
+        final Method method = DataPermissionAspectTest.class.getMethod("nullMethod");
         ProceedingJoinPoint point = mock(ProceedingJoinPoint.class);
+        final MethodSignature signature = mock(MethodSignature.class);
+        when(point.getSignature()).thenReturn(signature);
+        when(signature.getMethod()).thenReturn(method);
         assertDoesNotThrow(() -> printApiLogAspect.logAround(point));
+        assertNotEquals(SessionUtil.visitor(), visitor);
+        
+        addVisitor();
         when(dashboardProperties.getEnablePrintApiLog()).thenReturn(true);
         when(point.getTarget()).thenReturn(mock(PrintApiLogAspectTest.class));
-        when(point.getSignature()).thenReturn(mock(Signature.class));
+        when(point.getSignature()).thenReturn(signature);
         assertDoesNotThrow(() -> printApiLogAspect.logAround(point));
+        assertNotEquals(SessionUtil.visitor(), visitor);
         try {
+            addVisitor();
             doThrow(ShenyuException.class).when(point).proceed();
             assertThrows(ShenyuException.class, () -> printApiLogAspect.logAround(point));
+            assertNotEquals(SessionUtil.visitor(), visitor);
         } catch (Throwable e) {
             throw new ShenyuException(e);
         }
     }
-
+    
     @Test
     public void pointCutTest() {
-        assertDoesNotThrow(() -> printApiLogAspect.pointCut());
+        assertDoesNotThrow(() -> printApiLogAspect.controller());
+    }
+    
+    private void addVisitor() {
+        SessionUtil.setLocalVisitor(visitor);
+    }
+    
+    /**
+     * nullMethod.
+     */
+    public void nullMethod() {
     }
 }