From 229bd9becfda15cbcb049fd1e0842dbe04d7b135 Mon Sep 17 00:00:00 2001 From: Charles7c Date: Fri, 27 Dec 2024 21:54:10 +0800 Subject: [PATCH] =?UTF-8?q?refactor(system/client):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/model/query/OnlineUserQuery.java | 6 ++ .../admin/auth/model/resp/OnlineUserResp.java | 12 +++ .../service/impl/OnlineUserServiceImpl.java | 28 ++++-- .../system/model/resp/ClientDetailResp.java | 87 ------------------- .../admin/system/model/resp/ClientResp.java | 4 +- .../service/impl/ClientServiceImpl.java | 23 +++-- .../db/changelog/mysql/main_table.sql | 9 +- .../db/changelog/postgresql/main_data.sql | 15 +++- .../db/changelog/postgresql/main_table.sql | 31 +++++++ 9 files changed, 105 insertions(+), 110 deletions(-) delete mode 100644 continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientDetailResp.java diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/model/query/OnlineUserQuery.java b/continew-module-system/src/main/java/top/continew/admin/auth/model/query/OnlineUserQuery.java index 26a7ee7f..e5e7b42b 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/model/query/OnlineUserQuery.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/model/query/OnlineUserQuery.java @@ -45,6 +45,12 @@ public class OnlineUserQuery implements Serializable { @Schema(description = "用户昵称", example = "张三") private String nickname; + /** + * 客户端 ID + */ + @Schema(description = "客户端 ID", example = "ef51c9a3e9046c4f2ea45142c8a8344a") + private String clientId; + /** * 登录时间 */ diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/model/resp/OnlineUserResp.java b/continew-module-system/src/main/java/top/continew/admin/auth/model/resp/OnlineUserResp.java index 00ed9ca8..a5e0d7d3 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/model/resp/OnlineUserResp.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/model/resp/OnlineUserResp.java @@ -68,6 +68,18 @@ public class OnlineUserResp implements Serializable { @Schema(description = "昵称", example = "张三") private String nickname; + /** + * 客户端类型 + */ + @Schema(description = "客户端类型", example = "PC") + private String clientType; + + /** + * 客户端 ID + */ + @Schema(description = "客户端 ID", example = "ef51c9a3e9046c4f2ea45142c8a8344a") + private String clientId; + /** * 登录 IP */ diff --git a/continew-module-system/src/main/java/top/continew/admin/auth/service/impl/OnlineUserServiceImpl.java b/continew-module-system/src/main/java/top/continew/admin/auth/service/impl/OnlineUserServiceImpl.java index 085d0364..c7e1be02 100644 --- a/continew-module-system/src/main/java/top/continew/admin/auth/service/impl/OnlineUserServiceImpl.java +++ b/continew-module-system/src/main/java/top/continew/admin/auth/service/impl/OnlineUserServiceImpl.java @@ -73,18 +73,20 @@ public class OnlineUserServiceImpl implements OnlineUserService { for (Map.Entry> entry : tokenMap.entrySet()) { Long userId = entry.getKey(); UserContext userContext = UserContextHolder.getContext(userId); - if (null == userContext || !this.isMatchNickname(query.getNickname(), userContext)) { + if (null == userContext || !this.isMatchNickname(query.getNickname(), userContext) || !this + .isMatchClientId(query.getClientId(), userContext)) { continue; } List loginTimeList = query.getLoginTime(); entry.getValue().parallelStream().forEach(token -> { UserExtraContext extraContext = UserContextHolder.getExtraContext(token); - if (this.isMatchLoginTime(loginTimeList, extraContext.getLoginTime())) { - OnlineUserResp resp = BeanUtil.copyProperties(userContext, OnlineUserResp.class); - BeanUtil.copyProperties(extraContext, resp); - resp.setToken(token); - list.add(resp); + if (!this.isMatchLoginTime(loginTimeList, extraContext.getLoginTime())) { + return; } + OnlineUserResp resp = BeanUtil.copyProperties(userContext, OnlineUserResp.class); + BeanUtil.copyProperties(extraContext, resp); + resp.setToken(token); + list.add(resp); }); } // 设置排序 @@ -121,6 +123,20 @@ public class OnlineUserServiceImpl implements OnlineUserService { .getNickname(userContext.getId()), nickname); } + /** + * 是否匹配客户端 ID + * + * @param clientId 客户端 ID + * @param userContext 用户上下文信息 + * @return 是否匹配客户端 ID + */ + private boolean isMatchClientId(String clientId, UserContext userContext) { + if (StrUtil.isBlank(clientId)) { + return true; + } + return Objects.equals(userContext.getClientId(), clientId); + } + /** * 是否匹配登录时间 * diff --git a/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientDetailResp.java b/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientDetailResp.java deleted file mode 100644 index 3ed5b32d..00000000 --- a/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientDetailResp.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package top.continew.admin.system.model.resp; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import top.continew.admin.common.base.BaseDetailResp; -import top.continew.admin.common.enums.DisEnableStatusEnum; - -import java.io.Serial; -import java.util.List; - -/** - * 客户端详情信息 - * - * @author KAI - * @since 2024/12/03 16:04 - */ -@Data -@Schema(description = "客户端详情信息") -public class ClientDetailResp extends BaseDetailResp { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 客户端ID - */ - @Schema(description = "客户端ID") - private String clientId; - - /** - * 客户端Key - */ - @Schema(description = "客户端Key") - private String clientKey; - - /** - * 客户端秘钥 - */ - @Schema(description = "客户端秘钥") - private String clientSecret; - - /** - * 登录类型 - */ - @Schema(description = "登录类型") - private List authType; - - /** - * 客户端类型 - */ - @Schema(description = "客户端类型") - private String clientType; - - /** - * Token最低活跃频率(-1为不限制) - */ - @Schema(description = "Token最低活跃频率(-1为不限制)") - private Integer activeTimeout; - - /** - * Token有效期(默认30天,单位:秒) - */ - @Schema(description = "Token有效期(默认30天,单位:秒)") - private Integer timeout; - - /** - * 状态 - */ - @Schema(description = "状态", example = "1") - private DisEnableStatusEnum status; -} \ No newline at end of file diff --git a/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientResp.java b/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientResp.java index a7b32d9b..059a2e41 100644 --- a/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientResp.java +++ b/continew-module-system/src/main/java/top/continew/admin/system/model/resp/ClientResp.java @@ -72,13 +72,13 @@ public class ClientResp extends BaseDetailResp { * Token 最低活跃频率(单位:秒,-1:不限制,永不冻结) */ @Schema(description = "Token 最低活跃频率(单位:秒,-1:不限制,永不冻结)", example = "1800") - private Integer activeTimeout; + private Long activeTimeout; /** * Token 有效期(单位:秒,-1:永不过期) */ @Schema(description = "Token 有效期(单位:秒,-1:永不过期)", example = "86400") - private Integer timeout; + private Long timeout; /** * 状态 diff --git a/continew-module-system/src/main/java/top/continew/admin/system/service/impl/ClientServiceImpl.java b/continew-module-system/src/main/java/top/continew/admin/system/service/impl/ClientServiceImpl.java index dc9df9ce..c563abec 100644 --- a/continew-module-system/src/main/java/top/continew/admin/system/service/impl/ClientServiceImpl.java +++ b/continew-module-system/src/main/java/top/continew/admin/system/service/impl/ClientServiceImpl.java @@ -18,8 +18,10 @@ package top.continew.admin.system.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.crypto.digest.DigestUtil; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import top.continew.admin.auth.enums.AuthTypeEnum; +import top.continew.admin.auth.model.query.OnlineUserQuery; +import top.continew.admin.auth.service.OnlineUserService; import top.continew.admin.system.mapper.ClientMapper; import top.continew.admin.system.model.entity.ClientDO; import top.continew.admin.system.model.query.ClientQuery; @@ -27,7 +29,7 @@ import top.continew.admin.system.model.req.ClientReq; import top.continew.admin.system.model.resp.ClientResp; import top.continew.admin.system.service.ClientService; import top.continew.starter.core.constant.StringConstants; -import top.continew.starter.core.validation.ValidationUtils; +import top.continew.starter.core.validation.CheckUtils; import top.continew.starter.extension.crud.service.BaseServiceImpl; import java.util.List; @@ -40,8 +42,11 @@ import java.util.List; * @since 2024/12/03 16:04 */ @Service +@RequiredArgsConstructor public class ClientServiceImpl extends BaseServiceImpl implements ClientService { + private final OnlineUserService onlineUserService; + @Override public void beforeAdd(ClientReq req) { String clientId = DigestUtil.md5Hex(req.getClientKey() + StringConstants.COLON + req.getClientSecret()); @@ -50,13 +55,13 @@ public class ClientServiceImpl extends BaseServiceImpl ids) { - // 查询如果删除客户端记录以后是否还存在账号认证的方式,不存在则不允许删除 - List clientList = baseMapper.lambdaQuery() - .in(ClientDO::getId, ids) - .like(ClientDO::getAuthType, AuthTypeEnum.ACCOUNT.getValue()) - .list(); - ValidationUtils.throwIfEmpty(clientList, "请至少保留 [{}] 认证类型", AuthTypeEnum.ACCOUNT.getDescription()); - super.beforeDelete(ids); + // 如果还存在在线用户,则不能删除 + OnlineUserQuery query = new OnlineUserQuery(); + for (Long id : ids) { + ClientDO client = this.getById(id); + query.setClientId(client.getClientId()); + CheckUtils.throwIfNotEmpty(onlineUserService.list(query), "客户端 [{}] 还存在在线用户,不能删除", client.getClientKey()); + } } @Override diff --git a/continew-webapi/src/main/resources/db/changelog/mysql/main_table.sql b/continew-webapi/src/main/resources/db/changelog/mysql/main_table.sql index afebf7ca..f0f9b1a9 100644 --- a/continew-webapi/src/main/resources/db/changelog/mysql/main_table.sql +++ b/continew-webapi/src/main/resources/db/changelog/mysql/main_table.sql @@ -300,14 +300,15 @@ CREATE TABLE IF NOT EXISTS `sys_client` ( `client_id` varchar(50) NOT NULL COMMENT '客户端ID', `client_key` varchar(255) NOT NULL COMMENT '客户端Key', `client_secret` varchar(255) NOT NULL COMMENT '客户端秘钥', - `auth_type` json DEFAULT NULL COMMENT '认证类型', + `auth_type` json NOT NULL COMMENT '认证类型', `client_type` varchar(50) NOT NULL COMMENT '客户端类型', - `active_timeout` int DEFAULT '-1' COMMENT 'Token最低活跃频率(-1为不限制)', - `timeout` int DEFAULT '2592000' COMMENT 'Token有效期(默认30天,单位:秒)', + `active_timeout` bigint(20) DEFAULT -1 COMMENT 'Token最低活跃频率(单位:秒,-1:不限制,永不冻结)', + `timeout` bigint(20) DEFAULT 2592000 COMMENT 'Token有效期(单位:秒,-1:永不过期)', `status` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态(1:启用;2:禁用)', `create_user` bigint(20) NOT NULL COMMENT '创建人', `create_time` datetime NOT NULL COMMENT '创建时间', `update_user` bigint(20) DEFAULT NULL COMMENT '修改人', `update_time` datetime DEFAULT NULL COMMENT '修改时间', - PRIMARY KEY (`id`) + PRIMARY KEY (`id`), + UNIQUE INDEX `uk_client_id`(`client_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户端表'; diff --git a/continew-webapi/src/main/resources/db/changelog/postgresql/main_data.sql b/continew-webapi/src/main/resources/db/changelog/postgresql/main_data.sql index c164bae1..c8ca3609 100644 --- a/continew-webapi/src/main/resources/db/changelog/postgresql/main_data.sql +++ b/continew-webapi/src/main/resources/db/changelog/postgresql/main_data.sql @@ -76,6 +76,13 @@ VALUES (1114, '修改', 1110, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:update', 4, 1, 1, NOW()), (1115, '删除', 1110, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:delete', 5, 1, 1, NOW()), +( 1180, '客户端管理', 1000, 2, '/system/client', 'SystemClient', 'system/client/index', NULL, 'mobile', false, false, false, NULL, 9, 1, 1, NOW()), +(1181, '列表', 1180, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:list', 1, 1, 1, NOW()), +(1182, '详情', 1180, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:detail', 2, 1, 1, NOW()), +(1183, '新增', 1180, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:add', 3, 1, 1, NOW()), +(1184, '修改', 1180, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:update', 4, 1, 1, NOW()), +(1185, '删除', 1180, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:delete', 5, 1, 1, NOW()), + (1190, '系统配置', 1000, 2, '/system/config', 'SystemConfig', 'system/config/index', NULL, 'config', false, false, false, NULL, 999, 1, 1, NOW()), (1191, '查看', 1190, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:config:list', 1, 1, 1, NOW()), (1192, '修改', 1190, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:config:update', 2, 1, 1, NOW()), @@ -150,7 +157,8 @@ INSERT INTO "sys_dict" ("id", "name", "code", "description", "is_system", "create_user", "create_time") VALUES (1, '公告类型', 'notice_type', NULL, true, 1, NOW()), -(2, '消息类型', 'message_type', NULL, true, 1, NOW()); +(2, '消息类型', 'message_type', NULL, true, 1, NOW()), +(3, '客户端类型', 'client_type', NULL, true, 1, NOW()); INSERT INTO "sys_dict_item" ("id", "label", "value", "color", "sort", "description", "status", "dict_id", "create_user", "create_time") @@ -158,7 +166,10 @@ VALUES (1, '通知', '1', 'blue', 1, NULL, 1, 1, 1, NOW()), (2, '活动', '2', 'orangered', 2, NULL, 1, 1, 1, NOW()), (3, '安全消息', '1', 'blue', 1, NULL, 1, 2, 1, NOW()), -(4, '活动消息', '2', 'orangered', 2, NULL, 1, 2, 1, NOW()); +(4, '活动消息', '2', 'orangered', 2, NULL, 1, 2, 1, NOW()), +(5, '桌面端', 'PC', 'blue', 1, NULL, 1, 3, 1, NOW()), +(6, '安卓', 'ANDROID', '#148628', 2, NULL, 1, 3, 1, NOW()), +(7, '小程序', 'XCX', '#7930AD', 3, NULL, 1, 3, 1, NOW()); -- 初始化默认用户和角色关联数据 INSERT INTO "sys_user_role" diff --git a/continew-webapi/src/main/resources/db/changelog/postgresql/main_table.sql b/continew-webapi/src/main/resources/db/changelog/postgresql/main_table.sql index 25075ec5..868be1ac 100644 --- a/continew-webapi/src/main/resources/db/changelog/postgresql/main_table.sql +++ b/continew-webapi/src/main/resources/db/changelog/postgresql/main_table.sql @@ -490,3 +490,34 @@ COMMENT ON COLUMN "sys_file"."update_user" IS '修改人'; COMMENT ON COLUMN "sys_file"."update_time" IS '修改时间'; COMMENT ON TABLE "sys_file" IS '文件表'; +CREATE TABLE IF NOT EXISTS "sys_client" ( + "id" int8 NOT NULL, + "client_id" varchar(50) NOT NULL, + "client_key" varchar(255) NOT NULL, + "client_secret" varchar(255) NOT NULL, + "auth_type" json NOT NULL, + "client_type" varchar(50) NOT NULL, + "active_timeout" int8 NOT NULL DEFAULT -1, + "timeout" int8 NOT NULL DEFAULT 2592000, + "status" int2 NOT NULL DEFAULT 1, + "create_user" int8 NOT NULL, + "create_time" timestamp NOT NULL, + "update_user" int8 DEFAULT NULL, + "update_time" timestamp DEFAULT NULL, + PRIMARY KEY ("id") +); +CREATE UNIQUE INDEX "uk_client_client_id" ON "sys_client" ("client_id"); +COMMENT ON COLUMN "sys_client"."id" IS 'ID'; +COMMENT ON COLUMN "sys_client"."client_id" IS '客户端ID'; +COMMENT ON COLUMN "sys_client"."client_key" IS '客户端Key'; +COMMENT ON COLUMN "sys_client"."client_secret" IS '客户端秘钥'; +COMMENT ON COLUMN "sys_client"."auth_type" IS '认证类型'; +COMMENT ON COLUMN "sys_client"."client_type" IS '客户端类型'; +COMMENT ON COLUMN "sys_client"."active_timeout" IS 'Token最低活跃频率(单位:秒,-1:不限制,永不冻结)'; +COMMENT ON COLUMN "sys_client"."timeout" IS 'Token有效期(单位:秒,-1:永不过期)'; +COMMENT ON COLUMN "sys_client"."status" IS '状态(1:启用;2:禁用)'; +COMMENT ON COLUMN "sys_client"."create_user" IS '创建人'; +COMMENT ON COLUMN "sys_client"."create_time" IS '创建时间'; +COMMENT ON COLUMN "sys_client"."update_user" IS '修改人'; +COMMENT ON COLUMN "sys_client"."update_time" IS '修改时间'; +COMMENT ON TABLE "sys_client" IS '客户端表'; \ No newline at end of file