You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2022/12/12 07:22:37 UTC

[dubbo] branch 3.2 updated: update(qos): support anonymous access. (#11076)

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

albumenj pushed a commit to branch 3.2
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.2 by this push:
     new ab5d95f46b update(qos): support anonymous access. (#11076)
ab5d95f46b is described below

commit ab5d95f46b9bd63ff60d926f031903b3ac171126
Author: Koy Zhuang <ko...@ko8e24.top>
AuthorDate: Mon Dec 12 15:22:26 2022 +0800

    update(qos): support anonymous access. (#11076)
---
 .../common/constants/LoggerCodeConstants.java      |   2 +
 .../dubbo/common/constants/QosConstants.java       |   4 +
 .../org/apache/dubbo/config/ApplicationConfig.java |  25 +++++
 dubbo-distribution/dubbo-all/pom.xml               |   6 ++
 .../apache/dubbo/qos/command/CommandContext.java   |  16 +++
 .../apache/dubbo/qos/command/CommandExecutor.java  |   5 +-
 .../dubbo/qos/command/DefaultCommandExecutor.java  |  29 ++++-
 .../apache/dubbo/qos/command/annotation/Cmd.java   |  10 ++
 .../exception/CommandException.java}               |  13 +--
 .../{ => exception}/NoSuchCommandException.java    |   4 +-
 .../PermissionDenyException.java}                  |   8 +-
 .../org/apache/dubbo/qos/command/impl/Live.java    |   5 +-
 .../org/apache/dubbo/qos/command/impl/Quit.java    |   3 +-
 .../org/apache/dubbo/qos/command/impl/Ready.java   |   5 +-
 .../org/apache/dubbo/qos/command/impl/Startup.java |   3 +-
 .../apache/dubbo/qos/common/QosConfiguration.java  | 118 +++++++++++++++++++++
 .../org/apache/dubbo/qos/common/QosConstants.java  |   2 +
 .../DefaultAnonymousAccessPermissionChecker.java}  |  14 ++-
 .../PermissionChecker.java}                        |  17 ++-
 .../dubbo/qos/permission/PermissionLevel.java      |  67 ++++++++++++
 .../dubbo/qos/protocol/QosProtocolWrapper.java     |   4 +
 .../org/apache/dubbo/qos/pu/QosWireProtocol.java   |  10 +-
 .../java/org/apache/dubbo/qos/server/Server.java   |  17 ++-
 .../server/handler/ForeignHostPermitHandler.java   |  25 +++--
 .../qos/server/handler/HttpProcessHandler.java     |  25 +++--
 .../qos/server/handler/QosProcessHandler.java      |  23 ++--
 .../qos/server/handler/TelnetProcessHandler.java   |  15 ++-
 .../qos/command/DefaultCommandExecutorTest.java    |  29 ++++-
 .../apache/dubbo/qos/pu/QosWireProtocolTest.java}  |  36 +++----
 .../handler/ForeignHostPermitHandlerTest.java      |  52 ++++++++-
 .../qos/server/handler/HttpProcessHandlerTest.java |  16 ++-
 .../qos/server/handler/QosProcessHandlerTest.java  |  17 ++-
 .../server/handler/TelnetProcessHandlerTest.java   |  18 +++-
 ...g.apache.dubbo.qos.permission.PermissionChecker |   1 +
 34 files changed, 537 insertions(+), 107 deletions(-)

diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/LoggerCodeConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/LoggerCodeConstants.java
index 5bd40bccbe..c0c819cade 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/LoggerCodeConstants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/LoggerCodeConstants.java
@@ -380,6 +380,8 @@ public interface LoggerCodeConstants {
 
     String QOS_UNEXPECTED_EXCEPTION = "7-6";
 
+    String QOS_PERMISSION_DENY_EXCEPTION = "7-7";
+
     // Internal unknown error.
     String INTERNAL_ERROR = "99-0";
 
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/QosConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/QosConstants.java
index 3939296ffa..e02ec74a65 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/QosConstants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/QosConstants.java
@@ -32,6 +32,8 @@ public interface QosConstants {
 
     String ACCEPT_FOREIGN_IP_WHITELIST = "qos.accept.foreign.ip.whitelist";
 
+    String ANONYMOUS_ACCESS_PERMISSION_LEVEL = "qos.anonymous.access.permission.level";
+
     String QOS_ENABLE_COMPATIBLE = "qos-enable";
 
     String QOS_HOST_COMPATIBLE = "qos-host";
@@ -41,4 +43,6 @@ public interface QosConstants {
     String ACCEPT_FOREIGN_IP_COMPATIBLE = "qos-accept-foreign-ip";
 
     String ACCEPT_FOREIGN_IP_WHITELIST_COMPATIBLE = "qos-accept-foreign-ip-whitelist";
+
+    String ANONYMOUS_ACCESS_PERMISSION_LEVEL_COMPATIBLE = "qos-anonymous-access-permission-level";
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/ApplicationConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/ApplicationConfig.java
index 080616ccb8..85b4173307 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/ApplicationConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/ApplicationConfig.java
@@ -38,6 +38,8 @@ import static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;
 import static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP_COMPATIBLE;
 import static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP_WHITELIST;
 import static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP_WHITELIST_COMPATIBLE;
+import static org.apache.dubbo.common.constants.QosConstants.ANONYMOUS_ACCESS_PERMISSION_LEVEL;
+import static org.apache.dubbo.common.constants.QosConstants.ANONYMOUS_ACCESS_PERMISSION_LEVEL_COMPATIBLE;
 import static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;
 import static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE_COMPATIBLE;
 import static org.apache.dubbo.common.constants.QosConstants.QOS_HOST;
@@ -164,6 +166,11 @@ public class ApplicationConfig extends AbstractConfig {
      */
     private String qosAcceptForeignIpWhitelist;
 
+    /**
+     * the anonymous(any foreign ip) access permission level, default is NONE, can not access any cmd
+     */
+    private String qosAnonymousAccessPermissionLevel;
+
     /**
      * Customized parameters
      */
@@ -444,6 +451,15 @@ public class ApplicationConfig extends AbstractConfig {
         this.qosAcceptForeignIpWhitelist = qosAcceptForeignIpWhitelist;
     }
 
+    @Parameter(key = ANONYMOUS_ACCESS_PERMISSION_LEVEL)
+    public String getQosAnonymousAccessPermissionLevel() {
+        return qosAnonymousAccessPermissionLevel;
+    }
+
+    public void setQosAnonymousAccessPermissionLevel(String qosAnonymousAccessPermissionLevel) {
+        this.qosAnonymousAccessPermissionLevel = qosAnonymousAccessPermissionLevel;
+    }
+
     /**
      * The format is the same as the springboot, including: getQosEnableCompatible(), getQosPortCompatible(), getQosAcceptForeignIpCompatible().
      *
@@ -494,6 +510,15 @@ public class ApplicationConfig extends AbstractConfig {
         this.setQosAcceptForeignIpWhitelist(qosAcceptForeignIpWhitelist);
     }
 
+    @Parameter(key = ANONYMOUS_ACCESS_PERMISSION_LEVEL_COMPATIBLE, excluded = true, attribute = false)
+    public String getQosAnonymousAccessPermissionLevelCompatible() {
+        return this.getQosAnonymousAccessPermissionLevel();
+    }
+
+    public void setQosAnonymousAccessPermissionLevelCompatible(String qosAnonymousAccessPermissionLevel) {
+        this.setQosAnonymousAccessPermissionLevel(qosAnonymousAccessPermissionLevel);
+    }
+
     public Map<String, String> getParameters() {
         return parameters;
     }
diff --git a/dubbo-distribution/dubbo-all/pom.xml b/dubbo-distribution/dubbo-all/pom.xml
index 4d59293a3d..f14687efb2 100644
--- a/dubbo-distribution/dubbo-all/pom.xml
+++ b/dubbo-distribution/dubbo-all/pom.xml
@@ -812,6 +812,12 @@
                                         META-INF/dubbo/internal/org.apache.dubbo.qos.probe.StartupProbe
                                     </resource>
                                 </transformer>
+                                <transformer
+                                    implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+                                    <resource>
+                                        META-INF/dubbo/internal/org.apache.dubbo.qos.permission.PermissionChecker
+                                    </resource>
+                                </transformer>
                                 <transformer
                                     implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                     <resource>
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/CommandContext.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/CommandContext.java
index 0c2612a5c4..a45560becd 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/CommandContext.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/CommandContext.java
@@ -17,6 +17,8 @@
 package org.apache.dubbo.qos.command;
 
 import io.netty.channel.Channel;
+import org.apache.dubbo.qos.permission.PermissionLevel;
+import org.apache.dubbo.qos.common.QosConfiguration;
 
 public class CommandContext {
 
@@ -27,6 +29,8 @@ public class CommandContext {
     private Object originRequest;
     private int httpCode = 200;
 
+    private QosConfiguration qosConfiguration;
+
     public CommandContext(String commandName) {
         this.commandName = commandName;
     }
@@ -84,4 +88,16 @@ public class CommandContext {
     public void setHttpCode(int httpCode) {
         this.httpCode = httpCode;
     }
+
+    public void setQosConfiguration(QosConfiguration qosConfiguration) {
+        this.qosConfiguration = qosConfiguration;
+    }
+
+    public boolean hasPermission(PermissionLevel cmdRequiredPermissionLevel) {
+        return cmdRequiredPermissionLevel.getLevel() <= qosConfiguration.getAnonymousAccessPermissionLevel().getLevel();
+    }
+
+    public boolean isAllowAnonymousAccess(){
+        return this.qosConfiguration.isAllowAnonymousAccess();
+    }
 }
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/CommandExecutor.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/CommandExecutor.java
index d60115c51a..0efec6f090 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/CommandExecutor.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/CommandExecutor.java
@@ -16,6 +16,9 @@
  */
 package org.apache.dubbo.qos.command;
 
+import org.apache.dubbo.qos.command.exception.NoSuchCommandException;
+import org.apache.dubbo.qos.command.exception.PermissionDenyException;
+
 public interface CommandExecutor {
     /**
      * Execute one command and return the execution result
@@ -24,5 +27,5 @@ public interface CommandExecutor {
      * @return command execution result
      * @throws NoSuchCommandException
      */
-    String execute(CommandContext commandContext) throws NoSuchCommandException;
+    String execute(CommandContext commandContext) throws NoSuchCommandException, PermissionDenyException;
 }
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/DefaultCommandExecutor.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/DefaultCommandExecutor.java
index 12cd5f9b9e..6b645cfe6b 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/DefaultCommandExecutor.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/DefaultCommandExecutor.java
@@ -16,17 +16,24 @@
  */
 package org.apache.dubbo.qos.command;
 
+import org.apache.dubbo.qos.command.annotation.Cmd;
+import org.apache.dubbo.qos.common.QosConstants;
+import org.apache.dubbo.qos.permission.PermissionLevel;
+import org.apache.dubbo.qos.command.exception.NoSuchCommandException;
+import org.apache.dubbo.qos.command.exception.PermissionDenyException;
+import org.apache.dubbo.qos.permission.DefaultAnonymousAccessPermissionChecker;
+import org.apache.dubbo.qos.permission.PermissionChecker;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
 public class DefaultCommandExecutor implements CommandExecutor {
-    private FrameworkModel frameworkModel;
+    private final FrameworkModel frameworkModel;
 
     public DefaultCommandExecutor(FrameworkModel frameworkModel) {
         this.frameworkModel = frameworkModel;
     }
 
     @Override
-    public String execute(CommandContext commandContext) throws NoSuchCommandException {
+    public String execute(CommandContext commandContext) throws NoSuchCommandException, PermissionDenyException {
         BaseCommand command = null;
         try {
             command = frameworkModel.getExtensionLoader(BaseCommand.class).getExtension(commandContext.getCommandName());
@@ -36,6 +43,24 @@ public class DefaultCommandExecutor implements CommandExecutor {
         if (command == null) {
             throw new NoSuchCommandException(commandContext.getCommandName());
         }
+
+        // check permission when configs allow anonymous access
+        if (commandContext.isAllowAnonymousAccess()) {
+            PermissionChecker permissionChecker = DefaultAnonymousAccessPermissionChecker.INSTANCE;
+            try {
+                permissionChecker = frameworkModel.getExtensionLoader(PermissionChecker.class).getExtension(QosConstants.QOS_PERMISSION_CHECKER);
+            } catch (Throwable throwable) {
+                //can't find valid custom permissionChecker
+            }
+
+            final Cmd cmd = command.getClass().getAnnotation(Cmd.class);
+            final PermissionLevel cmdRequiredPermissionLevel = cmd.requiredPermissionLevel();
+
+            if (!permissionChecker.access(commandContext, cmdRequiredPermissionLevel)) {
+                throw new PermissionDenyException(commandContext.getCommandName());
+            }
+        }
+
         return command.execute(commandContext, commandContext.getArgs());
     }
 }
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/annotation/Cmd.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/annotation/Cmd.java
index dfeb9b8cfa..bccc1d77d2 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/annotation/Cmd.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/annotation/Cmd.java
@@ -16,6 +16,8 @@
  */
 package org.apache.dubbo.qos.command.annotation;
 
+import org.apache.dubbo.qos.permission.PermissionLevel;
+
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -55,4 +57,12 @@ public @interface Cmd {
      * @return command order in help
      */
     int sort() default 0;
+
+    /**
+     * Command required access permission level
+     *
+     * @return command permission level
+     */
+    PermissionLevel requiredPermissionLevel() default PermissionLevel.PROTECTED;
+
 }
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/common/QosConstants.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/exception/CommandException.java
similarity index 82%
copy from dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/common/QosConstants.java
copy to dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/exception/CommandException.java
index f4bf6e7194..3cb67f108e 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/common/QosConstants.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/exception/CommandException.java
@@ -14,13 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.qos.common;
-
-public interface QosConstants {
-
-    int DEFAULT_PORT = 22222;
-
-    String BR_STR = "\r\n";
-    String CLOSE = "close!";
+package org.apache.dubbo.qos.command.exception;
 
+public class CommandException extends Exception {
+    public CommandException(String msg) {
+        super(msg);
+    }
 }
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/NoSuchCommandException.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/exception/NoSuchCommandException.java
similarity index 89%
copy from dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/NoSuchCommandException.java
copy to dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/exception/NoSuchCommandException.java
index 1d7396bdb4..b606bb6459 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/NoSuchCommandException.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/exception/NoSuchCommandException.java
@@ -14,9 +14,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.qos.command;
+package org.apache.dubbo.qos.command.exception;
 
-public class NoSuchCommandException extends Exception {
+public class NoSuchCommandException extends CommandException {
     public NoSuchCommandException(String msg) {
         super("NoSuchCommandException:" + msg);
     }
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/NoSuchCommandException.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/exception/PermissionDenyException.java
similarity index 78%
rename from dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/NoSuchCommandException.java
rename to dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/exception/PermissionDenyException.java
index 1d7396bdb4..2377eaf287 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/NoSuchCommandException.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/exception/PermissionDenyException.java
@@ -14,10 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.qos.command;
+package org.apache.dubbo.qos.command.exception;
 
-public class NoSuchCommandException extends Exception {
-    public NoSuchCommandException(String msg) {
-        super("NoSuchCommandException:" + msg);
+public class PermissionDenyException extends CommandException {
+    public PermissionDenyException(String msg) {
+        super("Permission Deny On Operation: " + msg);
     }
 }
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Live.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Live.java
index 947ad8e4ac..bc4870ac3f 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Live.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Live.java
@@ -22,6 +22,7 @@ import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.qos.command.BaseCommand;
 import org.apache.dubbo.qos.command.CommandContext;
 import org.apache.dubbo.qos.command.annotation.Cmd;
+import org.apache.dubbo.qos.permission.PermissionLevel;
 import org.apache.dubbo.qos.probe.LivenessProbe;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
@@ -29,9 +30,9 @@ import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
-@Cmd(name = "live", summary = "Judge if service is alive? ")
+@Cmd(name = "live", summary = "Judge if service is alive? ", requiredPermissionLevel = PermissionLevel.PUBLIC)
 public class Live implements BaseCommand {
-    private FrameworkModel frameworkModel;
+    private final FrameworkModel frameworkModel;
 
     public Live(FrameworkModel frameworkModel) {
         this.frameworkModel = frameworkModel;
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Quit.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Quit.java
index 9539db9dea..90e34ea67d 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Quit.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Quit.java
@@ -19,9 +19,10 @@ package org.apache.dubbo.qos.command.impl;
 import org.apache.dubbo.qos.command.BaseCommand;
 import org.apache.dubbo.qos.command.CommandContext;
 import org.apache.dubbo.qos.command.annotation.Cmd;
+import org.apache.dubbo.qos.permission.PermissionLevel;
 import org.apache.dubbo.qos.common.QosConstants;
 
-@Cmd(name = "quit",summary = "quit telnet console")
+@Cmd(name = "quit", summary = "quit telnet console", requiredPermissionLevel = PermissionLevel.PUBLIC)
 public class Quit implements BaseCommand {
     @Override
     public String execute(CommandContext commandContext, String[] args) {
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Ready.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Ready.java
index e7ce83977b..5b5d898a0a 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Ready.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Ready.java
@@ -22,6 +22,7 @@ import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.qos.command.BaseCommand;
 import org.apache.dubbo.qos.command.CommandContext;
 import org.apache.dubbo.qos.command.annotation.Cmd;
+import org.apache.dubbo.qos.permission.PermissionLevel;
 import org.apache.dubbo.qos.probe.ReadinessProbe;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
@@ -29,9 +30,9 @@ import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
-@Cmd(name = "ready", summary = "Judge if service is ready to work? ")
+@Cmd(name = "ready", summary = "Judge if service is ready to work? ", requiredPermissionLevel = PermissionLevel.PUBLIC)
 public class Ready implements BaseCommand {
-    private FrameworkModel frameworkModel;
+    private final FrameworkModel frameworkModel;
 
     public Ready(FrameworkModel frameworkModel) {
         this.frameworkModel = frameworkModel;
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Startup.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Startup.java
index e963f65d33..8f2d2d0148 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Startup.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Startup.java
@@ -22,6 +22,7 @@ import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.qos.command.BaseCommand;
 import org.apache.dubbo.qos.command.CommandContext;
 import org.apache.dubbo.qos.command.annotation.Cmd;
+import org.apache.dubbo.qos.permission.PermissionLevel;
 import org.apache.dubbo.qos.probe.StartupProbe;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
@@ -29,7 +30,7 @@ import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
-@Cmd(name = "startup", summary = "Judge if service has started? ")
+@Cmd(name = "startup", summary = "Judge if service has started? ", requiredPermissionLevel = PermissionLevel.PUBLIC)
 public class Startup implements BaseCommand {
 
     private FrameworkModel frameworkModel;
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/common/QosConfiguration.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/common/QosConfiguration.java
new file mode 100644
index 0000000000..fee7486913
--- /dev/null
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/common/QosConfiguration.java
@@ -0,0 +1,118 @@
+/*
+ * 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.dubbo.qos.common;
+
+import org.apache.dubbo.qos.permission.PermissionLevel;
+
+public class QosConfiguration {
+    private String welcome;
+    private boolean acceptForeignIp;
+
+    // the whitelist of foreign IP when acceptForeignIp = false, the delimiter is colon(,)
+    // support specific ip and an ip range from CIDR specification
+    private String acceptForeignIpWhitelist;
+
+    // this permission level for anonymous access, it will ignore the acceptForeignIp and acceptForeignIpWhitelist configurations
+    // Access permission depends on the config anonymousAccessPermissionLevel and the cmd required permission level
+    // the default value is Cmd.PermissionLevel.PUBLIC, can only access PUBLIC level cmd
+    private PermissionLevel anonymousAccessPermissionLevel = PermissionLevel.PUBLIC;
+
+    private QosConfiguration() {
+    }
+
+    public QosConfiguration(Builder builder) {
+        this.welcome = builder.getWelcome();
+        this.acceptForeignIp = builder.isAcceptForeignIp();
+        this.acceptForeignIpWhitelist = builder.getAcceptForeignIpWhitelist();
+        this.anonymousAccessPermissionLevel = builder.getAnonymousAccessPermissionLevel();
+    }
+
+    public boolean isAllowAnonymousAccess() {
+        return PermissionLevel.NONE != anonymousAccessPermissionLevel;
+    }
+
+    public String getWelcome() {
+        return welcome;
+    }
+
+    public PermissionLevel getAnonymousAccessPermissionLevel() {
+        return anonymousAccessPermissionLevel;
+    }
+
+    public String getAcceptForeignIpWhitelist() {
+        return acceptForeignIpWhitelist;
+    }
+
+    public boolean isAcceptForeignIp() {
+        return acceptForeignIp;
+    }
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+
+    public static class Builder {
+        private String welcome;
+        private boolean acceptForeignIp;
+        private String acceptForeignIpWhitelist;
+        private PermissionLevel anonymousAccessPermissionLevel = PermissionLevel.PUBLIC;
+
+        private Builder() {
+        }
+
+        public Builder welcome(String welcome) {
+            this.welcome = welcome;
+            return this;
+        }
+
+        public Builder acceptForeignIp(boolean acceptForeignIp) {
+            this.acceptForeignIp = acceptForeignIp;
+            return this;
+        }
+
+        public Builder acceptForeignIpWhitelist(String acceptForeignIpWhitelist) {
+            this.acceptForeignIpWhitelist = acceptForeignIpWhitelist;
+            return this;
+        }
+
+        public Builder anonymousAccessPermissionLevel(String anonymousAccessPermissionLevel) {
+            this.anonymousAccessPermissionLevel = PermissionLevel.from(anonymousAccessPermissionLevel);
+            return this;
+        }
+
+        public QosConfiguration build() {
+            return new QosConfiguration(this);
+        }
+
+        public String getWelcome() {
+            return welcome;
+        }
+
+        public boolean isAcceptForeignIp() {
+            return acceptForeignIp;
+        }
+
+        public String getAcceptForeignIpWhitelist() {
+            return acceptForeignIpWhitelist;
+        }
+
+        public PermissionLevel getAnonymousAccessPermissionLevel() {
+            return anonymousAccessPermissionLevel;
+        }
+    }
+}
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/common/QosConstants.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/common/QosConstants.java
index f4bf6e7194..96bd786693 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/common/QosConstants.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/common/QosConstants.java
@@ -23,4 +23,6 @@ public interface QosConstants {
     String BR_STR = "\r\n";
     String CLOSE = "close!";
 
+    String QOS_PERMISSION_CHECKER = "qosPermissionChecker";
+
 }
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Quit.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/permission/DefaultAnonymousAccessPermissionChecker.java
similarity index 66%
copy from dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Quit.java
copy to dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/permission/DefaultAnonymousAccessPermissionChecker.java
index 9539db9dea..ab5aa79e7b 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Quit.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/permission/DefaultAnonymousAccessPermissionChecker.java
@@ -14,17 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.qos.command.impl;
+package org.apache.dubbo.qos.permission;
 
-import org.apache.dubbo.qos.command.BaseCommand;
 import org.apache.dubbo.qos.command.CommandContext;
-import org.apache.dubbo.qos.command.annotation.Cmd;
-import org.apache.dubbo.qos.common.QosConstants;
 
-@Cmd(name = "quit",summary = "quit telnet console")
-public class Quit implements BaseCommand {
+public class DefaultAnonymousAccessPermissionChecker implements PermissionChecker {
+    public static final DefaultAnonymousAccessPermissionChecker INSTANCE = new DefaultAnonymousAccessPermissionChecker();
+
     @Override
-    public String execute(CommandContext commandContext, String[] args) {
-        return QosConstants.CLOSE;
+    public boolean access(CommandContext commandContext, PermissionLevel defaultCmdRequiredPermissionLevel) {
+        return commandContext.hasPermission(defaultCmdRequiredPermissionLevel);
     }
 }
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Quit.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/permission/PermissionChecker.java
similarity index 67%
copy from dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Quit.java
copy to dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/permission/PermissionChecker.java
index 9539db9dea..c7a8c6675f 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Quit.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/permission/PermissionChecker.java
@@ -14,17 +14,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.qos.command.impl;
+package org.apache.dubbo.qos.permission;
 
-import org.apache.dubbo.qos.command.BaseCommand;
+import org.apache.dubbo.common.extension.ExtensionScope;
+import org.apache.dubbo.common.extension.SPI;
 import org.apache.dubbo.qos.command.CommandContext;
-import org.apache.dubbo.qos.command.annotation.Cmd;
-import org.apache.dubbo.qos.common.QosConstants;
 
-@Cmd(name = "quit",summary = "quit telnet console")
-public class Quit implements BaseCommand {
-    @Override
-    public String execute(CommandContext commandContext, String[] args) {
-        return QosConstants.CLOSE;
-    }
+// qosPermissionChecker=xxx.xxx.xxxPermissionChecker
+@SPI(scope = ExtensionScope.FRAMEWORK)
+public interface PermissionChecker {
+    boolean access(CommandContext commandContext, PermissionLevel defaultCmdPermissionLevel);
 }
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/permission/PermissionLevel.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/permission/PermissionLevel.java
new file mode 100644
index 0000000000..9d4a74b160
--- /dev/null
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/permission/PermissionLevel.java
@@ -0,0 +1,67 @@
+/*
+ * 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.dubbo.qos.permission;
+
+import org.apache.dubbo.common.utils.StringUtils;
+
+import java.util.Arrays;
+
+public enum PermissionLevel {
+    /**
+     * the lowest permission level (default), can access with
+     * anonymousAccessPermissionLevel=PUBLIC / anonymousAccessPermissionLevel=1 or higher
+     */
+    PUBLIC(1),
+    /**
+     * the middle permission level, default permission for each cmd
+     */
+    PROTECTED(2),
+    /**
+     * the highest permission level, suppose only the localhost can access this command
+     */
+    PRIVATE(3),
+
+    /**
+     * It is the reserved  anonymous permission level, can not access any command
+     */
+    NONE(Integer.MIN_VALUE),
+
+    ;
+    private final int level;
+
+    PermissionLevel(int level) {
+        this.level = level;
+    }
+
+    public int getLevel() {
+        return level;
+    }
+
+    // find the permission level by the level value, if not found, return default PUBLIC level
+    public static PermissionLevel from(String permissionLevel) {
+        if (StringUtils.isNumber(permissionLevel)) {
+            return Arrays.stream(values())
+                .filter(p -> String.valueOf(p.getLevel()).equals(permissionLevel.trim()))
+                .findFirst()
+                .orElse(PUBLIC);
+        }
+        return Arrays.stream(values())
+            .filter(p -> p.name().equalsIgnoreCase(String.valueOf(permissionLevel).trim()))
+            .findFirst()
+            .orElse(PUBLIC);
+    }
+}
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/protocol/QosProtocolWrapper.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/protocol/QosProtocolWrapper.java
index 32b32c4cbf..c16a25f98c 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/protocol/QosProtocolWrapper.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/protocol/QosProtocolWrapper.java
@@ -21,6 +21,7 @@ import org.apache.dubbo.common.extension.Activate;
 import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.qos.permission.PermissionLevel;
 import org.apache.dubbo.qos.common.QosConstants;
 import org.apache.dubbo.qos.pu.QosWireProtocol;
 import org.apache.dubbo.qos.server.Server;
@@ -39,6 +40,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_FAILED_START_SERVER;
 import static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;
 import static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP_WHITELIST;
+import static org.apache.dubbo.common.constants.QosConstants.ANONYMOUS_ACCESS_PERMISSION_LEVEL;
 import static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;
 import static org.apache.dubbo.common.constants.QosConstants.QOS_HOST;
 import static org.apache.dubbo.common.constants.QosConstants.QOS_PORT;
@@ -116,6 +118,7 @@ public class QosProtocolWrapper implements Protocol, ScopeModelAware {
             int port = url.getParameter(QOS_PORT, QosConstants.DEFAULT_PORT);
             boolean acceptForeignIp = Boolean.parseBoolean(url.getParameter(ACCEPT_FOREIGN_IP, "false"));
             String acceptForeignIpWhitelist = url.getParameter(ACCEPT_FOREIGN_IP_WHITELIST, StringUtils.EMPTY_STRING);
+            String anonymousAccessPermissionLevel = url.getParameter(ANONYMOUS_ACCESS_PERMISSION_LEVEL, PermissionLevel.PUBLIC.name());
             Server server = frameworkModel.getBeanFactory().getBean(Server.class);
 
             if (server.isStarted()) {
@@ -126,6 +129,7 @@ public class QosProtocolWrapper implements Protocol, ScopeModelAware {
             server.setPort(port);
             server.setAcceptForeignIp(acceptForeignIp);
             server.setAcceptForeignIpWhitelist(acceptForeignIpWhitelist);
+            server.setAnonymousAccessPermissionLevel(anonymousAccessPermissionLevel);
             server.start();
 
         } catch (Throwable throwable) {
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/pu/QosWireProtocol.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/pu/QosWireProtocol.java
index 889f533226..14f20f4cb3 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/pu/QosWireProtocol.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/pu/QosWireProtocol.java
@@ -19,7 +19,9 @@ package org.apache.dubbo.qos.pu;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.extension.Activate;
 import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.qos.permission.PermissionLevel;
 import org.apache.dubbo.qos.server.DubboLogo;
+import org.apache.dubbo.qos.common.QosConfiguration;
 import org.apache.dubbo.qos.server.handler.QosProcessHandler;
 import org.apache.dubbo.remoting.ChannelHandler;
 import org.apache.dubbo.remoting.api.AbstractWireProtocol;
@@ -46,7 +48,13 @@ public class QosWireProtocol extends AbstractWireProtocol implements ScopeModelA
     public void configServerProtocolHandler(URL url, ChannelOperator operator) {
         // add qosProcess handler
         QosProcessHandler handler = new QosProcessHandler(url.getOrDefaultFrameworkModel(),
-            DubboLogo.DUBBO, false, StringUtils.EMPTY_STRING);
+            QosConfiguration.builder()
+                .welcome(DubboLogo.DUBBO)
+                .acceptForeignIp(false)
+                .acceptForeignIpWhitelist(StringUtils.EMPTY_STRING)
+                .anonymousAccessPermissionLevel(PermissionLevel.PUBLIC.name())
+                .build()
+        );
         List<ChannelHandler> handlers = new ArrayList<>();
         handlers.add(new ChannelHandlerPretender(handler));
         operator.configChannelHandler(handlers);
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/Server.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/Server.java
index 2d60b24457..836fa47379 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/Server.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/Server.java
@@ -19,6 +19,8 @@ package org.apache.dubbo.qos.server;
 import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.qos.permission.PermissionLevel;
+import org.apache.dubbo.qos.common.QosConfiguration;
 import org.apache.dubbo.qos.server.handler.QosProcessHandler;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
@@ -54,6 +56,8 @@ public class Server {
     private boolean acceptForeignIp = true;
     private String acceptForeignIpWhitelist = StringUtils.EMPTY_STRING;
 
+    private String anonymousAccessPermissionLevel = PermissionLevel.NONE.name();
+
     private EventLoopGroup boss;
 
     private EventLoopGroup worker;
@@ -98,7 +102,14 @@ public class Server {
 
             @Override
             protected void initChannel(Channel ch) throws Exception {
-                ch.pipeline().addLast(new QosProcessHandler(frameworkModel, welcome, acceptForeignIp, acceptForeignIpWhitelist));
+                ch.pipeline().addLast(new QosProcessHandler(frameworkModel,
+                    QosConfiguration.builder()
+                        .welcome(welcome)
+                        .acceptForeignIp(acceptForeignIp)
+                        .acceptForeignIpWhitelist(acceptForeignIpWhitelist)
+                        .anonymousAccessPermissionLevel(anonymousAccessPermissionLevel)
+                        .build()
+                ));
             }
         });
         try {
@@ -152,6 +163,10 @@ public class Server {
         this.acceptForeignIpWhitelist = acceptForeignIpWhitelist;
     }
 
+    public void setAnonymousAccessPermissionLevel(String anonymousAccessPermissionLevel) {
+        this.anonymousAccessPermissionLevel = anonymousAccessPermissionLevel;
+    }
+
     public String getWelcome() {
         return welcome;
     }
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/ForeignHostPermitHandler.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/ForeignHostPermitHandler.java
index c63072a9de..e385c4d6aa 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/ForeignHostPermitHandler.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/ForeignHostPermitHandler.java
@@ -24,6 +24,7 @@ import io.netty.channel.ChannelHandlerContext;
 import org.apache.dubbo.common.utils.NetUtils;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.qos.common.QosConstants;
+import org.apache.dubbo.qos.common.QosConfiguration;
 
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
@@ -34,18 +35,21 @@ import java.util.function.Predicate;
 public class ForeignHostPermitHandler extends ChannelHandlerAdapter {
 
     // true means to accept foreign IP
-    private  boolean acceptForeignIp;
+    private final boolean acceptForeignIp;
 
     // the whitelist of foreign IP when acceptForeignIp = false, the delimiter is colon(,)
     // support specific ip and an ip range from CIDR specification
-    private String acceptForeignIpWhitelist;
+    private final String acceptForeignIpWhitelist;
     private Predicate<String> whitelistPredicate = foreignIp -> false;
 
-    public ForeignHostPermitHandler(boolean acceptForeignIp, String foreignIpWhitelist) {
-        this.acceptForeignIp = acceptForeignIp;
-        this.acceptForeignIpWhitelist = foreignIpWhitelist;
-        if (StringUtils.isNotEmpty(foreignIpWhitelist)) {
-            whitelistPredicate = Arrays.stream(foreignIpWhitelist.split(","))
+    private final QosConfiguration qosConfiguration;
+
+    public ForeignHostPermitHandler(QosConfiguration qosConfiguration) {
+        this.qosConfiguration = qosConfiguration;
+        this.acceptForeignIp = qosConfiguration.isAcceptForeignIp();
+        this.acceptForeignIpWhitelist = qosConfiguration.getAcceptForeignIpWhitelist();
+        if (StringUtils.isNotEmpty(acceptForeignIpWhitelist)) {
+            whitelistPredicate = Arrays.stream(acceptForeignIpWhitelist.split(","))
                 .map(String::trim)
                 .filter(StringUtils::isNotEmpty)
                 .map(foreignIpPattern -> (Predicate<String>) foreignIp -> {
@@ -67,6 +71,12 @@ public class ForeignHostPermitHandler extends ChannelHandlerAdapter {
             return;
         }
 
+        // the anonymous access is enabled by default, permission level is PUBLIC
+        // if allow anonymous access, return
+        if (qosConfiguration.isAllowAnonymousAccess()) {
+            return;
+        }
+
         final InetAddress inetAddress = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress();
         // loopback address, return
         if (inetAddress.isLoopbackAddress()) {
@@ -78,6 +88,7 @@ public class ForeignHostPermitHandler extends ChannelHandlerAdapter {
             return;
         }
 
+
         ByteBuf cb = Unpooled.wrappedBuffer((QosConstants.BR_STR + "Foreign Ip Not Permitted, Consider Config It In Whitelist."
             + QosConstants.BR_STR).getBytes());
         ctx.writeAndFlush(cb).addListener(ChannelFutureListener.CLOSE);
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/HttpProcessHandler.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/HttpProcessHandler.java
index 6af1b5e9f3..0d9acedaab 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/HttpProcessHandler.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/HttpProcessHandler.java
@@ -21,8 +21,10 @@ import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.qos.command.CommandContext;
 import org.apache.dubbo.qos.command.CommandExecutor;
 import org.apache.dubbo.qos.command.DefaultCommandExecutor;
-import org.apache.dubbo.qos.command.NoSuchCommandException;
+import org.apache.dubbo.qos.command.exception.NoSuchCommandException;
+import org.apache.dubbo.qos.command.exception.PermissionDenyException;
 import org.apache.dubbo.qos.command.decoder.HttpCommandDecoder;
+import org.apache.dubbo.qos.common.QosConfiguration;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
 import io.netty.buffer.Unpooled;
@@ -39,6 +41,7 @@ import io.netty.handler.codec.http.HttpVersion;
 
 import static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_COMMAND_NOT_FOUND;
 import static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_UNEXPECTED_EXCEPTION;
+import static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_PERMISSION_DENY_EXCEPTION;
 
 /**
  * Parse HttpRequest for uri and parameters
@@ -54,10 +57,13 @@ import static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_UNEXPECT
 public class HttpProcessHandler extends SimpleChannelInboundHandler<HttpRequest> {
 
     private static final ErrorTypeAwareLogger log = LoggerFactory.getErrorTypeAwareLogger(HttpProcessHandler.class);
-    private CommandExecutor commandExecutor;
+    private final CommandExecutor commandExecutor;
 
-    public HttpProcessHandler(FrameworkModel frameworkModel) {
+    private final QosConfiguration qosConfiguration;
+
+    public HttpProcessHandler(FrameworkModel frameworkModel, QosConfiguration qosConfiguration) {
         this.commandExecutor = new DefaultCommandExecutor(frameworkModel);
+        this.qosConfiguration = qosConfiguration;
     }
 
     private static FullHttpResponse http(int httpCode, String result) {
@@ -69,8 +75,8 @@ public class HttpProcessHandler extends SimpleChannelInboundHandler<HttpRequest>
         return response;
     }
 
-    private static FullHttpResponse http404() {
-        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND);
+    private static FullHttpResponse http(int httpCode) {
+        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(httpCode));
         HttpHeaders httpHeaders = response.headers();
         httpHeaders.set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
         httpHeaders.set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
@@ -83,10 +89,11 @@ public class HttpProcessHandler extends SimpleChannelInboundHandler<HttpRequest>
         // return 404 when fail to construct command context
         if (commandContext == null) {
             log.warn(QOS_UNEXPECTED_EXCEPTION, "", "", "can not found commandContext, url: " + msg.uri());
-            FullHttpResponse response = http404();
+            FullHttpResponse response = http(404);
             ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
         } else {
             commandContext.setRemote(ctx.channel());
+            commandContext.setQosConfiguration(qosConfiguration);
             try {
                 String result = commandExecutor.execute(commandContext);
                 int httpCode = commandContext.getHttpCode();
@@ -94,7 +101,11 @@ public class HttpProcessHandler extends SimpleChannelInboundHandler<HttpRequest>
                 ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
             } catch (NoSuchCommandException ex) {
                 log.error(QOS_COMMAND_NOT_FOUND, "", "", "can not find command: " + commandContext, ex);
-                FullHttpResponse response = http404();
+                FullHttpResponse response = http(404);
+                ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
+            } catch (PermissionDenyException ex) {
+                log.error(QOS_PERMISSION_DENY_EXCEPTION, "", "", "permission deny to access command: " + commandContext, ex);
+                FullHttpResponse response = http(403);
                 ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
             } catch (Exception qosEx) {
                 log.error(QOS_UNEXPECTED_EXCEPTION, "", "", "execute commandContext: " + commandContext + " got exception", qosEx);
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/QosProcessHandler.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/QosProcessHandler.java
index 32d89f7278..98cd08741e 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/QosProcessHandler.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/QosProcessHandler.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.qos.server.handler;
 
 import org.apache.dubbo.common.utils.ExecutorUtil;
+import org.apache.dubbo.qos.common.QosConfiguration;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
 import io.netty.buffer.ByteBuf;
@@ -41,25 +42,21 @@ public class QosProcessHandler extends ByteToMessageDecoder {
 
     private ScheduledFuture<?> welcomeFuture;
 
-    private String welcome;
-    // true means to accept foreign IP
-    private boolean acceptForeignIp;
-    private String acceptForeignIpWhitelist;
-
-    private FrameworkModel frameworkModel;
+    private final FrameworkModel frameworkModel;
 
     public static final String PROMPT = "dubbo>";
 
-    public QosProcessHandler(FrameworkModel frameworkModel, String welcome, boolean acceptForeignIp, String acceptForeignIpWhitelist) {
+    private final QosConfiguration qosConfiguration;
+
+    public QosProcessHandler(FrameworkModel frameworkModel, QosConfiguration qosConfiguration) {
         this.frameworkModel = frameworkModel;
-        this.welcome = welcome;
-        this.acceptForeignIp = acceptForeignIp;
-        this.acceptForeignIpWhitelist = acceptForeignIpWhitelist;
+        this.qosConfiguration = qosConfiguration;
     }
 
     @Override
     public void channelActive(final ChannelHandlerContext ctx) throws Exception {
         welcomeFuture = ctx.executor().schedule(() -> {
+            final String welcome = qosConfiguration.getWelcome();
             if (welcome != null) {
                 ctx.write(Unpooled.wrappedBuffer(welcome.getBytes()));
                 ctx.writeAndFlush(Unpooled.wrappedBuffer(PROMPT.getBytes()));
@@ -77,7 +74,7 @@ public class QosProcessHandler extends ByteToMessageDecoder {
         final int magic = in.getByte(in.readerIndex());
 
         ChannelPipeline p = ctx.pipeline();
-        p.addLast(new ForeignHostPermitHandler(acceptForeignIp, acceptForeignIpWhitelist));
+        p.addLast(new ForeignHostPermitHandler(qosConfiguration));
         if (isHttp(magic)) {
             // no welcome output for http protocol
             if (welcomeFuture != null && welcomeFuture.isCancellable()) {
@@ -85,7 +82,7 @@ public class QosProcessHandler extends ByteToMessageDecoder {
             }
             p.addLast(new HttpServerCodec());
             p.addLast(new HttpObjectAggregator(1048576));
-            p.addLast(new HttpProcessHandler(frameworkModel));
+            p.addLast(new HttpProcessHandler(frameworkModel, qosConfiguration));
             p.remove(this);
         } else {
             p.addLast(new LineBasedFrameDecoder(2048));
@@ -93,7 +90,7 @@ public class QosProcessHandler extends ByteToMessageDecoder {
             p.addLast(new StringEncoder(CharsetUtil.UTF_8));
             p.addLast(new IdleStateHandler(0, 0, 5 * 60));
             p.addLast(new TelnetIdleEventHandler());
-            p.addLast(new TelnetProcessHandler(frameworkModel));
+            p.addLast(new TelnetProcessHandler(frameworkModel, qosConfiguration));
             p.remove(this);
         }
     }
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/TelnetProcessHandler.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/TelnetProcessHandler.java
index 54ed428614..d5c7df4121 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/TelnetProcessHandler.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/TelnetProcessHandler.java
@@ -22,9 +22,11 @@ import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.qos.command.CommandContext;
 import org.apache.dubbo.qos.command.CommandExecutor;
 import org.apache.dubbo.qos.command.DefaultCommandExecutor;
-import org.apache.dubbo.qos.command.NoSuchCommandException;
+import org.apache.dubbo.qos.command.exception.NoSuchCommandException;
+import org.apache.dubbo.qos.command.exception.PermissionDenyException;
 import org.apache.dubbo.qos.command.decoder.TelnetCommandDecoder;
 import org.apache.dubbo.qos.common.QosConstants;
+import org.apache.dubbo.qos.common.QosConfiguration;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
 import io.netty.channel.ChannelFutureListener;
@@ -33,6 +35,7 @@ import io.netty.channel.SimpleChannelInboundHandler;
 
 import static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_COMMAND_NOT_FOUND;
 import static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_UNEXPECTED_EXCEPTION;
+import static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_PERMISSION_DENY_EXCEPTION;
 
 /**
  * Telnet process handler
@@ -42,8 +45,11 @@ public class TelnetProcessHandler extends SimpleChannelInboundHandler<String> {
     private static final ErrorTypeAwareLogger log = LoggerFactory.getErrorTypeAwareLogger(TelnetProcessHandler.class);
     private final CommandExecutor commandExecutor;
 
-    public TelnetProcessHandler(FrameworkModel frameworkModel) {
+    private final QosConfiguration qosConfiguration;
+
+    public TelnetProcessHandler(FrameworkModel frameworkModel, QosConfiguration qosConfiguration) {
         this.commandExecutor = new DefaultCommandExecutor(frameworkModel);
+        this.qosConfiguration = qosConfiguration;
     }
 
     @Override
@@ -53,6 +59,7 @@ public class TelnetProcessHandler extends SimpleChannelInboundHandler<String> {
             ctx.writeAndFlush(QosProcessHandler.PROMPT);
         } else {
             CommandContext commandContext = TelnetCommandDecoder.decode(msg);
+            commandContext.setQosConfiguration(qosConfiguration);
             commandContext.setRemote(ctx.channel());
 
             try {
@@ -66,6 +73,10 @@ public class TelnetProcessHandler extends SimpleChannelInboundHandler<String> {
                 ctx.writeAndFlush(msg + " :no such command");
                 ctx.writeAndFlush(QosConstants.BR_STR + QosProcessHandler.PROMPT);
                 log.error(QOS_COMMAND_NOT_FOUND, "", "", "can not found command " + commandContext, ex);
+            } catch (PermissionDenyException ex) {
+                ctx.writeAndFlush(msg + " :permission deny");
+                ctx.writeAndFlush(QosConstants.BR_STR + QosProcessHandler.PROMPT);
+                log.error(QOS_PERMISSION_DENY_EXCEPTION, "", "", "permission deny to access command " + commandContext, ex);
             } catch (Exception ex) {
                 ctx.writeAndFlush(msg + " :fail to execute commandContext by " + ex.getMessage());
                 ctx.writeAndFlush(QosConstants.BR_STR + QosProcessHandler.PROMPT);
diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/DefaultCommandExecutorTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/DefaultCommandExecutorTest.java
index dc988059d4..90e0cacd3e 100644
--- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/DefaultCommandExecutorTest.java
+++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/DefaultCommandExecutorTest.java
@@ -17,6 +17,10 @@
 
 package org.apache.dubbo.qos.command;
 
+import org.apache.dubbo.qos.command.exception.NoSuchCommandException;
+import org.apache.dubbo.qos.command.exception.PermissionDenyException;
+import org.apache.dubbo.qos.common.QosConfiguration;
+import org.apache.dubbo.qos.permission.PermissionLevel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
 import org.junit.jupiter.api.Assertions;
@@ -37,7 +41,28 @@ class DefaultCommandExecutorTest {
     @Test
     void testExecute2() throws Exception {
         DefaultCommandExecutor executor = new DefaultCommandExecutor(FrameworkModel.defaultModel());
-        String result = executor.execute(CommandContextFactory.newInstance("greeting", new String[]{"dubbo"}, false));
+        final CommandContext commandContext = CommandContextFactory.newInstance("greeting", new String[]{"dubbo"}, false);
+        commandContext.setQosConfiguration(QosConfiguration.builder()
+            .anonymousAccessPermissionLevel(PermissionLevel.PROTECTED.name())
+            .build());
+        String result = executor.execute(commandContext);
         assertThat(result, equalTo("greeting dubbo"));
     }
-}
\ No newline at end of file
+
+    @Test
+    void shouldNotThrowPermissionDenyException_GivenPermissionConfigAndMatchDefaultPUBLICCmdPermissionLevel() throws Exception {
+        DefaultCommandExecutor executor = new DefaultCommandExecutor(FrameworkModel.defaultModel());
+        final CommandContext commandContext = CommandContextFactory.newInstance("live", new String[]{"dubbo"}, false);
+        commandContext.setQosConfiguration(QosConfiguration.builder().build());
+        Assertions.assertDoesNotThrow(() -> executor.execute(commandContext));
+    }
+
+    @Test
+    void shouldNotThrowPermissionDenyException_GivenPermissionConfigAndNotMatchCmdPermissionLevel() throws Exception {
+        DefaultCommandExecutor executor = new DefaultCommandExecutor(FrameworkModel.defaultModel());
+        final CommandContext commandContext = CommandContextFactory.newInstance("live", new String[]{"dubbo"}, false);
+        // 1 PROTECTED
+        commandContext.setQosConfiguration(QosConfiguration.builder().anonymousAccessPermissionLevel("1").build());
+        Assertions.assertDoesNotThrow(() -> executor.execute(commandContext));
+    }
+}
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/DefaultCommandExecutor.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/pu/QosWireProtocolTest.java
similarity index 51%
copy from dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/DefaultCommandExecutor.java
copy to dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/pu/QosWireProtocolTest.java
index 12cd5f9b9e..febeda154f 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/DefaultCommandExecutor.java
+++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/pu/QosWireProtocolTest.java
@@ -14,28 +14,28 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.qos.command;
 
+package org.apache.dubbo.qos.pu;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.remoting.api.pu.ChannelOperator;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
-public class DefaultCommandExecutor implements CommandExecutor {
-    private FrameworkModel frameworkModel;
+import org.junit.jupiter.api.Test;
 
-    public DefaultCommandExecutor(FrameworkModel frameworkModel) {
-        this.frameworkModel = frameworkModel;
-    }
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+class QosWireProtocolTest {
+
+    @Test
+    void ShouldNotThrowExOnConfigServerProtocolHandler_GivenHappyPassConfig() {
+        final QosWireProtocol target = new QosWireProtocol(FrameworkModel.defaultModel());
+        final URL url = mock(URL.class);
+        final ChannelOperator channelOperator = mock(ChannelOperator.class);
+        target.configServerProtocolHandler(url, channelOperator);
+        verify(channelOperator).configChannelHandler(anyList());
 
-    @Override
-    public String execute(CommandContext commandContext) throws NoSuchCommandException {
-        BaseCommand command = null;
-        try {
-            command = frameworkModel.getExtensionLoader(BaseCommand.class).getExtension(commandContext.getCommandName());
-        } catch (Throwable throwable) {
-                //can't find command
-        }
-        if (command == null) {
-            throw new NoSuchCommandException(commandContext.getCommandName());
-        }
-        return command.execute(commandContext, commandContext.getArgs());
     }
 }
diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/ForeignHostPermitHandlerTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/ForeignHostPermitHandlerTest.java
index 0cebdbdc67..91bd5f9092 100644
--- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/ForeignHostPermitHandlerTest.java
+++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/ForeignHostPermitHandlerTest.java
@@ -22,6 +22,8 @@ import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
 import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.qos.permission.PermissionLevel;
+import org.apache.dubbo.qos.common.QosConfiguration;
 import org.junit.jupiter.api.Test;
 import org.mockito.ArgumentCaptor;
 
@@ -48,7 +50,13 @@ class ForeignHostPermitHandlerTest {
         when(channel.remoteAddress()).thenReturn(address);
         ChannelFuture future = mock(ChannelFuture.class);
         when(context.writeAndFlush(any(ByteBuf.class))).thenReturn(future);
-        ForeignHostPermitHandler handler = new ForeignHostPermitHandler(false, StringUtils.EMPTY_STRING);
+        ForeignHostPermitHandler handler = new ForeignHostPermitHandler(
+            QosConfiguration.builder()
+                .acceptForeignIp(false)
+                .acceptForeignIpWhitelist(StringUtils.EMPTY_STRING)
+                .anonymousAccessPermissionLevel(PermissionLevel.NONE.name())
+                .build()
+        );
         handler.handlerAdded(context);
         ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class);
         verify(context).writeAndFlush(captor.capture());
@@ -68,7 +76,14 @@ class ForeignHostPermitHandlerTest {
         when(channel.remoteAddress()).thenReturn(address);
         ChannelFuture future = mock(ChannelFuture.class);
         when(context.writeAndFlush(any(ByteBuf.class))).thenReturn(future);
-        ForeignHostPermitHandler handler = new ForeignHostPermitHandler(false, "175.23.44.1 ,  192.168.1.192/26");
+        ForeignHostPermitHandler handler = new ForeignHostPermitHandler(
+            QosConfiguration.builder()
+                .acceptForeignIp(false)
+                .acceptForeignIpWhitelist("175.23.44.1 ,  192.168.1.192/26")
+                .anonymousAccessPermissionLevel(PermissionLevel.NONE.name())
+                .build()
+        );
+
         handler.handlerAdded(context);
         ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class);
         verify(context).writeAndFlush(captor.capture());
@@ -87,7 +102,12 @@ class ForeignHostPermitHandlerTest {
         InetSocketAddress address = new InetSocketAddress(addr, 12345);
         when(channel.remoteAddress()).thenReturn(address);
 
-        ForeignHostPermitHandler handler = new ForeignHostPermitHandler(false, "175.23.44.1, 192.168.1.192/26  ");
+        ForeignHostPermitHandler handler = new ForeignHostPermitHandler(
+            QosConfiguration.builder()
+                .acceptForeignIp(false)
+                .acceptForeignIpWhitelist("175.23.44.1, 192.168.1.192/26  ")
+                .build()
+        );
         handler.handlerAdded(context);
         verify(context, never()).writeAndFlush(any());
     }
@@ -103,8 +123,32 @@ class ForeignHostPermitHandlerTest {
         InetSocketAddress address = new InetSocketAddress(addr, 12345);
         when(channel.remoteAddress()).thenReturn(address);
 
-        ForeignHostPermitHandler handler = new ForeignHostPermitHandler(false, "175.23.44.1, 192.168.1.192/26");
+        ForeignHostPermitHandler handler = new ForeignHostPermitHandler(
+            QosConfiguration.builder()
+                .acceptForeignIp(false)
+                .acceptForeignIpWhitelist("175.23.44.1, 192.168.1.192/26")
+                .build()
+        );
         handler.handlerAdded(context);
         verify(context, never()).writeAndFlush(any());
     }
+
+    @Test
+    void shouldNotShowIpNotPermittedMsg_GivenAcceptForeignIpFalseAndNotMatchWhiteListAndPermissionConfig() throws Exception {
+        ChannelHandlerContext context = mock(ChannelHandlerContext.class);
+        Channel channel = mock(Channel.class);
+        when(context.channel()).thenReturn(channel);
+        ChannelFuture future = mock(ChannelFuture.class);
+        when(context.writeAndFlush(any(ByteBuf.class))).thenReturn(future);
+        ForeignHostPermitHandler handler = new ForeignHostPermitHandler(
+            QosConfiguration.builder()
+                .acceptForeignIp(false)
+                .acceptForeignIpWhitelist("175.23.44.1 ,  192.168.1.192/26")
+                .anonymousAccessPermissionLevel(PermissionLevel.PROTECTED.name())
+                .build()
+        );
+
+        handler.handlerAdded(context);
+        verify(future, never()).addListener(ChannelFutureListener.CLOSE);
+    }
 }
diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/HttpProcessHandlerTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/HttpProcessHandlerTest.java
index 84745ca830..820b09c850 100644
--- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/HttpProcessHandlerTest.java
+++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/HttpProcessHandlerTest.java
@@ -16,6 +16,8 @@
  */
 package org.apache.dubbo.qos.server.handler;
 
+import org.apache.dubbo.qos.common.QosConfiguration;
+import org.apache.dubbo.qos.permission.PermissionLevel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
 import io.netty.channel.ChannelFuture;
@@ -43,7 +45,7 @@ class HttpProcessHandlerTest {
         when(context.writeAndFlush(any(FullHttpResponse.class))).thenReturn(future);
         HttpRequest message = Mockito.mock(HttpRequest.class);
         when(message.uri()).thenReturn("test");
-        HttpProcessHandler handler = new HttpProcessHandler(FrameworkModel.defaultModel());
+        HttpProcessHandler handler = new HttpProcessHandler(FrameworkModel.defaultModel(), QosConfiguration.builder().build());
         handler.channelRead0(context, message);
         verify(future).addListener(ChannelFutureListener.CLOSE);
         ArgumentCaptor<FullHttpResponse> captor = ArgumentCaptor.forClass(FullHttpResponse.class);
@@ -60,7 +62,10 @@ class HttpProcessHandlerTest {
         HttpRequest message = Mockito.mock(HttpRequest.class);
         when(message.uri()).thenReturn("localhost:80/greeting");
         when(message.method()).thenReturn(HttpMethod.GET);
-        HttpProcessHandler handler = new HttpProcessHandler(FrameworkModel.defaultModel());
+        HttpProcessHandler handler = new HttpProcessHandler(FrameworkModel.defaultModel(),
+            QosConfiguration.builder()
+                .anonymousAccessPermissionLevel(PermissionLevel.NONE.name())
+                .build());
         handler.channelRead0(context, message);
         verify(future).addListener(ChannelFutureListener.CLOSE);
         ArgumentCaptor<FullHttpResponse> captor = ArgumentCaptor.forClass(FullHttpResponse.class);
@@ -77,7 +82,10 @@ class HttpProcessHandlerTest {
         HttpRequest message = Mockito.mock(HttpRequest.class);
         when(message.uri()).thenReturn("localhost:80/test");
         when(message.method()).thenReturn(HttpMethod.GET);
-        HttpProcessHandler handler = new HttpProcessHandler(FrameworkModel.defaultModel());
+        HttpProcessHandler handler = new HttpProcessHandler(FrameworkModel.defaultModel(),
+            QosConfiguration.builder()
+                .anonymousAccessPermissionLevel(PermissionLevel.NONE.name())
+                .build());
         handler.channelRead0(context, message);
         verify(future).addListener(ChannelFutureListener.CLOSE);
         ArgumentCaptor<FullHttpResponse> captor = ArgumentCaptor.forClass(FullHttpResponse.class);
@@ -85,4 +93,4 @@ class HttpProcessHandlerTest {
         FullHttpResponse response = captor.getValue();
         assertThat(response.status().code(), equalTo(404));
     }
-}
\ No newline at end of file
+}
diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/QosProcessHandlerTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/QosProcessHandlerTest.java
index 3649bcdeca..dbac3e68b1 100644
--- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/QosProcessHandlerTest.java
+++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/QosProcessHandlerTest.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.qos.server.handler;
 
 import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.qos.common.QosConfiguration;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
 import io.netty.buffer.ByteBuf;
@@ -43,7 +44,13 @@ class QosProcessHandlerTest {
         ChannelHandlerContext context = Mockito.mock(ChannelHandlerContext.class);
         ChannelPipeline pipeline = Mockito.mock(ChannelPipeline.class);
         Mockito.when(context.pipeline()).thenReturn(pipeline);
-        QosProcessHandler handler = new QosProcessHandler(FrameworkModel.defaultModel(), "welcome", false, StringUtils.EMPTY_STRING);
+        QosProcessHandler handler = new QosProcessHandler(FrameworkModel.defaultModel(),
+            QosConfiguration.builder()
+                .welcome("welcome")
+                .acceptForeignIp(false)
+                .acceptForeignIpWhitelist(StringUtils.EMPTY_STRING)
+                .build()
+        );
         handler.decode(context, buf, Collections.emptyList());
         verify(pipeline).addLast(any(HttpServerCodec.class));
         verify(pipeline).addLast(any(HttpObjectAggregator.class));
@@ -57,7 +64,13 @@ class QosProcessHandlerTest {
         ChannelHandlerContext context = Mockito.mock(ChannelHandlerContext.class);
         ChannelPipeline pipeline = Mockito.mock(ChannelPipeline.class);
         Mockito.when(context.pipeline()).thenReturn(pipeline);
-        QosProcessHandler handler = new QosProcessHandler(FrameworkModel.defaultModel(), "welcome", false, StringUtils.EMPTY_STRING);
+        QosProcessHandler handler = new QosProcessHandler(FrameworkModel.defaultModel(),
+            QosConfiguration.builder()
+                .welcome("welcome")
+                .acceptForeignIp(false)
+                .acceptForeignIpWhitelist(StringUtils.EMPTY_STRING)
+                .build()
+        );
         handler.decode(context, buf, Collections.emptyList());
         verify(pipeline).addLast(any(LineBasedFrameDecoder.class));
         verify(pipeline).addLast(any(StringDecoder.class));
diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/TelnetProcessHandlerTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/TelnetProcessHandlerTest.java
index 3a256f877d..2a526931ce 100644
--- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/TelnetProcessHandlerTest.java
+++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/TelnetProcessHandlerTest.java
@@ -16,6 +16,8 @@
  */
 package org.apache.dubbo.qos.server.handler;
 
+import org.apache.dubbo.qos.common.QosConfiguration;
+import org.apache.dubbo.qos.permission.PermissionLevel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
 import io.netty.channel.ChannelFuture;
@@ -36,7 +38,10 @@ class TelnetProcessHandlerTest {
     @Test
     void testPrompt() throws Exception {
         ChannelHandlerContext context = mock(ChannelHandlerContext.class);
-        TelnetProcessHandler handler = new TelnetProcessHandler(FrameworkModel.defaultModel());
+        TelnetProcessHandler handler = new TelnetProcessHandler(FrameworkModel.defaultModel(),
+            QosConfiguration.builder()
+                .anonymousAccessPermissionLevel(PermissionLevel.NONE.name())
+                .build());
         handler.channelRead0(context, "");
         verify(context).writeAndFlush(QosProcessHandler.PROMPT);
     }
@@ -44,7 +49,7 @@ class TelnetProcessHandlerTest {
     @Test
     void testBye() throws Exception {
         ChannelHandlerContext context = mock(ChannelHandlerContext.class);
-        TelnetProcessHandler handler = new TelnetProcessHandler(FrameworkModel.defaultModel());
+        TelnetProcessHandler handler = new TelnetProcessHandler(FrameworkModel.defaultModel(), QosConfiguration.builder().build());
         ChannelFuture future = mock(ChannelFuture.class);
         when(context.writeAndFlush("BYE!\n")).thenReturn(future);
         handler.channelRead0(context, "quit");
@@ -54,7 +59,7 @@ class TelnetProcessHandlerTest {
     @Test
     void testUnknownCommand() throws Exception {
         ChannelHandlerContext context = mock(ChannelHandlerContext.class);
-        TelnetProcessHandler handler = new TelnetProcessHandler(FrameworkModel.defaultModel());
+        TelnetProcessHandler handler = new TelnetProcessHandler(FrameworkModel.defaultModel(), QosConfiguration.builder().build());
         handler.channelRead0(context, "unknown");
         ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
         verify(context, Mockito.atLeastOnce()).writeAndFlush(captor.capture());
@@ -64,11 +69,14 @@ class TelnetProcessHandlerTest {
     @Test
     void testGreeting() throws Exception {
         ChannelHandlerContext context = mock(ChannelHandlerContext.class);
-        TelnetProcessHandler handler = new TelnetProcessHandler(FrameworkModel.defaultModel());
+        TelnetProcessHandler handler = new TelnetProcessHandler(FrameworkModel.defaultModel(),
+            QosConfiguration.builder()
+                .anonymousAccessPermissionLevel(PermissionLevel.NONE.name())
+                .build());
         handler.channelRead0(context, "greeting");
         ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
         verify(context).writeAndFlush(captor.capture());
         assertThat(captor.getValue(), containsString("greeting"));
         assertThat(captor.getValue(), containsString("dubbo>"));
     }
-}
\ No newline at end of file
+}
diff --git a/dubbo-plugin/dubbo-qos/src/test/resources/META-INF/services/org.apache.dubbo.qos.permission.PermissionChecker b/dubbo-plugin/dubbo-qos/src/test/resources/META-INF/services/org.apache.dubbo.qos.permission.PermissionChecker
new file mode 100644
index 0000000000..83a2576611
--- /dev/null
+++ b/dubbo-plugin/dubbo-qos/src/test/resources/META-INF/services/org.apache.dubbo.qos.permission.PermissionChecker
@@ -0,0 +1 @@
+qosPermissionChecker=not.exist.mock.permissionChecker