mirror of
https://github.com/continew-org/continew-admin.git
synced 2025-09-10 20:57:14 +08:00
refactor(system/client): 完善客户端管理
This commit is contained in:
@@ -45,6 +45,12 @@ public class OnlineUserQuery implements Serializable {
|
||||
@Schema(description = "用户昵称", example = "张三")
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 客户端 ID
|
||||
*/
|
||||
@Schema(description = "客户端 ID", example = "ef51c9a3e9046c4f2ea45142c8a8344a")
|
||||
private String clientId;
|
||||
|
||||
/**
|
||||
* 登录时间
|
||||
*/
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -73,18 +73,20 @@ public class OnlineUserServiceImpl implements OnlineUserService {
|
||||
for (Map.Entry<Long, List<String>> 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<Date> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否匹配登录时间
|
||||
*
|
||||
|
@@ -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<String> 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;
|
||||
}
|
@@ -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;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
|
@@ -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<ClientMapper, ClientDO, ClientResp, ClientResp, ClientQuery, ClientReq> 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<ClientMapper, ClientDO, C
|
||||
|
||||
@Override
|
||||
public void beforeDelete(List<Long> ids) {
|
||||
// 查询如果删除客户端记录以后是否还存在账号认证的方式,不存在则不允许删除
|
||||
List<ClientDO> 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
|
||||
|
@@ -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='客户端表';
|
||||
|
@@ -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"
|
||||
|
@@ -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 '客户端表';
|
Reference in New Issue
Block a user