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

liuhongyu 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 a1d4cdecff [Feature] Invalidate Previous Tokens on New Login by 
Implementing Client ID Validation (#5600)
a1d4cdecff is described below

commit a1d4cdecfff7929f0af7337e809bd2a5cd65110a
Author: VampireAchao <ac...@apache.org>
AuthorDate: Thu Aug 1 17:49:38 2024 +0800

    [Feature] Invalidate Previous Tokens on New Login by Implementing Client ID 
Validation (#5600)
    
    * [Feature] kick other token when dashboard user login
    
    * [Fix] fix ci problem
    
    * [Fix] fix ci problem
    
    * [Fix] fix ci problem
    
    * [Fix] fix e2e ci problem
    
    * [Improve] invalid token logic only frontend has client id
    
    ---------
    
    Co-authored-by: moremind <hefen...@apache.org>
---
 db/init/mysql/schema.sql                           |   3 +-
 db/init/og/create-table.sql                        |   3 +-
 db/init/oracle/schema.sql                          |   1 +
 db/init/pg/create-table.sql                        |   3 +-
 db/upgrade/2.6.1-upgrade-2.7.0-mysql.sql           |   3 +
 db/upgrade/2.6.1-upgrade-2.7.0-og.sql              |   4 +
 db/upgrade/2.6.1-upgrade-2.7.0-oracle.sql          |   4 +
 db/upgrade/2.6.1-upgrade-2.7.0-pg.sql              |   4 +
 .../admin/controller/PlatformController.java       |   6 +-
 .../shenyu/admin/model/dto/DashboardUserDTO.java   | 119 ++++++++++++++-------
 .../shenyu/admin/model/entity/DashboardUserDO.java |  37 +++++++
 .../shenyu/admin/model/vo/DashboardUserVO.java     |  27 ++++-
 .../shenyu/admin/service/DashboardUserService.java |  25 ++---
 .../service/impl/DashboardUserServiceImpl.java     |  85 ++++++++-------
 .../shenyu/admin/shiro/config/ShiroRealm.java      |   7 +-
 .../admin/transfer/DashboardUserTransfer.java      |   1 +
 .../org/apache/shenyu/admin/utils/JwtUtils.java    |  36 +++++--
 .../resources/mappers/dashboard-user-sqlmap.xml    |  22 +++-
 .../src/main/resources/sql-script/h2/schema.sql    |   1 +
 .../controller/DashboardUserControllerTest.java    |   3 +-
 .../admin/controller/PlatformControllerTest.java   |   9 +-
 .../admin/service/DashboardUserServiceTest.java    |  12 +--
 .../apache/shenyu/admin/utils/JwtUtilsTest.java    |  11 +-
 23 files changed, 299 insertions(+), 127 deletions(-)

diff --git a/db/init/mysql/schema.sql b/db/init/mysql/schema.sql
index 86e9aa0a88..5eab7a2438 100644
--- a/db/init/mysql/schema.sql
+++ b/db/init/mysql/schema.sql
@@ -154,6 +154,7 @@ CREATE TABLE `dashboard_user`  (
   `password` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci 
NULL DEFAULT NULL COMMENT 'user password',
   `role` int(0) NOT NULL COMMENT 'role',
   `enabled` tinyint(0) NOT NULL COMMENT 'delete or not (0 close, 1 open) ',
+  `client_id` varchar(32) DEFAULT NULL COMMENT 'client id',
   `date_created` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 
'create time',
   `date_updated` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE 
CURRENT_TIMESTAMP(3) COMMENT 'update time',
   PRIMARY KEY (`id`) USING BTREE,
@@ -163,7 +164,7 @@ CREATE TABLE `dashboard_user`  (
 -- ----------------------------
 -- Records of dashboard_user
 -- ----------------------------
-INSERT INTO `dashboard_user` VALUES ('1', 'admin', 
'ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413',
 1, 1, '2022-05-25 18:02:52', '2022-05-25 18:02:52');
+INSERT INTO `dashboard_user` VALUES ('1', 'admin', 
'ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413',
 1, 1, null, '2022-05-25 18:02:52', '2022-05-25 18:02:52');
 
 -- ----------------------------
 -- Table structure for data_permission
diff --git a/db/init/og/create-table.sql b/db/init/og/create-table.sql
index 80b597f843..e9227ce8ca 100644
--- a/db/init/og/create-table.sql
+++ b/db/init/og/create-table.sql
@@ -202,6 +202,7 @@ CREATE TABLE "public"."dashboard_user" (
   "password" varchar(128) COLLATE "pg_catalog"."default",
   "role" int4 NOT NULL,
   "enabled" int2 NOT NULL,
+  "client_id" varchar(32) COLLATE "pg_catalog"."default",
   "date_created" timestamp(6) NOT NULL DEFAULT timezone('UTC-8'::text, 
(now())::timestamp(0) without time zone),
   "date_updated" timestamp(6) NOT NULL DEFAULT timezone('UTC-8'::text, 
(now())::timestamp(0) without time zone)
 )
@@ -217,7 +218,7 @@ COMMENT ON COLUMN "public"."dashboard_user"."date_updated" 
IS 'update time';
 -- ----------------------------
 -- Records of dashboard_user
 -- ----------------------------
-INSERT INTO "public"."dashboard_user" VALUES ('1', 'admin', 
'ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413',
 1, 1, '2022-05-25 18:08:01', '2022-05-25 18:08:01');
+INSERT INTO "public"."dashboard_user" VALUES ('1', 'admin', 
'ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413',
 1, 1, null, '2022-05-25 18:08:01', '2022-05-25 18:08:01');
 
 -- ----------------------------
 -- Table structure for data_permission
diff --git a/db/init/oracle/schema.sql b/db/init/oracle/schema.sql
index bfcca28224..8e9bb14b5f 100644
--- a/db/init/oracle/schema.sql
+++ b/db/init/oracle/schema.sql
@@ -21,6 +21,7 @@ create table dashboard_user
     password     VARCHAR2(128),
     role         NUMBER(10) not null,
     enabled      NUMBER(3) not null,
+    client_id     VARCHAR2(32),
     date_created timestamp(3) default SYSDATE not null,
     date_updated timestamp(3) default SYSDATE not null,
     PRIMARY KEY (id),
diff --git a/db/init/pg/create-table.sql b/db/init/pg/create-table.sql
index 7523e6b08c..6e12aa6ed6 100644
--- a/db/init/pg/create-table.sql
+++ b/db/init/pg/create-table.sql
@@ -202,6 +202,7 @@ CREATE TABLE "public"."dashboard_user" (
   "password" varchar(128) COLLATE "pg_catalog"."default",
   "role" int4 NOT NULL,
   "enabled" int2 NOT NULL,
+  "client_id" varchar(32) COLLATE "pg_catalog"."default",
   "date_created" timestamp(6) NOT NULL DEFAULT timezone('UTC-8'::text, 
(now())::timestamp(0) without time zone),
   "date_updated" timestamp(6) NOT NULL DEFAULT timezone('UTC-8'::text, 
(now())::timestamp(0) without time zone)
 )
@@ -217,7 +218,7 @@ COMMENT ON COLUMN "public"."dashboard_user"."date_updated" 
IS 'update time';
 -- ----------------------------
 -- Records of dashboard_user
 -- ----------------------------
-INSERT INTO "public"."dashboard_user" VALUES ('1', 'admin', 
'ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413',
 1, 1, '2022-05-25 18:08:01', '2022-05-25 18:08:01');
+INSERT INTO "public"."dashboard_user" VALUES ('1', 'admin', 
'ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413',
 1, 1, null, '2022-05-25 18:08:01', '2022-05-25 18:08:01');
 
 -- ----------------------------
 -- Table structure for data_permission
diff --git a/db/upgrade/2.6.1-upgrade-2.7.0-mysql.sql 
b/db/upgrade/2.6.1-upgrade-2.7.0-mysql.sql
index 289a9fc5cc..724a9b5a04 100755
--- a/db/upgrade/2.6.1-upgrade-2.7.0-mysql.sql
+++ b/db/upgrade/2.6.1-upgrade-2.7.0-mysql.sql
@@ -165,3 +165,6 @@ INSERT INTO `shenyu`.`permission` (`id`, `object_id`, 
`resource_id`, `date_creat
 INSERT INTO `shenyu`.`permission` (`id`, `object_id`, `resource_id`, 
`date_created`, `date_updated`) VALUES ('1792779493541343265', 
'1346358560427216896', '1792749362445840484', '2024-06-25 20:00:00.000', 
'2024-06-25 20:00:00.000');
 INSERT INTO `shenyu`.`permission` (`id`, `object_id`, `resource_id`, 
`date_created`, `date_updated`) VALUES ('1792779493541343266', 
'1346358560427216896', '1792749362445840485', '2024-06-25 20:00:00.000', 
'2024-06-25 20:00:00.000');
 INSERT INTO `shenyu`.`permission` (`id`, `object_id`, `resource_id`, 
`date_created`, `date_updated`) VALUES ('1792779493541343267', 
'1346358560427216896', '1792749362445840486', '2024-06-25 20:00:00.000', 
'2024-06-25 20:00:00.000');
+
+/* add column into dashboard_user table */
+ALTER TABLE `shenyu`.`dashboard_user` ADD COLUMN `client_id` varchar(32) NULL 
DEFAULT NULL COMMENT 'client id';
diff --git a/db/upgrade/2.6.1-upgrade-2.7.0-og.sql 
b/db/upgrade/2.6.1-upgrade-2.7.0-og.sql
index 97b7061274..f1cfc8f5eb 100644
--- a/db/upgrade/2.6.1-upgrade-2.7.0-og.sql
+++ b/db/upgrade/2.6.1-upgrade-2.7.0-og.sql
@@ -188,3 +188,7 @@ INSERT INTO "public"."permission" VALUES 
('1792779493541343264', '13463585604272
 INSERT INTO "public"."permission" VALUES ('1792779493541343265', 
'1346358560427216896', '1792749362445840484', '2024-06-25 20:00:00.000', 
'2024-06-25 20:00:00.000');
 INSERT INTO "public"."permission" VALUES ('1792779493541343266', 
'1346358560427216896', '1792749362445840485', '2024-06-25 20:00:00.000', 
'2024-06-25 20:00:00.000');
 INSERT INTO "public"."permission" VALUES ('1792779493541343267', 
'1346358560427216896', '1792749362445840486', '2024-06-25 20:00:00.000', 
'2024-06-25 20:00:00.000');
+
+/* add column into dashboard_user table */
+ALTER TABLE "public"."dashboard_user" ADD COLUMN client_id VARCHAR(32) NULL;
+COMMENT ON COLUMN "public"."dashboard_user".client_id IS 'client id';
diff --git a/db/upgrade/2.6.1-upgrade-2.7.0-oracle.sql 
b/db/upgrade/2.6.1-upgrade-2.7.0-oracle.sql
index 8b8ec0c45d..3de423095c 100755
--- a/db/upgrade/2.6.1-upgrade-2.7.0-oracle.sql
+++ b/db/upgrade/2.6.1-upgrade-2.7.0-oracle.sql
@@ -214,3 +214,7 @@ INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX (permission(id)) */ 
INTO permission (id, o
 INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX (permission(id)) */ INTO permission (id, 
object_id, resource_id) VALUES ('1792779493541343265', '1346358560427216896', 
'1792749362445840484');
 INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX (permission(id)) */ INTO permission (id, 
object_id, resource_id) VALUES ('1792779493541343266', '1346358560427216896', 
'1792749362445840485');
 INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX (permission(id)) */ INTO permission (id, 
object_id, resource_id) VALUES ('1792779493541343267', '1346358560427216896', 
'1792749362445840486');
+
+/* add column into dashboard_user table */
+ALTER TABLE dashboard_user ADD client_id VARCHAR(32) NULL;
+COMMENT ON COLUMN dashboard_user.client_id IS 'client id';
diff --git a/db/upgrade/2.6.1-upgrade-2.7.0-pg.sql 
b/db/upgrade/2.6.1-upgrade-2.7.0-pg.sql
index 36bab538dc..514de6e363 100755
--- a/db/upgrade/2.6.1-upgrade-2.7.0-pg.sql
+++ b/db/upgrade/2.6.1-upgrade-2.7.0-pg.sql
@@ -189,3 +189,7 @@ INSERT INTO "public"."permission" VALUES 
('1792779493541343264', '13463585604272
 INSERT INTO "public"."permission" VALUES ('1792779493541343265', 
'1346358560427216896', '1792749362445840484', '2024-06-25 20:00:00.000', 
'2024-06-25 20:00:00.000');
 INSERT INTO "public"."permission" VALUES ('1792779493541343266', 
'1346358560427216896', '1792749362445840485', '2024-06-25 20:00:00.000', 
'2024-06-25 20:00:00.000');
 INSERT INTO "public"."permission" VALUES ('1792779493541343267', 
'1346358560427216896', '1792749362445840486', '2024-06-25 20:00:00.000', 
'2024-06-25 20:00:00.000');
+
+/* add column into dashboard_user table */
+ALTER TABLE "public"."dashboard_user" ADD COLUMN client_id VARCHAR(32) NULL;
+COMMENT ON COLUMN "public"."dashboard_user".client_id IS 'client id';
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/PlatformController.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/PlatformController.java
index ef87439173..2944a7f89a 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/PlatformController.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/PlatformController.java
@@ -25,6 +25,7 @@ import org.apache.shenyu.admin.service.EnumService;
 import org.apache.shenyu.admin.service.SecretService;
 import org.apache.shenyu.admin.utils.ShenyuResultMessage;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 
 import java.util.Optional;
 
@@ -51,11 +52,12 @@ public class PlatformController {
      *
      * @param userName user name
      * @param password user password
+     * @param clientId client id
      * @return {@linkplain ShenyuAdminResult}
      */
     @GetMapping("/login")
-    public ShenyuAdminResult loginDashboardUser(final String userName, final 
String password) {
-        LoginDashboardUserVO loginVO = dashboardUserService.login(userName, 
password);
+    public ShenyuAdminResult loginDashboardUser(final String userName, final 
String password, @RequestParam(required = false) final String clientId) {
+        LoginDashboardUserVO loginVO = dashboardUserService.login(userName, 
password, clientId);
         return Optional.ofNullable(loginVO)
                 .map(loginStatus -> {
                     if (Boolean.TRUE.equals(loginStatus.getEnabled())) {
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/dto/DashboardUserDTO.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/dto/DashboardUserDTO.java
index 80ae509fab..a183533380 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/dto/DashboardUserDTO.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/dto/DashboardUserDTO.java
@@ -31,54 +31,60 @@ import java.util.Objects;
  * this is dashboard user from by web front.
  */
 public class DashboardUserDTO implements Serializable {
-    
+
     private static final long serialVersionUID = -7005615329360835626L;
-    
+
     /**
      * primary key.
      */
     private String id;
-    
+
     /**
      * user name.
      */
     @NotBlank
     private String userName;
-    
+
     /**
      * user password.
      */
     @Pattern(regexp = RegConstant.PASSWORD_RULE, message = '{' + 
FailI18nMessage.PASSWORD_MUST + '}')
     private String password;
-    
+
     /**
      * dashboard role.
      */
     private Integer role;
-    
+
     /**
      * current role list.
      */
     private List<@NotBlank String> roles;
-    
+
     /**
      * whether enabled.
      */
     @NotNull
     private Boolean enabled;
-    
+
+    /**
+     * clientId.
+     */
+    private String clientId;
+
     public DashboardUserDTO() {
     }
-    
-    public DashboardUserDTO(final String id, @NotNull final String userName, 
final String password, final Integer role, final List<String> roles, final 
Boolean enabled) {
+
+    public DashboardUserDTO(final String id, @NotNull final String userName, 
final String password, final Integer role, final List<String> roles, final 
Boolean enabled, final String clientId) {
         this.id = id;
         this.userName = userName;
         this.password = password;
         this.role = role;
         this.roles = roles;
         this.enabled = enabled;
+        this.clientId = clientId;
     }
-    
+
     /**
      * Gets the value of id.
      *
@@ -87,7 +93,7 @@ public class DashboardUserDTO implements Serializable {
     public String getId() {
         return id;
     }
-    
+
     /**
      * Sets the id.
      *
@@ -96,7 +102,7 @@ public class DashboardUserDTO implements Serializable {
     public void setId(final String id) {
         this.id = id;
     }
-    
+
     /**
      * Gets the value of userName.
      *
@@ -105,7 +111,7 @@ public class DashboardUserDTO implements Serializable {
     public String getUserName() {
         return userName;
     }
-    
+
     /**
      * Sets the userName.
      *
@@ -114,7 +120,7 @@ public class DashboardUserDTO implements Serializable {
     public void setUserName(final String userName) {
         this.userName = userName;
     }
-    
+
     /**
      * Gets the value of password.
      *
@@ -123,7 +129,7 @@ public class DashboardUserDTO implements Serializable {
     public String getPassword() {
         return password;
     }
-    
+
     /**
      * Sets the password.
      *
@@ -132,7 +138,7 @@ public class DashboardUserDTO implements Serializable {
     public void setPassword(final String password) {
         this.password = password;
     }
-    
+
     /**
      * Gets the value of role.
      *
@@ -141,7 +147,7 @@ public class DashboardUserDTO implements Serializable {
     public Integer getRole() {
         return role;
     }
-    
+
     /**
      * Sets the role.
      *
@@ -150,7 +156,7 @@ public class DashboardUserDTO implements Serializable {
     public void setRole(final Integer role) {
         this.role = role;
     }
-    
+
     /**
      * Gets the value of roles.
      *
@@ -159,7 +165,7 @@ public class DashboardUserDTO implements Serializable {
     public List<String> getRoles() {
         return roles;
     }
-    
+
     /**
      * Sets the roles.
      *
@@ -168,7 +174,7 @@ public class DashboardUserDTO implements Serializable {
     public void setRoles(final List<String> roles) {
         this.roles = roles;
     }
-    
+
     /**
      * Gets the value of enabled.
      *
@@ -177,7 +183,7 @@ public class DashboardUserDTO implements Serializable {
     public Boolean getEnabled() {
         return enabled;
     }
-    
+
     /**
      * Sets the enabled.
      *
@@ -186,7 +192,25 @@ public class DashboardUserDTO implements Serializable {
     public void setEnabled(final Boolean enabled) {
         this.enabled = enabled;
     }
-    
+
+    /**
+     * Gets the value of clientId.
+     *
+     * @return the value of clientId
+     */
+    public String getClientId() {
+        return clientId;
+    }
+
+    /**
+     * Sets the clientId.
+     *
+     * @param clientId clientId
+     */
+    public void setClientId(final String clientId) {
+        this.clientId = clientId;
+    }
+
     /**
      * builder method.
      *
@@ -195,7 +219,7 @@ public class DashboardUserDTO implements Serializable {
     public static DashboardUserDTO.DashboardUserDTOBuilder builder() {
         return new DashboardUserDTO.DashboardUserDTOBuilder();
     }
-    
+
     @Override
     public boolean equals(final Object o) {
         if (this == o) {
@@ -212,29 +236,31 @@ public class DashboardUserDTO implements Serializable {
                 && Objects.equals(roles, that.roles)
                 && Objects.equals(enabled, that.enabled);
     }
-    
+
     @Override
     public int hashCode() {
         return Objects.hash(id, userName, password, role, roles, enabled);
     }
-    
+
     public static final class DashboardUserDTOBuilder {
-        
+
         private String id;
-        
+
         private String userName;
-        
+
         private String password;
-        
+
         private Integer role;
-        
+
         private List<String> roles;
-        
+
         private Boolean enabled;
-        
+
+        private String clientId;
+
         private DashboardUserDTOBuilder() {
         }
-        
+
         /**
          * id.
          *
@@ -245,7 +271,7 @@ public class DashboardUserDTO implements Serializable {
             this.id = id;
             return this;
         }
-        
+
         /**
          * userName.
          *
@@ -256,7 +282,7 @@ public class DashboardUserDTO implements Serializable {
             this.userName = userName;
             return this;
         }
-        
+
         /**
          * password.
          *
@@ -267,7 +293,7 @@ public class DashboardUserDTO implements Serializable {
             this.password = password;
             return this;
         }
-        
+
         /**
          * role.
          *
@@ -278,7 +304,7 @@ public class DashboardUserDTO implements Serializable {
             this.role = role;
             return this;
         }
-        
+
         /**
          * roles.
          *
@@ -289,7 +315,7 @@ public class DashboardUserDTO implements Serializable {
             this.roles = roles;
             return this;
         }
-        
+
         /**
          * enabled.
          *
@@ -300,14 +326,25 @@ public class DashboardUserDTO implements Serializable {
             this.enabled = enabled;
             return this;
         }
-        
+
+        /**
+         * clientId.
+         *
+         * @param clientId the clientId.
+         * @return DashboardUserDTOBuilder.
+         */
+        public DashboardUserDTOBuilder clientId(final String clientId) {
+            this.clientId = clientId;
+            return this;
+        }
+
         /**
          * build method.
          *
          * @return build object.
          */
         public DashboardUserDTO build() {
-            return new DashboardUserDTO(id, userName, password, role, roles, 
enabled);
+            return new DashboardUserDTO(id, userName, password, role, roles, 
enabled, clientId);
         }
     }
 }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/entity/DashboardUserDO.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/entity/DashboardUserDO.java
index 20bb361e2b..733913be8c 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/entity/DashboardUserDO.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/entity/DashboardUserDO.java
@@ -54,6 +54,11 @@ public final class DashboardUserDO extends BaseDO {
      */
     private Boolean enabled;
 
+    /**
+     * clientId.
+     */
+    private String clientId;
+
     /**
      * current role list.
      */
@@ -133,6 +138,24 @@ public final class DashboardUserDO extends BaseDO {
         return enabled;
     }
 
+    /**
+     * Gets the value of clientId.
+     *
+     * @return the value of clientId
+     */
+    public String getClientId() {
+        return clientId;
+    }
+
+    /**
+     * Sets the clientId.
+     *
+     * @param clientId clientId
+     */
+    public void setClientId(final String clientId) {
+        this.clientId = clientId;
+    }
+
     /**
      * Sets the enabled.
      *
@@ -254,6 +277,8 @@ public final class DashboardUserDO extends BaseDO {
 
         private Boolean enabled;
 
+        private String clientId;
+
         private List<String> roles;
 
         private DashboardUserDOBuilder() {
@@ -336,6 +361,17 @@ public final class DashboardUserDO extends BaseDO {
             return this;
         }
 
+        /**
+         * clientId.
+         *
+         * @param clientId the clientId.
+         * @return DashboardUserDOBuilder.
+         */
+        public DashboardUserDOBuilder clientId(final String clientId) {
+            this.clientId = clientId;
+            return this;
+        }
+
         /**
          * roles.
          *
@@ -360,6 +396,7 @@ public final class DashboardUserDO extends BaseDO {
             dashboardUserDO.setUserName(userName);
             dashboardUserDO.setPassword(password);
             dashboardUserDO.setRole(role);
+            dashboardUserDO.setClientId(clientId);
             dashboardUserDO.setEnabled(enabled);
             dashboardUserDO.setRoles(roles);
             return dashboardUserDO;
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/DashboardUserVO.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/DashboardUserVO.java
index 3bbd1182af..9b10277881 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/DashboardUserVO.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/DashboardUserVO.java
@@ -58,6 +58,11 @@ public class DashboardUserVO implements Serializable {
      */
     private Boolean enabled;
 
+    /**
+     * clientId.
+     */
+    private String clientId;
+
     /**
      * created time.
      */
@@ -76,6 +81,7 @@ public class DashboardUserVO implements Serializable {
                            final String password,
                            final Integer role,
                            final Boolean enabled,
+                           final String clientId,
                            final String dateCreated,
                            final String dateUpdated) {
         this.id = id;
@@ -83,6 +89,7 @@ public class DashboardUserVO implements Serializable {
         this.password = password;
         this.role = role;
         this.enabled = enabled;
+        this.clientId = clientId;
         this.dateCreated = dateCreated;
         this.dateUpdated = dateUpdated;
     }
@@ -177,6 +184,24 @@ public class DashboardUserVO implements Serializable {
         this.enabled = enabled;
     }
 
+    /**
+     * Gets the value of clientId.
+     *
+     * @return the value of clientId
+     */
+    public String getClientId() {
+        return clientId;
+    }
+
+    /**
+     * Sets the clientId.
+     *
+     * @param clientId clientId
+     */
+    public void setClientId(final String clientId) {
+        this.clientId = clientId;
+    }
+
     /**
      * Gets the value of dateCreated.
      *
@@ -222,7 +247,7 @@ public class DashboardUserVO implements Serializable {
     public static DashboardUserVO buildDashboardUserVO(final DashboardUserDO 
dashboardUserDO) {
         return Optional.ofNullable(dashboardUserDO)
                 .map(item -> new DashboardUserVO(item.getId(), 
item.getUserName(),
-                        item.getPassword(), item.getRole(), item.getEnabled(),
+                        item.getPassword(), item.getRole(), item.getEnabled(), 
item.getClientId(),
                         
DateUtils.localDateTimeToString(item.getDateCreated().toLocalDateTime()),
                         
DateUtils.localDateTimeToString(item.getDateUpdated().toLocalDateTime())))
                 .orElse(null);
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/DashboardUserService.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/DashboardUserService.java
index a30257cd32..3144874442 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/DashboardUserService.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/DashboardUserService.java
@@ -31,7 +31,7 @@ import java.util.Set;
  * this is dashboard user service.
  */
 public interface DashboardUserService {
-    
+
     /**
      * create or update dashboard user.
      *
@@ -39,7 +39,7 @@ public interface DashboardUserService {
      * @return rows
      */
     int createOrUpdate(DashboardUserDTO dashboardUserDTO);
-    
+
     /**
      * create dashboard user.
      *
@@ -47,7 +47,7 @@ public interface DashboardUserService {
      * @return rows
      */
     int create(DashboardUserDTO dashboardUserDTO);
-    
+
     /**
      * update dashboard user.
      *
@@ -55,7 +55,7 @@ public interface DashboardUserService {
      * @return rows
      */
     int update(DashboardUserDTO dashboardUserDTO);
-    
+
     /**
      * delete dashboard users.
      *
@@ -63,7 +63,7 @@ public interface DashboardUserService {
      * @return rows
      */
     int delete(Set<String> ids);
-    
+
     /**
      * find dashboard user by id.
      *
@@ -71,7 +71,7 @@ public interface DashboardUserService {
      * @return {@linkplain DashboardUserVO}
      */
     DashboardUserEditVO findById(String id);
-    
+
     /**
      * find dashboard user by username.
      *
@@ -79,7 +79,7 @@ public interface DashboardUserService {
      * @return {@linkplain DashboardUserVO}
      */
     DashboardUserVO findByUserName(String username);
-    
+
     /**
      * find dashboard user by query.
      *
@@ -88,7 +88,7 @@ public interface DashboardUserService {
      * @return {@linkplain DashboardUserVO}
      */
     DashboardUserVO findByQuery(String userName, String password);
-    
+
     /**
      * find page of dashboard user by query.
      *
@@ -96,16 +96,17 @@ public interface DashboardUserService {
      * @return {@linkplain CommonPager}
      */
     CommonPager<DashboardUserVO> listByPage(DashboardUserQuery 
dashboardUserQuery);
-    
+
     /**
      * To deal with the admin login.
      *
      * @param userName default username is admin
      * @param password admin password
+     * @param clientId client id
      * @return {@linkplain LoginDashboardUserVO}
      */
-    LoginDashboardUserVO login(String userName, String password);
-    
+    LoginDashboardUserVO login(String userName, String password, String 
clientId);
+
     /**
      * modify password.
      *
@@ -113,7 +114,7 @@ public interface DashboardUserService {
      * @return rows
      */
     int modifyPassword(DashboardUserModifyPasswordDTO 
dashboardUserModifyPasswordDTO);
-    
+
     /**
      * check password.
      *
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/DashboardUserServiceImpl.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/DashboardUserServiceImpl.java
index 1e78516998..73bf0c1dd8 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/DashboardUserServiceImpl.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/DashboardUserServiceImpl.java
@@ -18,6 +18,7 @@
 package org.apache.shenyu.admin.service.impl;
 
 import com.google.common.collect.Lists;
+import jakarta.annotation.Nullable;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.admin.config.properties.DashboardProperties;
@@ -60,7 +61,6 @@ import org.springframework.ldap.support.LdapEncoder;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import jakarta.annotation.Nullable;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -72,25 +72,25 @@ import java.util.stream.Collectors;
  */
 @Service
 public class DashboardUserServiceImpl implements DashboardUserService {
-    
+
     private static final Logger LOG = 
LoggerFactory.getLogger(DashboardUserServiceImpl.class);
-    
+
     private final DashboardUserMapper dashboardUserMapper;
-    
+
     private final UserRoleMapper userRoleMapper;
-    
+
     private final RoleMapper roleMapper;
-    
+
     @Nullable
     private final LdapProperties ldapProperties;
-    
+
     @Nullable
     private final LdapTemplate ldapTemplate;
-    
+
     private final JwtProperties jwtProperties;
-    
+
     private final UserEventPublisher publisher;
-    
+
     private final DashboardProperties properties;
 
     private final SecretProperties secretProperties;
@@ -114,7 +114,7 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
         this.properties = properties;
         this.secretProperties = secretProperties;
     }
-    
+
     /**
      * create or update dashboard user.
      *
@@ -126,7 +126,7 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
     public int createOrUpdate(final DashboardUserDTO dashboardUserDTO) {
         return StringUtils.isBlank(dashboardUserDTO.getId()) ? 
create(dashboardUserDTO) : update(dashboardUserDTO);
     }
-    
+
     @Override
     public int create(final DashboardUserDTO dashboardUserDTO) {
         Assert.notBlack(dashboardUserDTO.getPassword(), "password is not 
null");
@@ -141,7 +141,7 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
         }
         return insertCount;
     }
-    
+
     @Override
     public int update(final DashboardUserDTO dashboardUserDTO) {
         // 【mandatory】This function can only be used by the admin user
@@ -169,7 +169,7 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
         }
         return updateCount;
     }
-    
+
     /**
      * delete dashboard users.
      *
@@ -192,11 +192,11 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
         if (deleteCount > 0) {
             userRoleMapper.deleteByUserIdList(deletedIds);
             publisher.onDeleted(deletedUser);
-            
+
         }
         return deleteCount;
     }
-    
+
     /**
      * find dashboard user by id.
      *
@@ -205,25 +205,25 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
      */
     @Override
     public DashboardUserEditVO findById(final String id) {
-        
+
         DashboardUserVO dashboardUserVO = 
DashboardUserVO.buildDashboardUserVO(dashboardUserMapper.selectById(id));
-        
+
         Set<String> roleIdSet = userRoleMapper.findByUserId(id)
                 .stream()
                 .map(UserRoleDO::getRoleId)
                 .collect(Collectors.toSet());
-        
+
         List<RoleDO> allRoleDOList = roleMapper.selectAll();
         List<RoleVO> allRoles = ListUtil.map(allRoleDOList, 
RoleVO::buildRoleVO);
-        
+
         List<RoleDO> roleDOList = allRoleDOList.stream()
                 .filter(roleDO -> roleIdSet.contains(roleDO.getId()))
                 .collect(Collectors.toList());
         List<RoleVO> roles = ListUtil.map(roleDOList, RoleVO::buildRoleVO);
-        
+
         return DashboardUserEditVO.buildDashboardUserEditVO(dashboardUserVO, 
roles, allRoles);
     }
-    
+
     /**
      * find dashboard user by query.
      *
@@ -235,7 +235,7 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
     public DashboardUserVO findByQuery(final String userName, final String 
password) {
         return 
DashboardUserVO.buildDashboardUserVO(dashboardUserMapper.findByQuery(userName, 
password));
     }
-    
+
     /**
      * find dashboard user by username.
      *
@@ -246,7 +246,7 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
     public DashboardUserVO findByUserName(final String userName) {
         return 
DashboardUserVO.buildDashboardUserVO(dashboardUserMapper.selectByUserName(userName));
     }
-    
+
     /**
      * find page of dashboard user by query.
      *
@@ -259,16 +259,17 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
             () -> dashboardUserMapper.countByQuery(dashboardUserQuery),
             () -> 
ListUtil.map(dashboardUserMapper.selectByQuery(dashboardUserQuery), 
DashboardUserVO::buildDashboardUserVO));
     }
-    
+
     /**
      * To deal with the admin login.
      *
      * @param userName default username is admin
      * @param password admin password
+     * @param clientId client id
      * @return {@linkplain LoginDashboardUserVO}
      */
     @Override
-    public LoginDashboardUserVO login(final String userName, final String 
password) {
+    public LoginDashboardUserVO login(final String userName, final String 
password, final String clientId) {
         DashboardUserVO dashboardUserVO = null;
         final String cbcDecryptPassword;
         if (StringUtils.isNotBlank(secretProperties.getKey()) && 
StringUtils.isNotBlank(secretProperties.getIv())) {
@@ -280,11 +281,11 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
         if (Objects.nonNull(ldapTemplate)) {
             dashboardUserVO = loginByLdap(userName, cbcDecryptPassword);
         }
-        
+
         if (Objects.isNull(dashboardUserVO)) {
             dashboardUserVO = loginByDatabase(userName, cbcDecryptPassword);
         }
-        
+
         final LoginDashboardUserVO loginDashboardUserVO = 
LoginDashboardUserVO.buildLoginDashboardUserVO(dashboardUserVO);
         final DashboardUserVO finalDashboardUserVO = dashboardUserVO;
         return Optional.ofNullable(loginDashboardUserVO)
@@ -292,12 +293,18 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
                     if (Boolean.FALSE.equals(loginUser.getEnabled())) {
                         return loginUser;
                     }
+                    if (clientId != null) {
+                        DashboardUserDO userDO = new DashboardUserDO();
+                        userDO.setId(loginUser.getId());
+                        userDO.setClientId(clientId);
+                        dashboardUserMapper.updateSelective(userDO);
+                    }
                     return 
loginUser.setToken(JwtUtils.generateToken(finalDashboardUserVO.getUserName(), 
finalDashboardUserVO.getPassword(),
-                            
jwtProperties.getExpiredSeconds())).setExpiredTime(jwtProperties.getExpiredSeconds());
+                            clientId, 
jwtProperties.getExpiredSeconds())).setExpiredTime(jwtProperties.getExpiredSeconds());
                 })
                 .orElse(null);
     }
-    
+
     /**
      * modify password.
      *
@@ -310,7 +317,7 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
         Assert.notNull(before, "current user is not found");
         Assert.isTrue(Boolean.TRUE.equals(before.getEnabled()), "current user 
is locked");
         Assert.isTrue(Objects.equals(before.getPassword(), 
dashboardUserModifyPasswordDTO.getOldPassword()), "old password is error");
-        
+
         DashboardUserDO dashboardUserDO = 
DashboardUserDO.buildDashboardUserDO(dashboardUserModifyPasswordDTO);
         int updateCount = dashboardUserMapper.updateSelective(dashboardUserDO);
         if (updateCount > 0) {
@@ -318,18 +325,18 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
         }
         return updateCount;
     }
-    
+
     @Override
     public boolean checkUserPassword(final String userId) {
         final DashboardUserDO userDO = dashboardUserMapper.selectById(userId);
-        
+
         WebI18nAssert.isTrue(!Objects.equals(userDO.getDateCreated(), 
userDO.getDateUpdated()), FailI18nMessage.PASSWORD_IS_DEFAULT);
-        
+
         // The password has not been changed for a long time
         WebI18nAssert.isTrue(passwordUsedLongTime(userDO), 
FailI18nMessage.PASSWORD_USED_FOR_LONG_TIME);
-        
+
         // Weak password blacklist
-        
+
         return true;
     }
 
@@ -362,11 +369,11 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
             return null;
         }
     }
-    
+
     private DashboardUserVO loginByDatabase(final String userName, final 
String password) {
         return findByQuery(userName, DigestUtils.sha512Hex(password));
     }
-    
+
     /**
      * bind user and role id.
      *
@@ -384,7 +391,7 @@ public class DashboardUserServiceImpl implements 
DashboardUserService {
                         .build()))
                 .collect(Collectors.toList()));
     }
-    
+
     private boolean passwordUsedLongTime(final DashboardUserDO userDO) {
         return userDO.getDateUpdated().getTime() >= System.currentTimeMillis() 
- properties.getSuperAdminPasswordValidDuration();
     }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/shiro/config/ShiroRealm.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/shiro/config/ShiroRealm.java
index d83f03aa73..4d7fef85a7 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/shiro/config/ShiroRealm.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/shiro/config/ShiroRealm.java
@@ -28,8 +28,8 @@ import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authc.AuthenticationException;
 import org.apache.shiro.authc.AuthenticationInfo;
 import org.apache.shiro.authc.AuthenticationToken;
-import org.apache.shiro.authc.SimpleAuthenticationInfo;
 import org.apache.shiro.authc.BearerToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
 import org.apache.shiro.authz.AuthorizationInfo;
 import org.apache.shiro.authz.Permission;
 import org.apache.shiro.authz.SimpleAuthorizationInfo;
@@ -101,6 +101,11 @@ public class ShiroRealm extends AuthorizingRealm {
             throw new AuthenticationException(String.format("userName(%s) can 
not be found.", userName));
         }
 
+        String clientIdFromToken = JwtUtils.getClientId(token);
+        if (StringUtils.isNotEmpty(dashboardUserVO.getClientId()) && 
!StringUtils.equals(dashboardUserVO.getClientId(), clientIdFromToken)) {
+            throw new AuthenticationException("clientId is invalid or does not 
match");
+        }
+
         if (!JwtUtils.verifyToken(token, dashboardUserVO.getPassword())) {
             throw new AuthenticationException("token is error.");
         }
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/transfer/DashboardUserTransfer.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/transfer/DashboardUserTransfer.java
index a84f03f939..41e2575bd1 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/transfer/DashboardUserTransfer.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/transfer/DashboardUserTransfer.java
@@ -65,6 +65,7 @@ public enum DashboardUserTransfer {
             dashboardVO.setPassword(data.getPassword());
             dashboardVO.setRole(data.getRole());
             dashboardVO.setEnabled(data.getEnabled());
+            dashboardVO.setClientId(data.getClientId());
             dashboardVO.setDateCreated(data.getDateCreated());
             dashboardVO.setDateUpdated(data.getDateUpdated());
             return dashboardVO;
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/JwtUtils.java 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/JwtUtils.java
index 94849cdec2..e1cacfdaf9 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/JwtUtils.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/JwtUtils.java
@@ -36,14 +36,14 @@ import java.util.Optional;
  * JWT tools.
  */
 public final class JwtUtils {
-    
+
     private static final Logger LOG = LoggerFactory.getLogger(JwtUtils.class);
-    
+
     private static final long TOKEN_EXPIRE_SECONDS = 24 * 60 * 60 * 1000L;
-    
+
     private JwtUtils() {
     }
-    
+
     /**
      * according to token to get isUserInfo.
      *
@@ -52,7 +52,7 @@ public final class JwtUtils {
     public static UserInfo getUserInfo() {
         return (UserInfo) SecurityUtils.getSubject().getPrincipal();
     }
-    
+
     /**
      * according to token to get issuer.
      *
@@ -63,30 +63,44 @@ public final class JwtUtils {
         DecodedJWT jwt = JWT.decode(token);
         return Optional.of(jwt).map(item -> 
item.getClaim("userName").asString()).orElse("");
     }
-    
+
+    /**
+     * according to token to get clientId.
+     *
+     * @param token token
+     * @return ClientId {@link String}
+     */
+    public static String getClientId(final String token) {
+        DecodedJWT jwt = JWT.decode(token);
+        return Optional.of(jwt).map(item -> 
item.getClaim("clientId").asString()).orElse("");
+    }
+
     /**
      * generate jwt token.
      *
      * @param userName login's userName
      * @param key      secretKey
+     * @param clientId clientId
      * @return token
      */
-    public static String generateToken(final String userName, final String 
key) {
-        return generateToken(userName, key, null);
+    public static String generateToken(final String userName, final String 
key, final String clientId) {
+        return generateToken(userName, key, clientId, null);
     }
-    
+
     /**
      * generate jwt token.
      *
      * @param userName      login's userName
      * @param key           secretKey
+     * @param clientId      clientId
      * @param expireSeconds expireSeconds
      * @return token
      */
-    public static String generateToken(final String userName, final String 
key, final Long expireSeconds) {
+    public static String generateToken(final String userName, final String 
key, final String clientId, final Long expireSeconds) {
         try {
             return JWT.create()
                     .withClaim("userName", userName)
+                    .withClaim("clientId", clientId)
                     .withExpiresAt(new Date(System.currentTimeMillis() + 
Optional.ofNullable(expireSeconds).orElse(TOKEN_EXPIRE_SECONDS)))
                     .sign(Algorithm.HMAC256(key));
         } catch (IllegalArgumentException | JWTCreationException e) {
@@ -94,7 +108,7 @@ public final class JwtUtils {
         }
         return StringUtils.EMPTY_STRING;
     }
-    
+
     public static boolean verifyToken(final String token, final String key) {
         try {
             JWTVerifier verifier = JWT.require(Algorithm.HMAC256(key)).build();
diff --git a/shenyu-admin/src/main/resources/mappers/dashboard-user-sqlmap.xml 
b/shenyu-admin/src/main/resources/mappers/dashboard-user-sqlmap.xml
index 68b5072704..17fd9c7c08 100644
--- a/shenyu-admin/src/main/resources/mappers/dashboard-user-sqlmap.xml
+++ b/shenyu-admin/src/main/resources/mappers/dashboard-user-sqlmap.xml
@@ -26,6 +26,7 @@
         <result column="password" jdbcType="VARCHAR" property="password"/>
         <result column="role" jdbcType="INTEGER" property="role"/>
         <result column="enabled" jdbcType="TINYINT" property="enabled"/>
+        <result column="client_id" jdbcType="VARCHAR" property="clientId"/>
     </resultMap>
 
     <sql id="Base_Column_List">
@@ -35,7 +36,8 @@
         user_name,
         password,
         role,
-        enabled
+        enabled,
+        client_id
     </sql>
 
     <select id="selectById" parameterType="java.lang.String" 
resultMap="BaseResultMap">
@@ -112,7 +114,8 @@
                     user_name,
                     password,
                     role,
-                    enabled)
+                    enabled,
+                    client_id)
              VALUES
                     (#{id, jdbcType=VARCHAR},
                     #{dateCreated, jdbcType=TIMESTAMP},
@@ -120,7 +123,8 @@
                     #{userName, jdbcType=VARCHAR},
                     #{password, jdbcType=VARCHAR},
                     #{role, jdbcType=INTEGER},
-                    #{enabled, jdbcType=TINYINT})
+                    #{enabled, jdbcType=TINYINT},
+                    #{clientId, jdbcType=VARCHAR})
     </insert>
 
     <insert id="insertSelective" 
parameterType="org.apache.shenyu.admin.model.entity.DashboardUserDO">
@@ -145,6 +149,9 @@
             <if test="enabled != null">
                 enabled,
             </if>
+            <if test="clientId != null">
+                client_id,
+            </if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
                 #{id, jdbcType=VARCHAR},
@@ -166,6 +173,9 @@
             <if test="enabled != null">
                 #{enabled, jdbcType=TINYINT},
             </if>
+            <if test="clientId != null">
+                #{clientId, jdbcType=VARCHAR},
+            </if>
         </trim>
     </insert>
 
@@ -177,7 +187,8 @@
                 user_name = #{userName, jdbcType=VARCHAR},
                 password = #{password, jdbcType=VARCHAR},
                 role = #{role, jdbcType=INTEGER},
-                enabled = #{enabled, jdbcType=TINYINT}
+                enabled = #{enabled, jdbcType=TINYINT},
+                client_id = #{clientId, jdbcType=VARCHAR}
           WHERE id = #{id, jdbcType=VARCHAR}
     </update>
 
@@ -202,6 +213,9 @@
             <if test="enabled != null">
                 enabled = #{enabled, jdbcType=TINYINT},
             </if>
+            <if test="clientId != null">
+                client_id = #{clientId, jdbcType=VARCHAR},
+            </if>
         </set>
          WHERE id = #{id, jdbcType=VARCHAR}
     </update>
diff --git a/shenyu-admin/src/main/resources/sql-script/h2/schema.sql 
b/shenyu-admin/src/main/resources/sql-script/h2/schema.sql
index 4d11086bf4..4bf8330f6f 100755
--- a/shenyu-admin/src/main/resources/sql-script/h2/schema.sql
+++ b/shenyu-admin/src/main/resources/sql-script/h2/schema.sql
@@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS `dashboard_user` (
   `password` varchar(128) DEFAULT NULL COMMENT 'user password',
   `role` int(4) NOT NULL COMMENT 'role',
   `enabled` tinyint(4) NOT NULL COMMENT 'delete or not',
+  `client_id` varchar(32) DEFAULT NULL COMMENT 'client id',
   `date_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'create 
time',
   `date_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP COMMENT 'update time',
   PRIMARY KEY (`id`),
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/controller/DashboardUserControllerTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/controller/DashboardUserControllerTest.java
index 9149bc9fd9..02b03645d5 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/controller/DashboardUserControllerTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/controller/DashboardUserControllerTest.java
@@ -79,11 +79,12 @@ public final class DashboardUserControllerTest {
             "bbiB8zbUo3z3oA0VqEB/IA==",
             0,
             false,
+            "1",
             "dateCreated",
             "dateUpdated");
 
     private final DashboardUserDTO dashboardUserDTO = new 
DashboardUserDTO("2", "userName",
-            "Admin@123", 0, Lists.newArrayList("1"), false);
+            "Admin@123", 0, Lists.newArrayList("1"), false, "1");
 
     private final DashboardUserModifyPasswordDTO modifyPasswordDTO = new 
DashboardUserModifyPasswordDTO("2",
             "admin", "ShenYu=#.123", "ShenYu=#.123");
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/controller/PlatformControllerTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/controller/PlatformControllerTest.java
index 6af2d5eaa0..e78bbe9a16 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/controller/PlatformControllerTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/controller/PlatformControllerTest.java
@@ -17,12 +17,12 @@
 
 package org.apache.shenyu.admin.controller;
 
+import org.apache.shenyu.admin.model.vo.DashboardUserVO;
+import org.apache.shenyu.admin.model.vo.LoginDashboardUserVO;
 import org.apache.shenyu.admin.service.DashboardUserService;
 import org.apache.shenyu.admin.service.EnumService;
 import org.apache.shenyu.admin.service.SecretService;
 import org.apache.shenyu.admin.utils.ShenyuResultMessage;
-import org.apache.shenyu.admin.model.vo.DashboardUserVO;
-import org.apache.shenyu.admin.model.vo.LoginDashboardUserVO;
 import org.apache.shenyu.common.exception.CommonErrorCode;
 import org.apache.shenyu.common.utils.DateUtils;
 import org.junit.jupiter.api.BeforeEach;
@@ -40,6 +40,7 @@ import java.time.LocalDateTime;
 
 import static org.hamcrest.core.Is.is;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.BDDMockito.given;
 import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
 import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -69,7 +70,7 @@ public final class PlatformControllerTest {
      * dashboardUser mock data.
      */
     private final DashboardUserVO dashboardUserVO = new DashboardUserVO("1", 
"admin", "2095132720951327",
-            1, true, DateUtils.localDateTimeToString(LocalDateTime.now()),
+            1, true, "1", DateUtils.localDateTimeToString(LocalDateTime.now()),
             DateUtils.localDateTimeToString(LocalDateTime.now()));
 
     /**
@@ -88,7 +89,7 @@ public final class PlatformControllerTest {
         final String loginUri = 
"/platform/login?userName=admin&password=123456";
 
         LoginDashboardUserVO loginDashboardUserVO = 
LoginDashboardUserVO.buildLoginDashboardUserVO(dashboardUserVO);
-        given(this.dashboardUserService.login(eq("admin"), 
eq("123456"))).willReturn(loginDashboardUserVO);
+        given(this.dashboardUserService.login(eq("admin"), eq("123456"), 
isNull())).willReturn(loginDashboardUserVO);
         this.mockMvc.perform(MockMvcRequestBuilders.request(HttpMethod.GET, 
loginUri))
                 .andExpect(status().isOk())
                 .andExpect(jsonPath("$.code", is(CommonErrorCode.SUCCESSFUL)))
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/DashboardUserServiceTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/DashboardUserServiceTest.java
index c0170c6f62..c26cd4c269 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/DashboardUserServiceTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/DashboardUserServiceTest.java
@@ -204,15 +204,15 @@ public final class DashboardUserServiceTest {
         ldapProperties.setBaseDn("test");
         ReflectionTestUtils.setField(dashboardUserService, "ldapProperties", 
ldapProperties);
         ReflectionTestUtils.setField(dashboardUserService, "ldapTemplate", 
ldapTemplate);
-        LoginDashboardUserVO loginDashboardUserVO = 
dashboardUserService.login(TEST_USER_NAME, TEST_PASSWORD);
+        LoginDashboardUserVO loginDashboardUserVO = 
dashboardUserService.login(TEST_USER_NAME, TEST_PASSWORD, null);
         assertEquals(TEST_USER_NAME, loginDashboardUserVO.getUserName());
         assertEquals(DigestUtils.sha512Hex(TEST_PASSWORD), 
loginDashboardUserVO.getPassword());
 
         // test loginByDatabase
         ReflectionTestUtils.setField(dashboardUserService, "ldapTemplate", 
null);
-        assertLoginSuccessful(dashboardUserDO, 
dashboardUserService.login(TEST_USER_NAME, TEST_PASSWORD));
+        assertLoginSuccessful(dashboardUserDO, 
dashboardUserService.login(TEST_USER_NAME, TEST_PASSWORD, null));
         verify(dashboardUserMapper).findByQuery(eq(TEST_USER_NAME), 
anyString());
-        assertLoginSuccessful(dashboardUserDO, 
dashboardUserService.login(TEST_USER_NAME, TEST_PASSWORD));
+        assertLoginSuccessful(dashboardUserDO, 
dashboardUserService.login(TEST_USER_NAME, TEST_PASSWORD, null));
         verify(dashboardUserMapper, times(2)).findByQuery(eq(TEST_USER_NAME), 
anyString());
 
         // test loginByDatabase AES password
@@ -221,9 +221,9 @@ public final class DashboardUserServiceTest {
         secretPropertiesTmp.setIv("6075877187097700");
         ReflectionTestUtils.setField(dashboardUserService, "secretProperties", 
secretPropertiesTmp);
         ReflectionTestUtils.setField(dashboardUserService, "ldapTemplate", 
null);
-        assertLoginSuccessful(dashboardUserDO, 
dashboardUserService.login(TEST_USER_NAME, 
AesUtils.cbcEncrypt("2095132720951327", "6075877187097700", TEST_PASSWORD)));
+        assertLoginSuccessful(dashboardUserDO, 
dashboardUserService.login(TEST_USER_NAME, 
AesUtils.cbcEncrypt("2095132720951327", "6075877187097700", TEST_PASSWORD), 
null));
         verify(dashboardUserMapper, times(3)).findByQuery(eq(TEST_USER_NAME), 
anyString());
-        assertLoginSuccessful(dashboardUserDO, 
dashboardUserService.login(TEST_USER_NAME, 
AesUtils.cbcEncrypt("2095132720951327", "6075877187097700", TEST_PASSWORD)));
+        assertLoginSuccessful(dashboardUserDO, 
dashboardUserService.login(TEST_USER_NAME, 
AesUtils.cbcEncrypt("2095132720951327", "6075877187097700", TEST_PASSWORD), 
null));
         verify(dashboardUserMapper, times(4)).findByQuery(eq(TEST_USER_NAME), 
anyString());
 
     }
@@ -235,7 +235,7 @@ public final class DashboardUserServiceTest {
                 .dateUpdated(new Timestamp(System.currentTimeMillis()))
                 .build();
     }
-    
+
     private void assertLoginSuccessful(final DashboardUserDO dashboardUserDO, 
final DashboardUserVO dashboardUserVO) {
         assertEquals(dashboardUserDO.getId(), dashboardUserVO.getId());
         assertEquals(dashboardUserDO.getUserName(), 
dashboardUserVO.getUserName());
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/utils/JwtUtilsTest.java 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/utils/JwtUtilsTest.java
index b88db39ce0..5527805b64 100644
--- a/shenyu-admin/src/test/java/org/apache/shenyu/admin/utils/JwtUtilsTest.java
+++ b/shenyu-admin/src/test/java/org/apache/shenyu/admin/utils/JwtUtilsTest.java
@@ -22,9 +22,10 @@ import org.apache.shenyu.admin.spring.SpringBeanUtils;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.springframework.context.ConfigurableApplicationContext;
+
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.notNullValue;
-import static org.hamcrest.MatcherAssert.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -53,10 +54,16 @@ public class JwtUtilsTest {
         assertThat(JwtUtils.getIssuer(TOKEN), is(""));
     }
 
+    @Test
+    public void testGetClientId() {
+        assertThat(JwtUtils.getClientId(TOKEN), is(""));
+    }
+
     @Test
     public void testGenerateToken() {
-        String token = JwtUtils.generateToken("userName", KEY);
+        String token = JwtUtils.generateToken("userName", KEY, "clientId");
         assertThat(token, notNullValue());
         assertThat(JwtUtils.getIssuer(token), is("userName"));
+        assertThat(JwtUtils.getClientId(token), is("clientId"));
     }
 }

Reply via email to