Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5162b99e3e | ||
|
|
263436405c | ||
|
|
2296ca46a4 | ||
|
|
ffcb3baf44 | ||
|
|
501755231a | ||
|
|
f4ddeb3e6c | ||
|
|
40afc03203 | ||
|
|
7c479b1720 | ||
|
|
6c6f69ae24 | ||
|
|
d1cb056adf | ||
|
|
14dc8e0407 | ||
|
|
528cfc90f2 | ||
|
|
327bb72659 | ||
|
|
c6b248ab6f | ||
|
|
0ece84bdf1 | ||
|
|
61fa7a6e32 | ||
|
|
21e7d29077 | ||
|
|
fbf4299a61 | ||
|
|
ad42be8fe8 | ||
|
|
d9c8923b6d | ||
|
|
aa913bce8d | ||
|
|
3e3af89939 | ||
|
|
783baaf8c8 | ||
|
|
a53565e06b | ||
|
|
061495eb13 | ||
|
|
6514363847 | ||
|
|
c3da882950 | ||
|
|
6deebedc75 | ||
|
|
2012f20a09 | ||
|
|
2377c50187 | ||
|
|
91b22297a2 | ||
|
|
5bbf46d141 | ||
|
|
3c7a0947ee | ||
|
|
83c64dddfb | ||
|
|
5d86c330fe | ||
|
|
6a13d3cb22 | ||
|
|
3a8addb4d2 | ||
|
|
90705781f2 |
@@ -6,6 +6,9 @@ SPRING_PROFILES_ACTIVE=prod
|
||||
DEMO_MODE=false
|
||||
|
||||
API_CORS=true
|
||||
API_HOST=0.0.0.0
|
||||
# API_URL=http://127.0.0.1:9700/orion-visor/api
|
||||
API_IP_HEADERS=X-Forwarded-For,X-Real-IP
|
||||
API_EXPOSE_TOKEN=pmqeHOyZaumHm0Wt
|
||||
SECRET_KEY=uQeacXV8b3isvKLK
|
||||
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -17,6 +17,8 @@ body:
|
||||
required: true
|
||||
- label: 我已搜索 [issue](https://github.com/dromara/orion-visor/issues) 并没有找到相关问题
|
||||
required: true
|
||||
- label: 我已 star 了此项目, 否则可能会被自动关闭
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
version: '3.3'
|
||||
|
||||
# latest = 2.5.4
|
||||
# latest = 2.5.6
|
||||
|
||||
# 支持以下源
|
||||
# lijiahangmax/*
|
||||
@@ -49,6 +49,8 @@ services:
|
||||
GUACD_DRIVE_PATH: ${GUACD_DRIVE_PATH:-/drive}
|
||||
SECRET_KEY: ${SECRET_KEY:-uQeacXV8b3isvKLK}
|
||||
API_EXPOSE_TOKEN: ${API_EXPOSE_TOKEN:-pmqeHOyZaumHm0Wt}
|
||||
API_IP_HEADERS: ${API_IP_HEADERS:-X-Forwarded-For,X-Real-IP}
|
||||
API_HOST: ${API_HOST:-0.0.0.0}
|
||||
API_CORS: ${API_CORS:-true}
|
||||
DEMO_MODE: ${DEMO_MODE:-false}
|
||||
volumes:
|
||||
|
||||
@@ -7,7 +7,7 @@ set -e
|
||||
source ./project-build.sh "$@"
|
||||
|
||||
# 版本号
|
||||
version=2.5.4
|
||||
version=2.5.6
|
||||
# 是否推送镜像
|
||||
push_image=false
|
||||
# 是否构建 latest
|
||||
|
||||
@@ -4,7 +4,7 @@ set -e
|
||||
# DockerContext: orion-visor
|
||||
|
||||
# 版本号
|
||||
version=2.5.4
|
||||
version=2.5.6
|
||||
# 是否构建 service
|
||||
export build_service=false
|
||||
# 是否构建 ui
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM --platform=$TARGETPLATFORM openjdk:8-jdk-alpine
|
||||
FROM --platform=$TARGETPLATFORM openjdk:8u171-jdk-alpine3.7
|
||||
|
||||
USER root
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* 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 org.dromara.visor.common.configuration;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.utils.IpUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
/**
|
||||
* 公共配置类
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/20 10:34
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class CommonConfiguration {
|
||||
|
||||
@Value("${orion.api.ip-headers}")
|
||||
private String[] ipHeaders;
|
||||
|
||||
/**
|
||||
* 设置 IP 请求头
|
||||
*/
|
||||
@PostConstruct
|
||||
public void setIpHeader() {
|
||||
IpUtils.setIpHeader(ipHeaders);
|
||||
log.info("IpUtils.setIpHeader {}", String.join(",", ipHeaders));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public interface AppConst extends OrionConst {
|
||||
/**
|
||||
* 同 ${orion.version} 迭代时候需要手动更改
|
||||
*/
|
||||
String VERSION = "2.5.4";
|
||||
String VERSION = "2.5.6";
|
||||
|
||||
/**
|
||||
* 同 ${spring.application.name}
|
||||
|
||||
@@ -55,4 +55,6 @@ public interface Const extends cn.orionsec.kit.lang.constant.Const, FieldConst,
|
||||
|
||||
int BATCH_COUNT = 500;
|
||||
|
||||
String IP_0000 = "0.0.0.0";
|
||||
|
||||
}
|
||||
|
||||
@@ -210,6 +210,10 @@ public interface ErrorMessage {
|
||||
|
||||
String PLEASE_SELECT_SUFFIX_FILE = "请选择 {} 类型的文件";
|
||||
|
||||
String SPEC_FORMAT_INCORRECT = "规格格式不正确";
|
||||
|
||||
String INFLUXDB_UNSUPPORTED = "InfluxDB 服务未开启";
|
||||
|
||||
/**
|
||||
* 是否为业务异常
|
||||
*
|
||||
|
||||
@@ -33,6 +33,20 @@ import java.io.Serializable;
|
||||
*/
|
||||
public interface RequestIdentity extends Serializable {
|
||||
|
||||
/**
|
||||
* 获取请求时间戳
|
||||
*
|
||||
* @return timestamp
|
||||
*/
|
||||
Long getTimestamp();
|
||||
|
||||
/**
|
||||
* 设置请求时间戳
|
||||
*
|
||||
* @param timestamp timestamp
|
||||
*/
|
||||
void setTimestamp(Long timestamp);
|
||||
|
||||
/**
|
||||
* 获取请求地址
|
||||
*
|
||||
|
||||
@@ -23,7 +23,10 @@
|
||||
package org.dromara.visor.common.entity;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 请求留痕模型
|
||||
@@ -33,9 +36,15 @@ import lombok.Data;
|
||||
* @since 2023/12/29 11:57
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "RequestIdentityModel", description = "请求留痕模型")
|
||||
public class RequestIdentityModel implements RequestIdentity {
|
||||
|
||||
@Schema(description = "时间戳")
|
||||
private Long timestamp;
|
||||
|
||||
@Schema(description = "请求地址")
|
||||
private String address;
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* 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 org.dromara.visor.common.mapstruct;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* date 转换器
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2025/3/7 17:43
|
||||
*/
|
||||
public class DateConversion {
|
||||
|
||||
private DateConversion() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Long > Date
|
||||
*
|
||||
* @param timestamp timestamp
|
||||
* @return Date
|
||||
*/
|
||||
public static Date longToDate(Long timestamp) {
|
||||
return timestamp != null ? new Date(timestamp) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Date > Long
|
||||
*
|
||||
* @param date date
|
||||
* @return Long
|
||||
*/
|
||||
public static Long dateToLong(Date date) {
|
||||
return date != null ? date.getTime() : null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,7 +24,7 @@ package org.dromara.visor.common.utils;
|
||||
|
||||
import cn.orionsec.kit.ext.location.Region;
|
||||
import cn.orionsec.kit.ext.location.region.LocationRegions;
|
||||
import cn.orionsec.kit.web.servlet.web.Servlets;
|
||||
import cn.orionsec.kit.lang.utils.net.IPs;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -40,6 +40,8 @@ import java.util.Map;
|
||||
*/
|
||||
public class IpUtils {
|
||||
|
||||
private static String[] IP_HEADER = new String[]{"X-Forwarded-For", "X-Real-IP"};
|
||||
|
||||
private static final Map<String, String> CACHE = new HashMap<>();
|
||||
|
||||
private IpUtils() {
|
||||
@@ -52,13 +54,17 @@ public class IpUtils {
|
||||
* @return addr
|
||||
*/
|
||||
public static String getRemoteAddr(HttpServletRequest request) {
|
||||
// 获取实际地址 X_REAL_IP 在多代理情况下会有问题
|
||||
// String realIp = request.getHeader(StandardHttpHeader.X_REAL_IP);
|
||||
// if (!Strings.isBlank(realIp)) {
|
||||
// return realIp;
|
||||
// }
|
||||
// 获取请求地址
|
||||
return Servlets.getRemoteAddr(request);
|
||||
if (request == null) {
|
||||
return null;
|
||||
} else {
|
||||
for (String remoteAddrHeader : IP_HEADER) {
|
||||
String addr = checkIpHeader(request.getHeader(remoteAddrHeader));
|
||||
if (addr != null) {
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
return checkIpHeader(request.getRemoteAddr());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,4 +118,23 @@ public class IpUtils {
|
||||
return Const.CN_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 ip 请求头
|
||||
*
|
||||
* @param headerValue headerValue
|
||||
* @return header
|
||||
*/
|
||||
private static String checkIpHeader(String headerValue) {
|
||||
if (headerValue == null) {
|
||||
return null;
|
||||
} else {
|
||||
headerValue = headerValue.split(",")[0];
|
||||
return IPs.checkIp(headerValue);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setIpHeader(String[] ipHeader) {
|
||||
IP_HEADER = ipHeader;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -64,10 +64,24 @@ public class Requests {
|
||||
.map(ServletRequestAttributes::getRequest)
|
||||
.ifPresent(request -> {
|
||||
String address = IpUtils.getRemoteAddr(request);
|
||||
identity.setTimestamp(System.currentTimeMillis());
|
||||
identity.setAddress(address);
|
||||
identity.setLocation(IpUtils.getLocation(address));
|
||||
identity.setUserAgent(Servlets.getUserAgent(request));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制留痕信息
|
||||
*
|
||||
* @param source source
|
||||
* @param target target
|
||||
*/
|
||||
public static void copyIdentity(RequestIdentityModel source, RequestIdentityModel target) {
|
||||
target.setTimestamp(source.getTimestamp());
|
||||
target.setAddress(source.getAddress());
|
||||
target.setLocation(source.getLocation());
|
||||
target.setUserAgent(source.getUserAgent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<url>https://github.com/dromara/orion-visor</url>
|
||||
|
||||
<properties>
|
||||
<revision>2.5.4</revision>
|
||||
<revision>2.5.6</revision>
|
||||
<spring.boot.version>2.7.17</spring.boot.version>
|
||||
<spring.boot.admin.version>2.7.15</spring.boot.admin.version>
|
||||
<flatten.maven.plugin.version>1.5.0</flatten.maven.plugin.version>
|
||||
|
||||
@@ -123,8 +123,8 @@ public class OperatorLogModel implements RequestIdentity {
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
* 时间戳
|
||||
*/
|
||||
private Date createTime;
|
||||
private Long timestamp;
|
||||
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializeFilter;
|
||||
import org.dromara.visor.common.entity.RequestIdentity;
|
||||
import org.dromara.visor.common.enums.BooleanBit;
|
||||
import org.dromara.visor.common.trace.TraceIdHolder;
|
||||
import org.dromara.visor.common.security.LoginUser;
|
||||
import org.dromara.visor.common.trace.TraceIdHolder;
|
||||
import org.dromara.visor.common.utils.Requests;
|
||||
import org.dromara.visor.framework.biz.operator.log.configuration.config.OperatorLogConfig;
|
||||
import org.dromara.visor.framework.biz.operator.log.core.enums.ReturnType;
|
||||
@@ -91,6 +91,7 @@ public class OperatorLogFiller implements Gettable<OperatorLogModel> {
|
||||
*/
|
||||
public OperatorLogFiller fillUsedTime(long start) {
|
||||
long end = System.currentTimeMillis();
|
||||
model.setTimestamp(start);
|
||||
model.setDuration((int) (end - start));
|
||||
model.setStartTime(new Date(start));
|
||||
model.setEndTime(new Date(end));
|
||||
|
||||
@@ -30,7 +30,9 @@ import com.influxdb.client.write.Point;
|
||||
import com.influxdb.query.FluxRecord;
|
||||
import com.influxdb.query.FluxTable;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.common.constant.ErrorMessage;
|
||||
import org.dromara.visor.common.entity.chart.TimeChartSeries;
|
||||
import org.dromara.visor.common.utils.Assert;
|
||||
import org.dromara.visor.framework.influxdb.core.query.FluxQueryBuilder;
|
||||
|
||||
import java.time.Instant;
|
||||
@@ -66,6 +68,7 @@ public class InfluxdbUtils {
|
||||
* @param points points
|
||||
*/
|
||||
public static void writePoints(List<Point> points) {
|
||||
Assert.notNull(client, ErrorMessage.INFLUXDB_UNSUPPORTED);
|
||||
try (WriteApi api = client.makeWriteApi()) {
|
||||
// 写入指标
|
||||
api.writePoints(points);
|
||||
@@ -79,6 +82,7 @@ public class InfluxdbUtils {
|
||||
* @return points
|
||||
*/
|
||||
public static List<FluxTable> queryTable(String query) {
|
||||
Assert.notNull(client, ErrorMessage.INFLUXDB_UNSUPPORTED);
|
||||
return client.getQueryApi().query(query);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.dromara.visor.common.constant.ErrorMessage;
|
||||
import org.dromara.visor.common.utils.Assert;
|
||||
#if($meta.enableCache)
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisMaps;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisUtils;
|
||||
import org.dromara.visor.framework.redis.core.utils.barrier.CacheBarriers;
|
||||
#end
|
||||
#foreach($pkg in ${customModuleFilePackages})
|
||||
@@ -76,7 +77,7 @@ public class ${table.serviceImplName} implements ${table.serviceName} {
|
||||
log.info("${type}Service-create${type} id: {}, effect: {}", id, effect);
|
||||
#if($meta.enableCache)
|
||||
// 删除缓存
|
||||
RedisMaps.delete(${type}CacheKeyDefine.${typeConst});
|
||||
RedisUtils.delete(${type}CacheKeyDefine.${typeConst});
|
||||
#end
|
||||
return id;
|
||||
}
|
||||
@@ -98,7 +99,7 @@ public class ${table.serviceImplName} implements ${table.serviceName} {
|
||||
log.info("${type}Service-update${type}ById effect: {}", effect);
|
||||
#if($meta.enableCache)
|
||||
// 删除缓存
|
||||
RedisMaps.delete(${type}CacheKeyDefine.${typeConst});
|
||||
RedisUtils.delete(${type}CacheKeyDefine.${typeConst});
|
||||
#end
|
||||
return effect;
|
||||
}
|
||||
@@ -116,7 +117,7 @@ public class ${table.serviceImplName} implements ${table.serviceName} {
|
||||
log.info("${type}Service.update${type} effect: {}", effect);
|
||||
#if($meta.enableCache)
|
||||
// 删除缓存
|
||||
RedisMaps.delete(${type}CacheKeyDefine.${typeConst});
|
||||
RedisUtils.delete(${type}CacheKeyDefine.${typeConst});
|
||||
#end
|
||||
return effect;
|
||||
}
|
||||
@@ -237,7 +238,7 @@ public class ${table.serviceImplName} implements ${table.serviceName} {
|
||||
log.info("${type}Service.delete${type} effect: {}", effect);
|
||||
#if($meta.enableCache)
|
||||
// 删除缓存
|
||||
RedisMaps.delete(${type}CacheKeyDefine.${typeConst});
|
||||
RedisUtils.delete(${type}CacheKeyDefine.${typeConst});
|
||||
#end
|
||||
return effect;
|
||||
}
|
||||
|
||||
@@ -169,7 +169,6 @@
|
||||
Message.success('删除成功');
|
||||
// 重新加载
|
||||
reload();
|
||||
} catch (e) {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -200,7 +199,6 @@
|
||||
pagination.total = data.total;
|
||||
pagination.current = request.page;
|
||||
pagination.pageSize = request.limit;
|
||||
} catch (e) {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -135,8 +135,6 @@
|
||||
}
|
||||
handleClose();
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -139,8 +139,6 @@
|
||||
}
|
||||
handleClose();
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -202,7 +202,6 @@
|
||||
selectedKeys.value = [];
|
||||
// 重新加载
|
||||
reload();
|
||||
} catch (e) {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -220,7 +219,6 @@
|
||||
Message.success('删除成功');
|
||||
// 重新加载
|
||||
reload();
|
||||
} catch (e) {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -246,7 +244,6 @@
|
||||
#if($vue.enableRowSelection)
|
||||
selectedKeys.value = [];
|
||||
#end
|
||||
} catch (e) {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ package org.dromara.visor.framework.test.core.base;
|
||||
|
||||
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
|
||||
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
|
||||
import org.dromara.visor.common.configuration.CommonConfiguration;
|
||||
import org.dromara.visor.common.configuration.SpringConfiguration;
|
||||
import org.dromara.visor.framework.datasource.configuration.OrionDataSourceAutoConfiguration;
|
||||
import org.dromara.visor.framework.mybatis.configuration.OrionMybatisAutoConfiguration;
|
||||
@@ -60,6 +61,7 @@ public class BaseUnitTest {
|
||||
@Import({
|
||||
// spring
|
||||
SpringConfiguration.class,
|
||||
CommonConfiguration.class,
|
||||
// mock
|
||||
OrionMockBeanTestConfiguration.class,
|
||||
OrionMockRedisTestConfiguration.class,
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.dromara.visor.common.constant.AutoConfigureOrderConst;
|
||||
import org.dromara.visor.common.constant.FilterOrderConst;
|
||||
import org.dromara.visor.common.web.WebFilterCreator;
|
||||
import org.dromara.visor.framework.web.configuration.config.ExposeApiConfig;
|
||||
import org.dromara.visor.framework.web.configuration.config.OrionApiConfig;
|
||||
import org.dromara.visor.framework.web.core.aspect.DemoDisableApiAspect;
|
||||
import org.dromara.visor.framework.web.core.aspect.ExposeApiAspect;
|
||||
import org.dromara.visor.framework.web.core.filter.TraceIdFilter;
|
||||
@@ -71,7 +72,7 @@ import java.util.List;
|
||||
@DependsOn({"executorContext"})
|
||||
@AutoConfiguration
|
||||
@AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_WEB)
|
||||
@EnableConfigurationProperties(ExposeApiConfig.class)
|
||||
@EnableConfigurationProperties({ExposeApiConfig.class, OrionApiConfig.class})
|
||||
public class OrionWebAutoConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Value("${orion.prefix}")
|
||||
|
||||
@@ -36,6 +36,11 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
@ConfigurationProperties("orion.api.expose")
|
||||
public class ExposeApiConfig {
|
||||
|
||||
/**
|
||||
* 对外服务地址
|
||||
*/
|
||||
private String host;
|
||||
|
||||
/**
|
||||
* 对外服务请求头
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* 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 org.dromara.visor.framework.web.configuration.config;
|
||||
|
||||
import cn.orionsec.kit.lang.utils.Strings;
|
||||
import cn.orionsec.kit.lang.utils.net.IPs;
|
||||
import lombok.Data;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* api 配置属性
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2025/12/8 14:00
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties("orion.api")
|
||||
public class OrionApiConfig {
|
||||
|
||||
private static final String URL_TEMPLATE = "http://{}:{}{}";
|
||||
|
||||
/**
|
||||
* 公共 api 前缀
|
||||
*/
|
||||
private String prefix;
|
||||
|
||||
/**
|
||||
* 服务端主机地址
|
||||
*/
|
||||
private String host;
|
||||
|
||||
/**
|
||||
* 服务端口
|
||||
*/
|
||||
@Value("${server.port}")
|
||||
private Integer port;
|
||||
|
||||
/**
|
||||
* 服务端 url
|
||||
*/
|
||||
private String url;
|
||||
|
||||
public String getHost() {
|
||||
if (Const.IP_0000.equalsIgnoreCase(host)) {
|
||||
// 本机
|
||||
return IPs.IP;
|
||||
} else {
|
||||
return host;
|
||||
}
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
if (!Strings.isBlank(url)) {
|
||||
return url;
|
||||
}
|
||||
// 构建
|
||||
return Strings.format(URL_TEMPLATE, this.getHost(), port, prefix);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,6 +33,21 @@
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "是否开启 cors 过滤器."
|
||||
},
|
||||
{
|
||||
"name": "orion.api.host",
|
||||
"type": "java.lang.String",
|
||||
"description": "服务端主机地址."
|
||||
},
|
||||
{
|
||||
"name": "orion.api.url",
|
||||
"type": "java.lang.String",
|
||||
"description": "服务端接口地址."
|
||||
},
|
||||
{
|
||||
"name": "orion.api.ip-headers",
|
||||
"type": "java.lang.String",
|
||||
"description": "获取 IP 的请求头."
|
||||
},
|
||||
{
|
||||
"name": "orion.api.expose.header",
|
||||
"type": "java.lang.String",
|
||||
|
||||
@@ -74,6 +74,13 @@ orion:
|
||||
api:
|
||||
# 是否允许跨域
|
||||
cors: ${API_CORS:true}
|
||||
# 服务端主机地址
|
||||
host: ${API_HOST:0.0.0.0}
|
||||
# 服务端接口地址 默认自动生成
|
||||
url: ${API_URL:}
|
||||
# 获取 IP 的请求头
|
||||
ip-headers: ${API_IP_HEADERS:X-Forwarded-For,X-Real-IP}
|
||||
# 对外服务
|
||||
expose:
|
||||
# 暴露接口请求头值
|
||||
token: ${API_EXPOSE_TOKEN:pmqeHOyZaumHm0Wt}
|
||||
|
||||
@@ -175,6 +175,12 @@ orion:
|
||||
prefix: ${orion.prefix}/api
|
||||
# 是否允许跨域
|
||||
cors: true
|
||||
# 服务端主机地址
|
||||
host: 0.0.0.0
|
||||
# 服务端接口地址 默认自动生成
|
||||
url:
|
||||
# 获取 IP 的请求头
|
||||
ip-headers: X-Forwarded-For,X-Real-IP
|
||||
# 对外服务
|
||||
expose:
|
||||
# 暴露接口请求头
|
||||
|
||||
@@ -39,9 +39,9 @@ import java.util.function.Function;
|
||||
*/
|
||||
public class ReplaceVersion {
|
||||
|
||||
private static final String TARGET_VERSION = "2.5.3";
|
||||
private static final String TARGET_VERSION = "2.5.5";
|
||||
|
||||
private static final String REPLACE_VERSION = "2.5.4";
|
||||
private static final String REPLACE_VERSION = "2.5.6";
|
||||
|
||||
private static final String PATH = new File("").getAbsolutePath();
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 主机探针状态 视图响应对象
|
||||
@@ -61,4 +62,7 @@ public class HostAgentStatusVO implements Serializable {
|
||||
@Schema(description = "探针在线状态")
|
||||
private Integer agentOnlineStatus;
|
||||
|
||||
@Schema(description = "探针切换在线状态时间")
|
||||
private Date agentOnlineChangeTime;
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
package org.dromara.visor.module.asset.handler.agent.intstall;
|
||||
|
||||
import cn.orionsec.kit.lang.utils.Exceptions;
|
||||
import cn.orionsec.kit.lang.utils.Strings;
|
||||
import cn.orionsec.kit.net.host.ssh.command.CommandExecutors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.FileConst;
|
||||
@@ -50,7 +51,7 @@ public class LinuxAgentInstaller extends AbstractAgentInstaller {
|
||||
sftpExecutor.write(agentHomePath + FileConst.CONFIG_YAML, this.replaceContent(params.getConfigFilePath()));
|
||||
log.info("写入配置文件成功");
|
||||
// 写入启动脚本
|
||||
sftpExecutor.write(agentHomePath + startScriptName, this.replaceContent(params.getStartScriptPath()));
|
||||
sftpExecutor.write(agentHomePath + startScriptName, Strings.replaceCRLF(this.replaceContent(params.getStartScriptPath())));
|
||||
log.info("写入启动脚本成功");
|
||||
// 上传探针文件
|
||||
sftpExecutor.uploadFile(agentHomePath + uploadAgentName, params.getAgentFilePath());
|
||||
|
||||
@@ -51,6 +51,16 @@ public class HostSpecExtraModel implements GenericsDataModel {
|
||||
*/
|
||||
private String sn;
|
||||
|
||||
/**
|
||||
* 制造商
|
||||
*/
|
||||
private String vendor;
|
||||
|
||||
/**
|
||||
* 型号
|
||||
*/
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 系统名称
|
||||
*/
|
||||
|
||||
@@ -31,7 +31,6 @@ import cn.orionsec.kit.lang.utils.io.FileReaders;
|
||||
import cn.orionsec.kit.lang.utils.io.Files1;
|
||||
import cn.orionsec.kit.lang.utils.io.compress.CompressTypeEnum;
|
||||
import cn.orionsec.kit.lang.utils.io.compress.FileDecompressor;
|
||||
import cn.orionsec.kit.lang.utils.net.IPs;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.common.constant.ErrorMessage;
|
||||
@@ -41,6 +40,8 @@ import org.dromara.visor.common.utils.Assert;
|
||||
import org.dromara.visor.common.utils.PathUtils;
|
||||
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisStrings;
|
||||
import org.dromara.visor.framework.web.configuration.config.ExposeApiConfig;
|
||||
import org.dromara.visor.framework.web.configuration.config.OrionApiConfig;
|
||||
import org.dromara.visor.module.asset.convert.HostConvert;
|
||||
import org.dromara.visor.module.asset.dao.HostAgentLogDAO;
|
||||
import org.dromara.visor.module.asset.dao.HostDAO;
|
||||
@@ -53,7 +54,6 @@ import org.dromara.visor.module.asset.enums.*;
|
||||
import org.dromara.visor.module.asset.handler.agent.intstall.AgentInstaller;
|
||||
import org.dromara.visor.module.asset.handler.agent.model.AgentInstallParams;
|
||||
import org.dromara.visor.module.asset.service.HostAgentService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@@ -77,8 +77,11 @@ public class HostAgentServiceImpl implements HostAgentService {
|
||||
|
||||
private String localVersion;
|
||||
|
||||
@Value("${orion.api.expose.token}")
|
||||
private String exposeToken;
|
||||
@Resource
|
||||
private OrionApiConfig orionApiConfig;
|
||||
|
||||
@Resource
|
||||
private ExposeApiConfig exposeApiConfig;
|
||||
|
||||
@Resource
|
||||
private HostDAO hostDAO;
|
||||
@@ -119,7 +122,8 @@ public class HostAgentServiceImpl implements HostAgentService {
|
||||
.select(HostDO::getId,
|
||||
HostDO::getAgentVersion,
|
||||
HostDO::getAgentInstallStatus,
|
||||
HostDO::getAgentOnlineStatus)
|
||||
HostDO::getAgentOnlineStatus,
|
||||
HostDO::getAgentOnlineChangeTime)
|
||||
.in(HostDO::getId, idList)
|
||||
.then()
|
||||
.stream()
|
||||
@@ -301,8 +305,8 @@ public class HostAgentServiceImpl implements HostAgentService {
|
||||
*/
|
||||
private Map<String, String> getReplaceVars() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("SERVER_HOST", IPs.IP);
|
||||
map.put("SERVER_TOKEN", exposeToken);
|
||||
map.put("SERVER_URL", orionApiConfig.getUrl());
|
||||
map.put("SERVER_TOKEN", exposeApiConfig.getToken());
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,13 @@
|
||||
*/
|
||||
package org.dromara.visor.module.asset.service.impl;
|
||||
|
||||
import cn.orionsec.kit.lang.utils.Exceptions;
|
||||
import cn.orionsec.kit.lang.utils.Strings;
|
||||
import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||
import cn.orionsec.kit.lang.utils.collect.Maps;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.common.constant.ErrorMessage;
|
||||
import org.dromara.visor.common.handler.data.model.GenericsDataModel;
|
||||
@@ -44,6 +47,7 @@ import org.dromara.visor.module.infra.enums.DataExtraTypeEnum;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -55,6 +59,7 @@ import java.util.stream.Collectors;
|
||||
* @version 1.0.0
|
||||
* @since 2023/12/20 12:11
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class HostExtraServiceImpl implements HostExtraService {
|
||||
|
||||
@@ -156,40 +161,57 @@ public class HostExtraServiceImpl implements HostExtraService {
|
||||
|
||||
@Override
|
||||
public void syncHostSpec(String key, String taskId, JSONObject spec) {
|
||||
try {
|
||||
// 查询主机id
|
||||
Long id = hostDAO.selectIdByAgentKey(key);
|
||||
Assert.notNull(id, ErrorMessage.HOST_ABSENT);
|
||||
// 设置已同步标识
|
||||
spec.put(Const.SYNCED, true);
|
||||
// 查询配置信息
|
||||
String newSpec;
|
||||
HostSpecExtraModel beforeSpec = this.getHostSpecMap(Lists.singleton(id)).get(id);
|
||||
if (beforeSpec == null) {
|
||||
// 新增
|
||||
newSpec = spec.toString();
|
||||
} else {
|
||||
// 合并
|
||||
JSONObject beforeSpecValue = JSON.parseObject(beforeSpec.serial());
|
||||
spec.forEach((k, v) -> {
|
||||
if (v != null) {
|
||||
beforeSpecValue.put(k, v);
|
||||
// 查询主机id
|
||||
Long id = hostDAO.selectIdByAgentKey(key);
|
||||
Assert.notNull(id, ErrorMessage.HOST_ABSENT);
|
||||
// 设置已同步标识
|
||||
spec.put(Const.SYNCED, true);
|
||||
// 查询配置信息
|
||||
String newSpec;
|
||||
HostSpecExtraModel beforeSpec = this.getHostSpecMap(Lists.singleton(id)).get(id);
|
||||
if (beforeSpec == null) {
|
||||
// 新增
|
||||
newSpec = spec.toString();
|
||||
} else {
|
||||
// 合并
|
||||
JSONObject beforeSpecValue = JSON.parseObject(beforeSpec.serial());
|
||||
spec.forEach((k, v) -> {
|
||||
// 获取原数据
|
||||
Object beforeValue = beforeSpecValue.get(k);
|
||||
// 检查是否存在
|
||||
boolean present = false;
|
||||
if (beforeValue != null) {
|
||||
if (beforeValue instanceof String) {
|
||||
present = !Strings.isBlank((String) beforeValue);
|
||||
} else if (beforeValue instanceof Collection) {
|
||||
present = !Lists.isEmpty((Collection<?>) beforeValue);
|
||||
} else if (beforeValue instanceof Map) {
|
||||
present = !Maps.isEmpty((Map<?, ?>) beforeValue);
|
||||
} else {
|
||||
present = true;
|
||||
}
|
||||
});
|
||||
newSpec = beforeSpecValue.toJSONString();
|
||||
}
|
||||
// 修改规格
|
||||
DataExtraSetDTO update = new DataExtraSetDTO();
|
||||
update.setUserId(Const.SYSTEM_USER_ID);
|
||||
update.setRelId(id);
|
||||
update.setItem(HostExtraItemEnum.SPEC.name());
|
||||
update.setValue(newSpec);
|
||||
dataExtraApi.setExtraItem(update, DataExtraTypeEnum.HOST);
|
||||
// 回调成功
|
||||
} catch (Exception e) {
|
||||
// 回调失败
|
||||
throw e;
|
||||
}
|
||||
// 不存在则覆盖
|
||||
if (!present && v != null) {
|
||||
beforeSpecValue.put(k, v);
|
||||
}
|
||||
});
|
||||
newSpec = beforeSpecValue.toJSONString();
|
||||
}
|
||||
// 检查是否能反解析 防止格式错误导致其他地方报错
|
||||
try {
|
||||
JSON.parseObject(newSpec, HostSpecExtraModel.class);
|
||||
} catch (Exception e) {
|
||||
log.error("HostExtraService-setHostSpec error: {}, spec: {}", e.getMessage(), newSpec, e);
|
||||
throw Exceptions.app(ErrorMessage.SPEC_FORMAT_INCORRECT, e);
|
||||
}
|
||||
// 修改规格
|
||||
DataExtraSetDTO update = new DataExtraSetDTO();
|
||||
update.setUserId(Const.SYSTEM_USER_ID);
|
||||
update.setRelId(id);
|
||||
update.setItem(HostExtraItemEnum.SPEC.name());
|
||||
update.setValue(newSpec);
|
||||
dataExtraApi.setExtraItem(update, DataExtraTypeEnum.HOST);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -110,7 +110,7 @@ public class HostIdentityServiceImpl implements HostIdentityService {
|
||||
int effect = hostIdentityDAO.insert(record);
|
||||
log.info("HostIdentityService-createHostIdentity effect: {}", effect);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(HostCacheKeyDefine.HOST_IDENTITY);
|
||||
RedisUtils.delete(HostCacheKeyDefine.HOST_IDENTITY);
|
||||
return record.getId();
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ public class HostIdentityServiceImpl implements HostIdentityService {
|
||||
int effect = hostIdentityDAO.update(updateRecord, wrapper);
|
||||
log.info("HostIdentityService-updateHostIdentityById effect: {}", effect);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(HostCacheKeyDefine.HOST_IDENTITY);
|
||||
RedisUtils.delete(HostCacheKeyDefine.HOST_IDENTITY);
|
||||
return effect;
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ public class HostIdentityServiceImpl implements HostIdentityService {
|
||||
.eq(HostIdentityDO::getName, domain.getName());
|
||||
// 检查是否存在
|
||||
boolean present = hostIdentityDAO.of(wrapper).present();
|
||||
Assert.isFalse(present, ErrorMessage.DATA_PRESENT);
|
||||
Assert.isFalse(present, ErrorMessage.NAME_PRESENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -104,7 +104,7 @@ public class HostKeyServiceImpl implements HostKeyService {
|
||||
log.info("HostKeyService-createHostKey effect: {}", effect);
|
||||
Long id = record.getId();
|
||||
// 删除缓存
|
||||
RedisMaps.delete(HostCacheKeyDefine.HOST_KEY);
|
||||
RedisUtils.delete(HostCacheKeyDefine.HOST_KEY);
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ public class HostKeyServiceImpl implements HostKeyService {
|
||||
int effect = hostKeyDAO.updateById(updateRecord);
|
||||
// 删除缓存
|
||||
if (!record.getName().equals(updateRecord.getName())) {
|
||||
RedisMaps.delete(HostCacheKeyDefine.HOST_KEY);
|
||||
RedisUtils.delete(HostCacheKeyDefine.HOST_KEY);
|
||||
}
|
||||
log.info("HostKeyService-updateHostKeyById effect: {}", effect);
|
||||
return effect;
|
||||
@@ -242,7 +242,7 @@ public class HostKeyServiceImpl implements HostKeyService {
|
||||
.eq(HostKeyDO::getName, domain.getName());
|
||||
// 检查是否存在
|
||||
boolean present = hostKeyDAO.of(wrapper).present();
|
||||
Assert.isFalse(present, ErrorMessage.DATA_PRESENT);
|
||||
Assert.isFalse(present, ErrorMessage.NAME_PRESENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.dromara.visor.common.utils.Assert;
|
||||
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
||||
import org.dromara.visor.framework.mybatis.core.query.DataQuery;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisMaps;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisUtils;
|
||||
import org.dromara.visor.framework.redis.core.utils.barrier.CacheBarriers;
|
||||
import org.dromara.visor.module.asset.convert.HostConvert;
|
||||
import org.dromara.visor.module.asset.dao.HostConfigDAO;
|
||||
@@ -376,7 +377,7 @@ public class HostServiceImpl implements HostService {
|
||||
|
||||
@Override
|
||||
public void clearCache() {
|
||||
RedisMaps.scanKeysDelete(HostCacheKeyDefine.HOST_INFO.format("*"));
|
||||
RedisUtils.scanKeysDelete(HostCacheKeyDefine.HOST_INFO.format("*"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -408,7 +408,7 @@ public class ExecJobServiceImpl implements ExecJobService {
|
||||
.eq(ExecJobDO::getName, domain.getName());
|
||||
// 检查是否存在
|
||||
boolean present = execJobDAO.of(wrapper).present();
|
||||
Assert.isFalse(present, ErrorMessage.DATA_PRESENT);
|
||||
Assert.isFalse(present, ErrorMessage.NAME_PRESENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -208,7 +208,7 @@ public class ExecTemplateServiceImpl implements ExecTemplateService {
|
||||
.eq(ExecTemplateDO::getName, domain.getName());
|
||||
// 检查是否存在
|
||||
boolean present = execTemplateDAO.of(wrapper).present();
|
||||
Assert.isFalse(present, ErrorMessage.DATA_PRESENT);
|
||||
Assert.isFalse(present, ErrorMessage.NAME_PRESENT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ package org.dromara.visor.module.infra.api.impl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.ErrorMessage;
|
||||
import org.dromara.visor.common.utils.Assert;
|
||||
import org.dromara.visor.common.utils.Requests;
|
||||
import org.dromara.visor.module.infra.api.AuthenticationApi;
|
||||
import org.dromara.visor.module.infra.entity.domain.SystemUserDO;
|
||||
import org.dromara.visor.module.infra.entity.dto.user.SystemUserAuthDTO;
|
||||
@@ -57,7 +58,11 @@ public class AuthenticationApiImpl implements AuthenticationApi {
|
||||
result.setUsername(user.getUsername());
|
||||
result.setNickname(user.getNickname());
|
||||
// 检查用户密码
|
||||
boolean passRight = authenticationService.checkUserPassword(user, password, addFailedCount);
|
||||
boolean passRight = authenticationService.checkUserPassword(user, password);
|
||||
if (!passRight && addFailedCount) {
|
||||
// 发送站内信
|
||||
authenticationService.addLoginFailedCount(user.getUsername(), Requests.getIdentity());
|
||||
}
|
||||
result.setPassRight(passRight);
|
||||
Assert.isTrue(passRight, ErrorMessage.USERNAME_PASSWORD_ERROR);
|
||||
// 检查用户状态
|
||||
|
||||
@@ -63,9 +63,8 @@ public class AuthenticationController {
|
||||
@PermitAll
|
||||
@Operation(summary = "登录")
|
||||
@PostMapping("/login")
|
||||
public UserLoginVO login(@Validated @RequestBody UserLoginRequest request,
|
||||
HttpServletRequest servletRequest) {
|
||||
return authenticationService.login(request, servletRequest);
|
||||
public UserLoginVO login(@Validated @RequestBody UserLoginRequest request) {
|
||||
return authenticationService.login(request);
|
||||
}
|
||||
|
||||
@OperatorLog(AuthenticationOperatorType.LOGOUT)
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.dromara.visor.module.infra.define.operator.SystemUserOperatorType;
|
||||
import org.dromara.visor.module.infra.entity.request.user.*;
|
||||
import org.dromara.visor.module.infra.entity.vo.LoginHistoryVO;
|
||||
import org.dromara.visor.module.infra.entity.vo.SystemUserVO;
|
||||
import org.dromara.visor.module.infra.entity.vo.UserLockedVO;
|
||||
import org.dromara.visor.module.infra.entity.vo.UserSessionVO;
|
||||
import org.dromara.visor.module.infra.service.OperatorLogService;
|
||||
import org.dromara.visor.module.infra.service.SystemUserManagementService;
|
||||
@@ -190,7 +191,33 @@ public class SystemUserController {
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/session/list")
|
||||
@GetMapping("/locked/list")
|
||||
@Operation(summary = "获取锁定的用户列表")
|
||||
@PreAuthorize("@ss.hasPermission('infra:system-user:query-lock')")
|
||||
public List<UserLockedVO> getLockedUserList() {
|
||||
return systemUserManagementService.getLockedUserList();
|
||||
}
|
||||
|
||||
@OperatorLog(SystemUserOperatorType.UNLOCK)
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@PutMapping("/locked/unlock")
|
||||
@Operation(summary = "解锁用户")
|
||||
@PreAuthorize("@ss.hasPermission('infra:system-user:management:unlock')")
|
||||
public Boolean unlockLockedUser(@RequestBody UserUnlockRequest request) {
|
||||
systemUserManagementService.unlockLockedUser(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/session/users/list")
|
||||
@Operation(summary = "获取全部用户会话列表")
|
||||
@PreAuthorize("@ss.hasPermission('infra:system-user:query-session')")
|
||||
public List<UserSessionVO> getUsersSessionList() {
|
||||
return systemUserManagementService.getUsersSessionList();
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/session/user/list")
|
||||
@Operation(summary = "获取用户会话列表")
|
||||
@PreAuthorize("@ss.hasPermission('infra:system-user:query-session')")
|
||||
public List<UserSessionVO> getUserSessionList(@RequestParam("id") Long id) {
|
||||
|
||||
@@ -22,16 +22,24 @@
|
||||
*/
|
||||
package org.dromara.visor.module.infra.controller;
|
||||
|
||||
import cn.orionsec.kit.lang.define.wrapper.DataGrid;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.validator.group.Page;
|
||||
import org.dromara.visor.framework.biz.operator.log.core.annotation.OperatorLog;
|
||||
import org.dromara.visor.framework.log.core.annotation.IgnoreLog;
|
||||
import org.dromara.visor.framework.log.core.enums.IgnoreLogMode;
|
||||
import org.dromara.visor.framework.web.core.annotation.DemoDisableApi;
|
||||
import org.dromara.visor.framework.web.core.annotation.RestWrapper;
|
||||
import org.dromara.visor.module.infra.define.operator.TagOperatorType;
|
||||
import org.dromara.visor.module.infra.entity.request.tag.TagCreateRequest;
|
||||
import org.dromara.visor.module.infra.entity.request.tag.TagQueryRequest;
|
||||
import org.dromara.visor.module.infra.entity.request.tag.TagUpdateRequest;
|
||||
import org.dromara.visor.module.infra.entity.vo.TagVO;
|
||||
import org.dromara.visor.module.infra.service.TagService;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -39,13 +47,13 @@ import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 标签枚举 api
|
||||
* 数据标签 api
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023-9-5 11:58
|
||||
*/
|
||||
@Tag(name = "infra - 标签枚举服务")
|
||||
@Tag(name = "infra - 数据标签服务")
|
||||
@Slf4j
|
||||
@Validated
|
||||
@RestWrapper
|
||||
@@ -56,12 +64,32 @@ public class TagController {
|
||||
@Resource
|
||||
private TagService tagService;
|
||||
|
||||
@DemoDisableApi
|
||||
@OperatorLog(TagOperatorType.CREATE)
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建标签")
|
||||
@PreAuthorize("@ss.hasPermission('infra:tag:create')")
|
||||
public Long createTag(@Validated @RequestBody TagCreateRequest request) {
|
||||
return tagService.createTag(request);
|
||||
}
|
||||
|
||||
@DemoDisableApi
|
||||
@OperatorLog(TagOperatorType.UPDATE)
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改标签")
|
||||
@PreAuthorize("@ss.hasPermission('infra:tag:update')")
|
||||
public Integer updateTag(@Validated @RequestBody TagUpdateRequest request) {
|
||||
return tagService.updateTag(request);
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@PostMapping("/query")
|
||||
@Operation(summary = "分页查询标签")
|
||||
@PreAuthorize("@ss.hasPermission('infra:tag:query')")
|
||||
public DataGrid<TagVO> getTagPage(@Validated(Page.class) @RequestBody TagQueryRequest request) {
|
||||
return tagService.getTagPage(request);
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询标签")
|
||||
@@ -70,12 +98,14 @@ public class TagController {
|
||||
return tagService.getTagList(type);
|
||||
}
|
||||
|
||||
@DemoDisableApi
|
||||
@OperatorLog(TagOperatorType.DELETE)
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "通过 id 删除标签")
|
||||
@Parameter(name = "id", description = "id", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('infra:tag:delete')")
|
||||
public Integer deleteTag(@RequestParam("id") Long id) {
|
||||
return tagService.deleteTagById(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -22,12 +22,14 @@
|
||||
*/
|
||||
package org.dromara.visor.module.infra.convert;
|
||||
|
||||
import org.dromara.visor.common.mapstruct.DateConversion;
|
||||
import org.dromara.visor.framework.biz.operator.log.core.model.OperatorLogModel;
|
||||
import org.dromara.visor.module.infra.entity.domain.OperatorLogDO;
|
||||
import org.dromara.visor.module.infra.entity.request.operator.OperatorLogQueryRequest;
|
||||
import org.dromara.visor.module.infra.entity.vo.LoginHistoryVO;
|
||||
import org.dromara.visor.module.infra.entity.vo.OperatorLogVO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
@@ -37,11 +39,12 @@ import org.mapstruct.factory.Mappers;
|
||||
* @version 1.0.0
|
||||
* @since 2023-10-10 17:08
|
||||
*/
|
||||
@Mapper
|
||||
@Mapper(uses = DateConversion.class)
|
||||
public interface OperatorLogConvert {
|
||||
|
||||
OperatorLogConvert MAPPER = Mappers.getMapper(OperatorLogConvert.class);
|
||||
|
||||
@Mapping(source = "timestamp", target = "createTime")
|
||||
OperatorLogDO to(OperatorLogModel model);
|
||||
|
||||
OperatorLogDO to(OperatorLogQueryRequest request);
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.dromara.visor.module.infra.entity.domain.TagDO;
|
||||
import org.dromara.visor.module.infra.entity.dto.TagCacheDTO;
|
||||
import org.dromara.visor.module.infra.entity.request.tag.TagCreateRequest;
|
||||
import org.dromara.visor.module.infra.entity.request.tag.TagQueryRequest;
|
||||
import org.dromara.visor.module.infra.entity.request.tag.TagUpdateRequest;
|
||||
import org.dromara.visor.module.infra.entity.vo.TagVO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
@@ -33,7 +34,7 @@ import org.mapstruct.factory.Mappers;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 标签枚举 内部对象转换器
|
||||
* 数据标签 内部对象转换器
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
@@ -46,6 +47,8 @@ public interface TagConvert {
|
||||
|
||||
TagDO to(TagCreateRequest request);
|
||||
|
||||
TagDO to(TagUpdateRequest request);
|
||||
|
||||
TagDO to(TagQueryRequest request);
|
||||
|
||||
TagVO to(TagDO domain);
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.mapstruct.factory.Mappers;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 标签枚举 对外对象转换器
|
||||
* 数据标签 对外对象转换器
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.dromara.visor.module.infra.entity.domain.TagDO;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 标签枚举 Mapper 接口
|
||||
* 数据标签 Mapper 接口
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
|
||||
@@ -24,8 +24,10 @@ package org.dromara.visor.module.infra.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.visor.framework.mybatis.core.mapper.IMapper;
|
||||
import org.dromara.visor.module.infra.entity.domain.TagRelDO;
|
||||
import org.dromara.visor.module.infra.entity.po.TagRelCountPO;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -72,4 +74,12 @@ public interface TagRelDAO extends IMapper<TagRelDO> {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询标签引用数量
|
||||
*
|
||||
* @param tagIdList tagIdList
|
||||
* @return count
|
||||
*/
|
||||
List<TagRelCountPO> selectTagRelCount(@Param("tagIdList") List<Long> tagIdList);
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import cn.orionsec.kit.lang.define.cache.key.CacheKeyBuilder;
|
||||
import cn.orionsec.kit.lang.define.cache.key.CacheKeyDefine;
|
||||
import cn.orionsec.kit.lang.define.cache.key.struct.RedisCacheStruct;
|
||||
import org.dromara.visor.common.security.LoginUser;
|
||||
import org.dromara.visor.module.infra.entity.dto.LoginFailedDTO;
|
||||
import org.dromara.visor.module.infra.entity.dto.LoginTokenDTO;
|
||||
import org.dromara.visor.module.infra.entity.dto.UserInfoDTO;
|
||||
|
||||
@@ -56,12 +57,13 @@ public interface UserCacheKeyDefine {
|
||||
.timeout(8, TimeUnit.HOURS)
|
||||
.build();
|
||||
|
||||
CacheKeyDefine LOGIN_FAILED_COUNT = new CacheKeyBuilder()
|
||||
.key("user:login-failed:{}")
|
||||
.desc("用户登录失败次数 ${username}")
|
||||
CacheKeyDefine LOGIN_FAILED = new CacheKeyBuilder()
|
||||
.key("user:login-failed-info:{}")
|
||||
.desc("用户登录失败信息 ${username}")
|
||||
.noPrefix()
|
||||
.type(Integer.class)
|
||||
.type(LoginFailedDTO.class)
|
||||
.struct(RedisCacheStruct.STRING)
|
||||
.timeout(24 * 60, TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
CacheKeyDefine LOGIN_TOKEN = new CacheKeyBuilder()
|
||||
|
||||
@@ -50,6 +50,8 @@ public class SystemUserOperatorType extends InitializingOperatorTypes {
|
||||
|
||||
public static final String DELETE = "system-user:delete";
|
||||
|
||||
public static final String UNLOCK = "system-user:unlock";
|
||||
|
||||
public static final String OFFLINE = "system-user:offline";
|
||||
|
||||
@Override
|
||||
@@ -61,6 +63,7 @@ public class SystemUserOperatorType extends InitializingOperatorTypes {
|
||||
new OperatorType(M, GRANT_ROLE, "分配用户角色 <sb>${username}</sb>"),
|
||||
new OperatorType(H, RESET_PASSWORD, "重置用户密码 <sb>${username}</sb>"),
|
||||
new OperatorType(H, DELETE, "删除用户 <sb>${username}</sb>"),
|
||||
new OperatorType(M, UNLOCK, "解锁用户 <sb>${username}</sb>"),
|
||||
new OperatorType(M, OFFLINE, "下线用户会话 <sb>${username}</sb>"),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* 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 org.dromara.visor.module.infra.define.operator;
|
||||
|
||||
import org.dromara.visor.framework.biz.operator.log.core.annotation.Module;
|
||||
import org.dromara.visor.framework.biz.operator.log.core.factory.InitializingOperatorTypes;
|
||||
import org.dromara.visor.framework.biz.operator.log.core.model.OperatorType;
|
||||
|
||||
import static org.dromara.visor.framework.biz.operator.log.core.enums.OperatorRiskLevel.L;
|
||||
import static org.dromara.visor.framework.biz.operator.log.core.enums.OperatorRiskLevel.M;
|
||||
|
||||
/**
|
||||
* 数据标签 操作日志类型
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/10/10 17:30
|
||||
*/
|
||||
@Module("infra:tag")
|
||||
public class TagOperatorType extends InitializingOperatorTypes {
|
||||
|
||||
public static final String CREATE = "tag:create";
|
||||
|
||||
public static final String UPDATE = "tag:update";
|
||||
|
||||
public static final String DELETE = "tag:delete";
|
||||
|
||||
@Override
|
||||
public OperatorType[] types() {
|
||||
return new OperatorType[]{
|
||||
new OperatorType(L, CREATE, "创建数据标签 <sb>${name}</sb>"),
|
||||
new OperatorType(L, UPDATE, "修改数据标签 <sb>${name}</sb>"),
|
||||
new OperatorType(M, DELETE, "删除数据标签 <sb>${name}</sb>"),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,7 +33,7 @@ import lombok.experimental.SuperBuilder;
|
||||
import org.dromara.visor.framework.mybatis.core.domain.BaseDO;
|
||||
|
||||
/**
|
||||
* 标签枚举 实体对象
|
||||
* 数据标签 实体对象
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
@@ -45,7 +45,7 @@ import org.dromara.visor.framework.mybatis.core.domain.BaseDO;
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName(value = "tag", autoResultMap = true)
|
||||
@Schema(name = "TagDO", description = "标签枚举 实体对象")
|
||||
@Schema(name = "TagDO", description = "数据标签 实体对象")
|
||||
public class TagDO extends BaseDO {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -23,40 +23,42 @@
|
||||
package org.dromara.visor.module.infra.entity.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.dromara.visor.common.entity.RequestIdentity;
|
||||
import org.dromara.visor.common.entity.RequestIdentityModel;
|
||||
|
||||
/**
|
||||
* 身份信息
|
||||
* 登录失败信息
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/11/1 1:01
|
||||
* @since 2025/10/8 15:44
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
public class LoginTokenIdentityDTO implements RequestIdentity {
|
||||
@NoArgsConstructor
|
||||
public class LoginFailedDTO {
|
||||
|
||||
/**
|
||||
* 原始登录时间
|
||||
* 用户名
|
||||
*/
|
||||
private Long loginTime;
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 当前设备登录地址
|
||||
* 失败次数
|
||||
*/
|
||||
private String address;
|
||||
private Integer failedCount;
|
||||
|
||||
/**
|
||||
* 当前设备登录地址
|
||||
* 失效时间
|
||||
*/
|
||||
private String location;
|
||||
private Long expireTime;
|
||||
|
||||
/**
|
||||
* 当前设备 userAgent
|
||||
* 原始登录留痕信息
|
||||
*/
|
||||
private String userAgent;
|
||||
private RequestIdentityModel origin;
|
||||
|
||||
}
|
||||
@@ -26,7 +26,7 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.dromara.visor.module.infra.enums.LoginTokenStatusEnum;
|
||||
import org.dromara.visor.common.entity.RequestIdentityModel;
|
||||
|
||||
/**
|
||||
* 登录 token 缓存
|
||||
@@ -42,14 +42,19 @@ import org.dromara.visor.module.infra.enums.LoginTokenStatusEnum;
|
||||
public class LoginTokenDTO {
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
* userId
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* token 状态
|
||||
*
|
||||
* @see LoginTokenStatusEnum
|
||||
* @see org.dromara.visor.module.infra.enums.LoginTokenStatusEnum
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
@@ -59,13 +64,13 @@ public class LoginTokenDTO {
|
||||
private Integer refreshCount;
|
||||
|
||||
/**
|
||||
* 原始登录身份
|
||||
* 原始登录留痕信息
|
||||
*/
|
||||
private LoginTokenIdentityDTO origin;
|
||||
private RequestIdentityModel origin;
|
||||
|
||||
/**
|
||||
* 覆盖登录身份
|
||||
* 覆盖登录刘海信息
|
||||
*/
|
||||
private LoginTokenIdentityDTO override;
|
||||
private RequestIdentityModel override;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* 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 org.dromara.visor.module.infra.entity.po;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 标签关联数量
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/12/23 16:24
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "TagRelCountPO", description = "标签关联数量")
|
||||
public class TagRelCountPO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "tagId")
|
||||
private Long tagId;
|
||||
|
||||
@Schema(description = "数量")
|
||||
private Integer count;
|
||||
|
||||
}
|
||||
@@ -33,7 +33,7 @@ import javax.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 标签枚举 创建请求对象
|
||||
* 数据标签 创建请求对象
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
@@ -43,17 +43,17 @@ import java.io.Serializable;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "TagCreateRequest", description = "标签枚举 创建请求对象")
|
||||
@Schema(name = "TagCreateRequest", description = "数据标签 创建请求对象")
|
||||
public class TagCreateRequest implements Serializable {
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 32)
|
||||
@Schema(description = "标签名称")
|
||||
private String name;
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 12)
|
||||
@Schema(description = "标签类型")
|
||||
private String type;
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 32)
|
||||
@Schema(description = "标签名称")
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.dromara.visor.common.entity.BaseQueryRequest;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 标签枚举 查询请求对象
|
||||
* 数据标签 查询请求对象
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
@@ -40,11 +40,15 @@ import javax.validation.constraints.Size;
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(name = "TagQueryRequest", description = "标签枚举 查询请求对象")
|
||||
@Schema(name = "TagQueryRequest", description = "数据标签 查询请求对象")
|
||||
public class TagQueryRequest extends BaseQueryRequest {
|
||||
|
||||
@Size(max = 12)
|
||||
@Schema(description = "标签类型")
|
||||
private String type;
|
||||
|
||||
@Size(max = 32)
|
||||
@Schema(description = "标签名称")
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
||||
@@ -64,4 +64,7 @@ public class TagRelQueryRequest extends BaseQueryRequest {
|
||||
@Schema(description = "关联id")
|
||||
private Collection<Long> relIdList;
|
||||
|
||||
@Schema(description = "tagId")
|
||||
private Collection<Long> tagIdList;
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ import javax.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 标签枚举 更新请求对象
|
||||
* 数据标签 更新请求对象
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
@@ -44,7 +44,7 @@ import java.io.Serializable;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "TagUpdateRequest", description = "标签枚举 更新请求对象")
|
||||
@Schema(name = "TagUpdateRequest", description = "数据标签 更新请求对象")
|
||||
public class TagUpdateRequest implements Serializable {
|
||||
|
||||
@NotNull
|
||||
@@ -56,9 +56,4 @@ public class TagUpdateRequest implements Serializable {
|
||||
@Schema(description = "标签名称")
|
||||
private String name;
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 12)
|
||||
@Schema(description = "标签类型")
|
||||
private String type;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* 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 org.dromara.visor.module.infra.entity.request.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 用户解锁请求
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/7/17 12:19
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "UserUnlockRequest", description = "用户解锁请求")
|
||||
public class UserUnlockRequest {
|
||||
|
||||
@NotBlank
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
}
|
||||
@@ -29,9 +29,10 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 标签枚举 视图响应对象
|
||||
* 数据标签 视图响应对象
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
@@ -41,7 +42,7 @@ import java.io.Serializable;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "TagVO", description = "标签枚举 视图响应对象")
|
||||
@Schema(name = "TagVO", description = "数据标签 视图响应对象")
|
||||
public class TagVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -49,7 +50,25 @@ public class TagVO implements Serializable {
|
||||
@Schema(description = "id")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "标签类型")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "标签名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "关联数量")
|
||||
private Integer relCount;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
@Schema(description = "修改时间")
|
||||
private Date updateTime;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creator;
|
||||
|
||||
@Schema(description = "修改人")
|
||||
private String updater;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* 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 org.dromara.visor.module.infra.entity.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户锁定 响应对象
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023-7-13 18:42
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "UserLockedVO", description = "用户锁定 响应对象")
|
||||
public class UserLockedVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "失效时间")
|
||||
private Long expireTime;
|
||||
|
||||
@Schema(description = "请求ip")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "请求地址")
|
||||
private String location;
|
||||
|
||||
@Schema(description = "userAgent")
|
||||
private String userAgent;
|
||||
|
||||
@Schema(description = "登录时间")
|
||||
private Date loginTime;
|
||||
|
||||
}
|
||||
@@ -47,6 +47,12 @@ public class UserSessionVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "id")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "是否为当前会话")
|
||||
private Boolean current;
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@ import cn.orionsec.kit.lang.utils.time.Dates;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.dromara.visor.common.constant.ErrorCode;
|
||||
import org.dromara.visor.common.entity.RequestIdentityModel;
|
||||
import org.dromara.visor.module.infra.entity.dto.LoginTokenDTO;
|
||||
import org.dromara.visor.module.infra.entity.dto.LoginTokenIdentityDTO;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@@ -53,9 +53,9 @@ public enum LoginTokenStatusEnum {
|
||||
OTHER_DEVICE(1) {
|
||||
@Override
|
||||
public RuntimeException toException(LoginTokenDTO token) {
|
||||
LoginTokenIdentityDTO override = token.getOverride();
|
||||
RequestIdentityModel override = token.getOverride();
|
||||
return ErrorCode.USER_OTHER_DEVICE_LOGIN.exception(
|
||||
Dates.format(new Date(override.getLoginTime()), Dates.MD_HM),
|
||||
Dates.format(new Date(override.getTimestamp()), Dates.MD_HM),
|
||||
override.getAddress(),
|
||||
override.getLocation());
|
||||
}
|
||||
@@ -68,9 +68,9 @@ public enum LoginTokenStatusEnum {
|
||||
SESSION_OFFLINE(2) {
|
||||
@Override
|
||||
public RuntimeException toException(LoginTokenDTO token) {
|
||||
LoginTokenIdentityDTO override = token.getOverride();
|
||||
RequestIdentityModel override = token.getOverride();
|
||||
return ErrorCode.USER_OFFLINE.exception(
|
||||
Dates.format(new Date(override.getLoginTime()), Dates.MD_HM),
|
||||
Dates.format(new Date(override.getTimestamp()), Dates.MD_HM),
|
||||
override.getAddress(),
|
||||
override.getLocation());
|
||||
}
|
||||
|
||||
@@ -82,12 +82,13 @@ public class SecurityFrameworkServiceImpl implements SecurityFrameworkService {
|
||||
if (tokenInfo == null) {
|
||||
return null;
|
||||
}
|
||||
Long loginTime = tokenInfo.getOrigin().getTimestamp();
|
||||
try {
|
||||
// 检查 token 状态
|
||||
this.checkTokenStatus(tokenInfo);
|
||||
} catch (Exception e) {
|
||||
// token 失效则删除
|
||||
RedisUtils.delete(UserCacheKeyDefine.LOGIN_TOKEN.format(tokenInfo.getId(), tokenInfo.getOrigin().getLoginTime()));
|
||||
RedisUtils.delete(UserCacheKeyDefine.LOGIN_TOKEN.format(tokenInfo.getId(), loginTime));
|
||||
throw e;
|
||||
}
|
||||
// 获取登录信息
|
||||
@@ -98,7 +99,7 @@ public class SecurityFrameworkServiceImpl implements SecurityFrameworkService {
|
||||
// 检查用户状态
|
||||
UserStatusEnum.checkUserStatus(user.getStatus());
|
||||
// 设置登录时间戳
|
||||
user.setTimestamp(tokenInfo.getOrigin().getLoginTime());
|
||||
user.setTimestamp(loginTime);
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
package org.dromara.visor.module.infra.service;
|
||||
|
||||
import org.dromara.visor.common.entity.RequestIdentityModel;
|
||||
import org.dromara.visor.common.security.LoginUser;
|
||||
import org.dromara.visor.module.infra.entity.domain.SystemUserDO;
|
||||
import org.dromara.visor.module.infra.entity.dto.LoginTokenDTO;
|
||||
@@ -42,11 +43,10 @@ public interface AuthenticationService {
|
||||
/**
|
||||
* 登录
|
||||
*
|
||||
* @param request request
|
||||
* @param servletRequest servletRequest
|
||||
* @param request request
|
||||
* @return login
|
||||
*/
|
||||
UserLoginVO login(UserLoginRequest request, HttpServletRequest servletRequest);
|
||||
UserLoginVO login(UserLoginRequest request);
|
||||
|
||||
/**
|
||||
* 登出
|
||||
@@ -83,12 +83,19 @@ public interface AuthenticationService {
|
||||
/**
|
||||
* 检查用户密码
|
||||
*
|
||||
* @param user user
|
||||
* @param password password
|
||||
* @param addFailedCount addFailedCount
|
||||
* @param user user
|
||||
* @param password password
|
||||
* @return passRight
|
||||
*/
|
||||
boolean checkUserPassword(SystemUserDO user, String password, boolean addFailedCount);
|
||||
boolean checkUserPassword(SystemUserDO user, String password);
|
||||
|
||||
/**
|
||||
* 添加登录失败次数
|
||||
*
|
||||
* @param username username
|
||||
* @param identity identity
|
||||
*/
|
||||
void addLoginFailedCount(String username, RequestIdentityModel identity);
|
||||
|
||||
/**
|
||||
* 检查用户状态
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
package org.dromara.visor.module.infra.service;
|
||||
|
||||
import org.dromara.visor.module.infra.entity.request.user.UserSessionOfflineRequest;
|
||||
import org.dromara.visor.module.infra.entity.request.user.UserUnlockRequest;
|
||||
import org.dromara.visor.module.infra.entity.vo.UserLockedVO;
|
||||
import org.dromara.visor.module.infra.entity.vo.UserSessionVO;
|
||||
|
||||
import java.util.List;
|
||||
@@ -44,6 +46,27 @@ public interface SystemUserManagementService {
|
||||
*/
|
||||
Integer getUserSessionCount(Long userId);
|
||||
|
||||
/**
|
||||
* 获取锁定的用户列表
|
||||
*
|
||||
* @return list
|
||||
*/
|
||||
List<UserLockedVO> getLockedUserList();
|
||||
|
||||
/**
|
||||
* 解锁用户
|
||||
*
|
||||
* @param request request
|
||||
*/
|
||||
void unlockLockedUser(UserUnlockRequest request);
|
||||
|
||||
/**
|
||||
* 获取全部用户会话列表
|
||||
*
|
||||
* @return list
|
||||
*/
|
||||
List<UserSessionVO> getUsersSessionList();
|
||||
|
||||
/**
|
||||
* 获取用户会话列表
|
||||
*
|
||||
|
||||
@@ -114,4 +114,20 @@ public interface TagRelService {
|
||||
*/
|
||||
Integer deleteRelIdList(String type, List<Long> relIdList);
|
||||
|
||||
/**
|
||||
* 通过 tagId 删除
|
||||
*
|
||||
* @param tagId tagId
|
||||
* @return effect
|
||||
*/
|
||||
Integer deleteTagId(Long tagId);
|
||||
|
||||
/**
|
||||
* 通过 tagId 删除
|
||||
*
|
||||
* @param tagIdList tagIdList
|
||||
* @return effect
|
||||
*/
|
||||
Integer deleteTagIdList(List<Long> tagIdList);
|
||||
|
||||
}
|
||||
|
||||
@@ -22,13 +22,16 @@
|
||||
*/
|
||||
package org.dromara.visor.module.infra.service;
|
||||
|
||||
import cn.orionsec.kit.lang.define.wrapper.DataGrid;
|
||||
import org.dromara.visor.module.infra.entity.request.tag.TagCreateRequest;
|
||||
import org.dromara.visor.module.infra.entity.request.tag.TagQueryRequest;
|
||||
import org.dromara.visor.module.infra.entity.request.tag.TagUpdateRequest;
|
||||
import org.dromara.visor.module.infra.entity.vo.TagVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 标签枚举 服务类
|
||||
* 数据标签 服务类
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
@@ -37,7 +40,7 @@ import java.util.List;
|
||||
public interface TagService {
|
||||
|
||||
/**
|
||||
* 创建标签枚举
|
||||
* 创建数据标签
|
||||
*
|
||||
* @param request request
|
||||
* @return id
|
||||
@@ -45,7 +48,23 @@ public interface TagService {
|
||||
Long createTag(TagCreateRequest request);
|
||||
|
||||
/**
|
||||
* 查询标签枚举
|
||||
* 更新数据标签
|
||||
*
|
||||
* @param request request
|
||||
* @return effect
|
||||
*/
|
||||
Integer updateTag(TagUpdateRequest request);
|
||||
|
||||
/**
|
||||
* 查询数据标签
|
||||
*
|
||||
* @param request request
|
||||
* @return dataGrid
|
||||
*/
|
||||
DataGrid<TagVO> getTagPage(TagQueryRequest request);
|
||||
|
||||
/**
|
||||
* 查询数据标签
|
||||
*
|
||||
* @param type type
|
||||
* @return rows
|
||||
@@ -53,7 +72,7 @@ public interface TagService {
|
||||
List<TagVO> getTagList(String type);
|
||||
|
||||
/**
|
||||
* 通过 id 删除标签枚举
|
||||
* 通过 id 删除数据标签
|
||||
*
|
||||
* @param id id
|
||||
* @return effect
|
||||
@@ -61,7 +80,7 @@ public interface TagService {
|
||||
Integer deleteTagById(Long id);
|
||||
|
||||
/**
|
||||
* 通过 id 删除标签枚举
|
||||
* 通过 id 删除数据标签
|
||||
*
|
||||
* @param idList idList
|
||||
* @return effect
|
||||
@@ -70,7 +89,9 @@ public interface TagService {
|
||||
|
||||
/**
|
||||
* 清理未使用的 tag
|
||||
*
|
||||
* @param days days
|
||||
*/
|
||||
void clearUnusedTag();
|
||||
void clearUnusedTag(Integer days);
|
||||
|
||||
}
|
||||
|
||||
@@ -22,26 +22,24 @@
|
||||
*/
|
||||
package org.dromara.visor.module.infra.service.impl;
|
||||
|
||||
import cn.orionsec.kit.lang.annotation.Keep;
|
||||
import cn.orionsec.kit.lang.define.wrapper.Pair;
|
||||
import cn.orionsec.kit.lang.utils.Booleans;
|
||||
import cn.orionsec.kit.lang.utils.Exceptions;
|
||||
import cn.orionsec.kit.lang.utils.Strings;
|
||||
import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||
import cn.orionsec.kit.lang.utils.crypto.Signatures;
|
||||
import cn.orionsec.kit.lang.utils.time.Dates;
|
||||
import cn.orionsec.kit.web.servlet.web.Servlets;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.dromara.visor.common.config.ConfigStore;
|
||||
import org.dromara.visor.common.constant.ConfigKeys;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.common.constant.ErrorMessage;
|
||||
import org.dromara.visor.common.constant.ExtraFieldConst;
|
||||
import org.dromara.visor.common.entity.RequestIdentity;
|
||||
import org.dromara.visor.common.entity.RequestIdentityModel;
|
||||
import org.dromara.visor.common.security.LoginUser;
|
||||
import org.dromara.visor.common.security.UserRole;
|
||||
import org.dromara.visor.common.utils.AesEncryptUtils;
|
||||
import org.dromara.visor.common.utils.Assert;
|
||||
import org.dromara.visor.common.utils.IpUtils;
|
||||
import org.dromara.visor.common.utils.Requests;
|
||||
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisStrings;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisUtils;
|
||||
@@ -54,8 +52,8 @@ import org.dromara.visor.module.infra.dao.SystemUserRoleDAO;
|
||||
import org.dromara.visor.module.infra.define.cache.UserCacheKeyDefine;
|
||||
import org.dromara.visor.module.infra.define.message.SystemUserMessageDefine;
|
||||
import org.dromara.visor.module.infra.entity.domain.SystemUserDO;
|
||||
import org.dromara.visor.module.infra.entity.dto.LoginFailedDTO;
|
||||
import org.dromara.visor.module.infra.entity.dto.LoginTokenDTO;
|
||||
import org.dromara.visor.module.infra.entity.dto.LoginTokenIdentityDTO;
|
||||
import org.dromara.visor.module.infra.entity.dto.message.SystemMessageDTO;
|
||||
import org.dromara.visor.module.infra.entity.request.user.UserLoginRequest;
|
||||
import org.dromara.visor.module.infra.entity.vo.UserLoginVO;
|
||||
@@ -63,7 +61,6 @@ import org.dromara.visor.module.infra.enums.LoginTokenStatusEnum;
|
||||
import org.dromara.visor.module.infra.enums.UserStatusEnum;
|
||||
import org.dromara.visor.module.infra.service.AuthenticationService;
|
||||
import org.dromara.visor.module.infra.service.UserPermissionService;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
@@ -98,10 +95,6 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
@Resource
|
||||
private SystemMessageApi systemMessageApi;
|
||||
|
||||
@Keep
|
||||
@Resource
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
@Resource
|
||||
private ConfigStore configStore;
|
||||
|
||||
@@ -110,25 +103,29 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
// 监听并且设置缓存过期时间
|
||||
configStore.int32(ConfigKeys.LOGIN_LOGIN_SESSION_TIME).onChange((v, b) -> this.setCacheExpireTime());
|
||||
configStore.int32(ConfigKeys.LOGIN_REFRESH_INTERVAL).onChange((v, b) -> this.setCacheExpireTime());
|
||||
configStore.int32(ConfigKeys.LOGIN_LOGIN_FAILED_LOCK_TIME).onChange((v, b) -> this.setCacheExpireTime());
|
||||
this.setCacheExpireTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserLoginVO login(UserLoginRequest request, HttpServletRequest servletRequest) {
|
||||
// 获取登录信息
|
||||
String remoteAddr = IpUtils.getRemoteAddr(servletRequest);
|
||||
String location = IpUtils.getLocation(remoteAddr);
|
||||
String userAgent = Servlets.getUserAgent(servletRequest);
|
||||
public UserLoginVO login(UserLoginRequest request) {
|
||||
// 获取登录痕迹
|
||||
String username = request.getUsername();
|
||||
RequestIdentityModel identity = Requests.getIdentity();
|
||||
// 设置日志上下文的用户 否则登录失败不会记录日志
|
||||
OperatorLogs.setUser(SystemUserConvert.MAPPER.toLoginUser(request));
|
||||
// 登录前检查
|
||||
SystemUserDO user = this.preCheckLogin(request.getUsername(), request.getPassword());
|
||||
SystemUserDO user = this.preCheckLogin(username, request.getPassword());
|
||||
// 重新设置日志上下文
|
||||
OperatorLogs.setUser(SystemUserConvert.MAPPER.toLoginUser(user));
|
||||
// 用户密码校验
|
||||
boolean passRight = this.checkUserPassword(user, request.getPassword(), true);
|
||||
// 发送站内信
|
||||
this.sendLoginFailedErrorMessage(passRight, user, remoteAddr, location);
|
||||
boolean passRight = this.checkUserPassword(user, request.getPassword());
|
||||
if (!passRight) {
|
||||
// 增加登录失败次数
|
||||
this.addLoginFailedCount(username, identity);
|
||||
// 登录失败发送站内信
|
||||
this.sendLoginFailedErrorMessage(user, identity);
|
||||
}
|
||||
Assert.isTrue(passRight, ErrorMessage.USERNAME_PASSWORD_ERROR);
|
||||
// 用户状态校验
|
||||
this.checkUserStatus(user);
|
||||
@@ -139,14 +136,13 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
this.deleteUserCache(user);
|
||||
// 重设用户缓存
|
||||
this.setUserCache(user);
|
||||
long current = System.currentTimeMillis();
|
||||
// 不允许多端登录
|
||||
if (Booleans.isFalse(appLoginConfig.getAllowMultiDevice())) {
|
||||
// 无效化其他缓存
|
||||
this.invalidOtherDeviceToken(id, current, remoteAddr, location, userAgent);
|
||||
this.invalidOtherDeviceToken(id, identity);
|
||||
}
|
||||
// 生成 loginToken
|
||||
String token = this.generatorLoginToken(user, current, remoteAddr, location, userAgent);
|
||||
String token = this.generatorLoginToken(user, identity);
|
||||
return UserLoginVO.builder()
|
||||
.token(token)
|
||||
.build();
|
||||
@@ -169,16 +165,16 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
// 删除 loginToken & refreshToken
|
||||
String loginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(id, current);
|
||||
String refreshKey = UserCacheKeyDefine.LOGIN_REFRESH.format(id, current);
|
||||
redisTemplate.delete(Lists.of(loginKey, refreshKey));
|
||||
RedisStrings.delete(loginKey, refreshKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginUser getLoginUser(Long id) {
|
||||
// 查询缓存用户信息
|
||||
String userInfoKey = UserCacheKeyDefine.USER_INFO.format(id);
|
||||
String userInfoCache = redisTemplate.opsForValue().get(userInfoKey);
|
||||
// 缓存存在
|
||||
if (userInfoCache != null) {
|
||||
return JSON.parseObject(userInfoCache, LoginUser.class);
|
||||
LoginUser loginUser = RedisStrings.getJson(userInfoKey, UserCacheKeyDefine.USER_INFO);
|
||||
if (loginUser != null) {
|
||||
return loginUser;
|
||||
}
|
||||
// 查询用户信息
|
||||
SystemUserDO user = systemUserDAO.selectById(id);
|
||||
@@ -198,22 +194,21 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
}
|
||||
// 获取登录 key value
|
||||
String loginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(pair.getKey(), pair.getValue());
|
||||
String loginCache = redisTemplate.opsForValue().get(loginKey);
|
||||
LoginTokenDTO loginCache = RedisStrings.getJson(loginKey, UserCacheKeyDefine.LOGIN_TOKEN);
|
||||
if (loginCache != null) {
|
||||
return JSON.parseObject(loginCache, LoginTokenDTO.class);
|
||||
return loginCache;
|
||||
}
|
||||
// loginToken 不存在 需要查询 refreshToken
|
||||
if (Booleans.isFalse(appLoginConfig.getAllowRefresh())) {
|
||||
return null;
|
||||
}
|
||||
String refreshKey = UserCacheKeyDefine.LOGIN_REFRESH.format(pair.getKey(), pair.getValue());
|
||||
String refreshCache = redisTemplate.opsForValue().get(refreshKey);
|
||||
// 未查询到刷新key直接返回
|
||||
if (refreshCache == null) {
|
||||
LoginTokenDTO refresh = RedisStrings.getJson(refreshKey, UserCacheKeyDefine.LOGIN_REFRESH);
|
||||
// 未查询到 refreshToken 直接返回
|
||||
if (refresh == null) {
|
||||
return null;
|
||||
}
|
||||
// 执行续签操作
|
||||
LoginTokenDTO refresh = JSON.parseObject(refreshCache, LoginTokenDTO.class);
|
||||
int refreshCount = refresh.getRefreshCount() + 1;
|
||||
refresh.setRefreshCount(refreshCount);
|
||||
// 设置登录缓存
|
||||
@@ -223,7 +218,7 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
RedisStrings.setJson(refreshKey, UserCacheKeyDefine.LOGIN_REFRESH, refresh);
|
||||
} else {
|
||||
// 大于等于续签最大次数 则删除
|
||||
redisTemplate.delete(refreshKey);
|
||||
RedisStrings.delete(refreshKey);
|
||||
}
|
||||
return refresh;
|
||||
}
|
||||
@@ -236,11 +231,14 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
}
|
||||
// 检查登录失败次数锁定
|
||||
if (Booleans.isTrue(appLoginConfig.getLoginFailedLock())) {
|
||||
String failedCountKey = UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(username);
|
||||
String failedCount = redisTemplate.opsForValue().get(failedCountKey);
|
||||
if (failedCount != null
|
||||
&& Integer.parseInt(failedCount) >= appLoginConfig.getLoginFailedLockThreshold()) {
|
||||
throw Exceptions.argument(ErrorMessage.MAX_LOGIN_FAILED);
|
||||
String loginFailedKey = UserCacheKeyDefine.LOGIN_FAILED.format(username);
|
||||
LoginFailedDTO loginFailed = RedisStrings.getJson(loginFailedKey, UserCacheKeyDefine.LOGIN_FAILED);
|
||||
Integer failedCount = Optional.ofNullable(loginFailed)
|
||||
.map(LoginFailedDTO::getFailedCount)
|
||||
.orElse(null);
|
||||
// 检查是否超过失败次数
|
||||
if (failedCount != null && failedCount >= appLoginConfig.getLoginFailedLockThreshold()) {
|
||||
Assert.lt(failedCount, appLoginConfig.getLoginFailedLockThreshold(), ErrorMessage.MAX_LOGIN_FAILED);
|
||||
}
|
||||
}
|
||||
// 获取登录用户
|
||||
@@ -254,16 +252,32 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkUserPassword(SystemUserDO user, String password, boolean addFailedCount) {
|
||||
// 检查密码
|
||||
boolean passRight = user.getPassword().equals(Signatures.md5(password));
|
||||
if (!passRight && addFailedCount) {
|
||||
// 刷新登录失败缓存
|
||||
String failedCountKey = UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(user.getUsername());
|
||||
redisTemplate.opsForValue().increment(failedCountKey);
|
||||
RedisUtils.setExpire(failedCountKey, appLoginConfig.getLoginFailedLockTime(), TimeUnit.MINUTES);
|
||||
public boolean checkUserPassword(SystemUserDO user, String password) {
|
||||
return user.getPassword().equals(Signatures.md5(password));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLoginFailedCount(String username, RequestIdentityModel identity) {
|
||||
// 过期时间
|
||||
long expireTime = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(UserCacheKeyDefine.LOGIN_FAILED.getTimeout());
|
||||
// 刷新登录失败缓存
|
||||
String loginFailedKey = UserCacheKeyDefine.LOGIN_FAILED.format(username);
|
||||
LoginFailedDTO loginFailed = RedisStrings.getJson(loginFailedKey, UserCacheKeyDefine.LOGIN_FAILED);
|
||||
if (loginFailed == null) {
|
||||
// 首次登录失败
|
||||
loginFailed = LoginFailedDTO.builder()
|
||||
.username(username)
|
||||
.failedCount(1)
|
||||
.expireTime(expireTime)
|
||||
.origin(identity)
|
||||
.build();
|
||||
} else {
|
||||
// 非首次登录失败
|
||||
loginFailed.setExpireTime(expireTime);
|
||||
loginFailed.setFailedCount(loginFailed.getFailedCount() + 1);
|
||||
}
|
||||
return passRight;
|
||||
// 重新设置缓存
|
||||
RedisStrings.setJson(loginFailedKey, UserCacheKeyDefine.LOGIN_FAILED, loginFailed);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -275,33 +289,30 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
/**
|
||||
* 发送登录失败错误消息
|
||||
*
|
||||
* @param passRight passRight
|
||||
* @param user user
|
||||
* @param remoteAddr remoteAddr
|
||||
* @param location location
|
||||
* @param user user
|
||||
* @param identity identity
|
||||
*/
|
||||
private void sendLoginFailedErrorMessage(boolean passRight, SystemUserDO user,
|
||||
String remoteAddr, String location) {
|
||||
if (passRight) {
|
||||
return;
|
||||
}
|
||||
private void sendLoginFailedErrorMessage(SystemUserDO user, RequestIdentity identity) {
|
||||
// 检查是否开启登录失败发信
|
||||
if (!Booleans.isTrue(appLoginConfig.getLoginFailedSend())) {
|
||||
return;
|
||||
}
|
||||
String failedCountKey = UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(user.getUsername());
|
||||
String failedCountStr = redisTemplate.opsForValue().get(failedCountKey);
|
||||
if (failedCountStr == null || !Strings.isInteger(failedCountStr)) {
|
||||
String loginFailedKey = UserCacheKeyDefine.LOGIN_FAILED.format(user.getUsername());
|
||||
LoginFailedDTO loginFailed = RedisStrings.getJson(loginFailedKey, UserCacheKeyDefine.LOGIN_FAILED);
|
||||
Integer failedCount = Optional.ofNullable(loginFailed)
|
||||
.map(LoginFailedDTO::getFailedCount)
|
||||
.orElse(null);
|
||||
if (failedCount == null) {
|
||||
return;
|
||||
}
|
||||
// 直接用相等 因为只触发一次
|
||||
if (!Integer.valueOf(failedCountStr).equals(appLoginConfig.getLoginFailedSendThreshold())) {
|
||||
if (!failedCount.equals(appLoginConfig.getLoginFailedSendThreshold())) {
|
||||
return;
|
||||
}
|
||||
// 发送站内信
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put(ExtraFieldConst.ADDRESS, remoteAddr);
|
||||
params.put(ExtraFieldConst.LOCATION, location);
|
||||
params.put(ExtraFieldConst.ADDRESS, identity.getAddress());
|
||||
params.put(ExtraFieldConst.LOCATION, identity.getLocation());
|
||||
params.put(ExtraFieldConst.TIME, Dates.current());
|
||||
SystemMessageDTO message = SystemMessageDTO.builder()
|
||||
.receiverId(user.getId())
|
||||
@@ -334,9 +345,9 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
// 用户信息缓存
|
||||
String userInfoKey = UserCacheKeyDefine.USER_INFO.format(user.getId());
|
||||
// 登录失败次数缓存
|
||||
String loginFailedCountKey = UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(user.getUsername());
|
||||
String loginFailedCountKey = UserCacheKeyDefine.LOGIN_FAILED.format(user.getUsername());
|
||||
// 删除缓存
|
||||
redisTemplate.delete(Lists.of(userInfoKey, loginFailedCountKey));
|
||||
RedisStrings.delete(userInfoKey, loginFailedCountKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -385,21 +396,16 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
/**
|
||||
* 无效化其他登录信息
|
||||
*
|
||||
* @param id id
|
||||
* @param loginTime loginTime
|
||||
* @param remoteAddr remoteAddr
|
||||
* @param location location
|
||||
* @param userAgent userAgent
|
||||
* @param id id
|
||||
* @param identity identity
|
||||
*/
|
||||
@SuppressWarnings("ALL")
|
||||
private void invalidOtherDeviceToken(Long id, long loginTime,
|
||||
String remoteAddr, String location, String userAgent) {
|
||||
private void invalidOtherDeviceToken(Long id, RequestIdentityModel identity) {
|
||||
// 获取登录信息
|
||||
Set<String> loginKeyList = RedisUtils.scanKeys(UserCacheKeyDefine.LOGIN_TOKEN.format(id, "*"));
|
||||
Set<String> loginKeyList = RedisStrings.scanKeys(UserCacheKeyDefine.LOGIN_TOKEN.format(id, "*"));
|
||||
if (!loginKeyList.isEmpty()) {
|
||||
// 获取有效登录信息
|
||||
List<LoginTokenDTO> loginTokenInfoList = redisTemplate.opsForValue()
|
||||
.multiGet(loginKeyList)
|
||||
List<LoginTokenDTO> loginTokenInfoList = RedisStrings.getList(loginKeyList)
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(s -> JSON.parseObject(s, LoginTokenDTO.class))
|
||||
@@ -407,9 +413,9 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
.collect(Collectors.toList());
|
||||
// 修改登录信息
|
||||
for (LoginTokenDTO loginTokenInfo : loginTokenInfoList) {
|
||||
String deviceLoginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(id, loginTokenInfo.getOrigin().getLoginTime());
|
||||
String deviceLoginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(id, loginTokenInfo.getOrigin().getTimestamp());
|
||||
loginTokenInfo.setStatus(LoginTokenStatusEnum.OTHER_DEVICE.getStatus());
|
||||
loginTokenInfo.setOverride(new LoginTokenIdentityDTO(loginTime, remoteAddr, location, userAgent));
|
||||
loginTokenInfo.setOverride(identity);
|
||||
RedisStrings.setJson(deviceLoginKey, UserCacheKeyDefine.LOGIN_TOKEN, loginTokenInfo);
|
||||
}
|
||||
}
|
||||
@@ -422,32 +428,30 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
/**
|
||||
* 生成 loginToken
|
||||
*
|
||||
* @param user user
|
||||
* @param loginTime loginTime
|
||||
* @param remoteAddr remoteAddr
|
||||
* @param location location
|
||||
* @param userAgent userAgent
|
||||
* @param user user
|
||||
* @param identity identity
|
||||
* @return loginToken
|
||||
*/
|
||||
private String generatorLoginToken(SystemUserDO user, long loginTime,
|
||||
String remoteAddr, String location, String userAgent) {
|
||||
private String generatorLoginToken(SystemUserDO user, RequestIdentityModel identity) {
|
||||
Long id = user.getId();
|
||||
Long timestamp = identity.getTimestamp();
|
||||
// 生成 loginToken
|
||||
String loginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(id, loginTime);
|
||||
String loginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(id, timestamp);
|
||||
LoginTokenDTO loginValue = LoginTokenDTO.builder()
|
||||
.id(id)
|
||||
.username(user.getUsername())
|
||||
.status(LoginTokenStatusEnum.OK.getStatus())
|
||||
.refreshCount(0)
|
||||
.origin(new LoginTokenIdentityDTO(loginTime, remoteAddr, location, userAgent))
|
||||
.origin(new RequestIdentityModel(timestamp, identity.getAddress(), identity.getLocation(), identity.getUserAgent()))
|
||||
.build();
|
||||
RedisStrings.setJson(loginKey, UserCacheKeyDefine.LOGIN_TOKEN, loginValue);
|
||||
// 生成 refreshToken
|
||||
if (Booleans.isTrue(appLoginConfig.getAllowRefresh())) {
|
||||
String refreshKey = UserCacheKeyDefine.LOGIN_REFRESH.format(id, loginTime);
|
||||
String refreshKey = UserCacheKeyDefine.LOGIN_REFRESH.format(id, timestamp);
|
||||
RedisStrings.setJson(refreshKey, UserCacheKeyDefine.LOGIN_REFRESH, loginValue);
|
||||
}
|
||||
// 返回token
|
||||
return AesEncryptUtils.encryptBase62(id + ":" + loginTime);
|
||||
return AesEncryptUtils.encryptBase62(id + ":" + timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -459,6 +463,10 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
UserCacheKeyDefine.LOGIN_TOKEN.setTimeout(loginSessionTime);
|
||||
UserCacheKeyDefine.LOGIN_REFRESH.setTimeout(loginSessionTime + appLoginConfig.getRefreshInterval());
|
||||
}
|
||||
Integer loginFailedLockTime = appLoginConfig.getLoginFailedLockTime();
|
||||
if (loginFailedLockTime != null) {
|
||||
UserCacheKeyDefine.LOGIN_FAILED.setTimeout(loginFailedLockTime);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.framework.mybatis.core.query.ThenLambdaWrapper;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisMaps;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisUtils;
|
||||
import org.dromara.visor.framework.redis.core.utils.barrier.CacheBarriers;
|
||||
import org.dromara.visor.module.infra.dao.DataExtraDAO;
|
||||
import org.dromara.visor.module.infra.define.cache.DataExtraCacheKeyDefine;
|
||||
@@ -92,7 +93,7 @@ public class DataExtraServiceImpl implements DataExtraService {
|
||||
insert.setValue(request.getValue());
|
||||
dataExtraDAO.insert(insert);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(DataExtraCacheKeyDefine.DATA_EXTRA.format(request.getUserId(), request.getType(), request.getItem()));
|
||||
RedisUtils.delete(DataExtraCacheKeyDefine.DATA_EXTRA.format(request.getUserId(), request.getType(), request.getItem()));
|
||||
return insert.getId();
|
||||
}
|
||||
|
||||
@@ -114,7 +115,7 @@ public class DataExtraServiceImpl implements DataExtraService {
|
||||
Set<String> keys = rows.stream()
|
||||
.map(s -> DataExtraCacheKeyDefine.DATA_EXTRA.format(s.getUserId(), s.getType(), s.getItem()))
|
||||
.collect(Collectors.toSet());
|
||||
RedisMaps.delete(keys);
|
||||
RedisUtils.delete(keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -133,7 +134,7 @@ public class DataExtraServiceImpl implements DataExtraService {
|
||||
// 更新
|
||||
int effect = dataExtraDAO.updateById(update);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(DataExtraCacheKeyDefine.DATA_EXTRA.format(data.getUserId(), data.getType(), data.getItem()));
|
||||
RedisUtils.delete(DataExtraCacheKeyDefine.DATA_EXTRA.format(data.getUserId(), data.getType(), data.getItem()));
|
||||
return effect;
|
||||
}
|
||||
|
||||
@@ -315,7 +316,7 @@ public class DataExtraServiceImpl implements DataExtraService {
|
||||
.map(s -> DataExtraCacheKeyDefine.DATA_EXTRA.format(s.getUserId(), s.getType(), s.getItem()))
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
RedisMaps.delete(keys);
|
||||
RedisUtils.delete(keys);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -343,7 +343,7 @@ public class DataGroupServiceImpl implements DataGroupService {
|
||||
.eq(DataGroupDO::getName, domain.getName());
|
||||
// 检查是否存在
|
||||
boolean present = dataGroupDAO.of(wrapper).present();
|
||||
Assert.isFalse(present, ErrorMessage.DATA_PRESENT);
|
||||
Assert.isFalse(present, ErrorMessage.NAME_PRESENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -346,7 +346,7 @@ public class DataPermissionServiceImpl implements DataPermissionService {
|
||||
.map(s -> DataPermissionCacheKeyDefine.DATA_PERMISSION_USER.format(value, s))
|
||||
.forEach(keys::add);
|
||||
}
|
||||
RedisLists.delete(keys);
|
||||
RedisUtils.delete(keys);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ public class DictKeyServiceImpl implements DictKeyService {
|
||||
.eq(DictKeyDO::getKeyName, domain.getKeyName());
|
||||
// 检查是否存在
|
||||
boolean present = dictKeyDAO.of(wrapper).present();
|
||||
Assert.isFalse(present, ErrorMessage.DATA_PRESENT);
|
||||
Assert.isFalse(present, ErrorMessage.NAME_PRESENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.utils.Assert;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisLists;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisUtils;
|
||||
import org.dromara.visor.framework.redis.core.utils.barrier.CacheBarriers;
|
||||
import org.dromara.visor.framework.security.core.utils.SecurityUtils;
|
||||
import org.dromara.visor.module.infra.convert.FavoriteConvert;
|
||||
@@ -79,7 +80,7 @@ public class FavoriteServiceImpl implements FavoriteService {
|
||||
// 插入
|
||||
favoriteDAO.insert(record);
|
||||
// 删除缓存
|
||||
RedisLists.delete(FavoriteCacheKeyDefine.FAVORITE.format(type, userId));
|
||||
RedisUtils.delete(FavoriteCacheKeyDefine.FAVORITE.format(type, userId));
|
||||
return record.getId();
|
||||
}
|
||||
|
||||
@@ -91,7 +92,7 @@ public class FavoriteServiceImpl implements FavoriteService {
|
||||
// 删除库
|
||||
int effect = favoriteDAO.deleteFavorite(type, userId, relId);
|
||||
// 删除缓存
|
||||
RedisLists.delete(FavoriteCacheKeyDefine.FAVORITE.format(type, userId));
|
||||
RedisUtils.delete(FavoriteCacheKeyDefine.FAVORITE.format(type, userId));
|
||||
return effect;
|
||||
}
|
||||
|
||||
|
||||
@@ -226,7 +226,7 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService {
|
||||
.eq(NotifyTemplateDO::getBizType, domain.getBizType());
|
||||
// 检查是否存在
|
||||
boolean present = notifyTemplateDAO.of(wrapper).present();
|
||||
Assert.isFalse(present, ErrorMessage.DATA_PRESENT);
|
||||
Assert.isFalse(present, ErrorMessage.NAME_PRESENT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import cn.orionsec.kit.lang.utils.collect.Maps;
|
||||
import cn.orionsec.kit.lang.utils.crypto.Keys;
|
||||
import cn.orionsec.kit.lang.utils.crypto.RSA;
|
||||
import cn.orionsec.kit.spring.SpringHolder;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.AppConst;
|
||||
import org.dromara.visor.common.constant.ConfigKeys;
|
||||
@@ -124,28 +123,12 @@ public class SystemSettingServiceImpl implements SystemSettingService {
|
||||
|
||||
@Override
|
||||
public void updateSystemSetting(SystemSettingUpdateRequest request) {
|
||||
String type = request.getType();
|
||||
String configKey = request.getConfigKey();
|
||||
String value = request.getValue();
|
||||
// 删除
|
||||
systemSettingDAO.delete(Conditions.eq(SystemSettingDO::getConfigKey, configKey));
|
||||
// 插入
|
||||
SystemSettingDO insert = SystemSettingDO.builder()
|
||||
.type(type)
|
||||
.configKey(configKey)
|
||||
.value(Strings.def(value))
|
||||
SystemSettingUpdateBatchRequest params = SystemSettingUpdateBatchRequest.builder()
|
||||
.type(request.getType())
|
||||
.settings(Maps.of(request.getConfigKey(), request.getValue()))
|
||||
.build();
|
||||
systemSettingDAO.insert(insert);
|
||||
// 更新
|
||||
SystemSettingDO update = new SystemSettingDO();
|
||||
update.setValue(value);
|
||||
LambdaQueryWrapper<SystemSettingDO> wrapper = systemSettingDAO.lambda()
|
||||
.eq(SystemSettingDO::getConfigKey, configKey);
|
||||
systemSettingDAO.update(update, wrapper);
|
||||
// 删除缓存
|
||||
RedisUtils.delete(SystemSettingKeyDefine.SETTING);
|
||||
// 触发修改事件
|
||||
SpringHolder.publishEvent(ConfigUpdateEvent.of(configKey, value));
|
||||
this.updateSystemSettingBatch(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,30 +22,32 @@
|
||||
*/
|
||||
package org.dromara.visor.module.infra.service.impl;
|
||||
|
||||
import cn.orionsec.kit.lang.utils.Objects1;
|
||||
import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.ErrorMessage;
|
||||
import org.dromara.visor.common.entity.RequestIdentityModel;
|
||||
import org.dromara.visor.common.utils.Assert;
|
||||
import org.dromara.visor.common.utils.Requests;
|
||||
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisStrings;
|
||||
import org.dromara.visor.framework.security.core.utils.SecurityUtils;
|
||||
import org.dromara.visor.module.common.config.AppLoginConfig;
|
||||
import org.dromara.visor.module.infra.dao.SystemUserDAO;
|
||||
import org.dromara.visor.module.infra.define.cache.UserCacheKeyDefine;
|
||||
import org.dromara.visor.module.infra.entity.domain.SystemUserDO;
|
||||
import org.dromara.visor.module.infra.entity.dto.LoginFailedDTO;
|
||||
import org.dromara.visor.module.infra.entity.dto.LoginTokenDTO;
|
||||
import org.dromara.visor.module.infra.entity.dto.LoginTokenIdentityDTO;
|
||||
import org.dromara.visor.module.infra.entity.request.user.UserSessionOfflineRequest;
|
||||
import org.dromara.visor.module.infra.entity.request.user.UserUnlockRequest;
|
||||
import org.dromara.visor.module.infra.entity.vo.UserLockedVO;
|
||||
import org.dromara.visor.module.infra.entity.vo.UserSessionVO;
|
||||
import org.dromara.visor.module.infra.enums.LoginTokenStatusEnum;
|
||||
import org.dromara.visor.module.infra.service.SystemUserManagementService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -59,6 +61,9 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class SystemUserManagementServiceImpl implements SystemUserManagementService {
|
||||
|
||||
@Resource
|
||||
private AppLoginConfig appLoginConfig;
|
||||
|
||||
@Resource
|
||||
private SystemUserDAO systemUserDAO;
|
||||
|
||||
@@ -69,6 +74,53 @@ public class SystemUserManagementServiceImpl implements SystemUserManagementServ
|
||||
return Lists.size(keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserLockedVO> getLockedUserList() {
|
||||
// 扫描缓存
|
||||
Set<String> keys = RedisStrings.scanKeys(UserCacheKeyDefine.LOGIN_FAILED.format("*"));
|
||||
if (Lists.isEmpty(keys)) {
|
||||
return Lists.empty();
|
||||
}
|
||||
// 查询缓存
|
||||
List<LoginFailedDTO> loginFailedList = RedisStrings.getJsonList(keys, UserCacheKeyDefine.LOGIN_FAILED);
|
||||
if (Lists.isEmpty(loginFailedList)) {
|
||||
return Lists.empty();
|
||||
}
|
||||
// 返回
|
||||
return loginFailedList.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(s -> s.getFailedCount() >= appLoginConfig.getLoginFailedLockThreshold())
|
||||
.map(s -> {
|
||||
RequestIdentityModel origin = s.getOrigin();
|
||||
return UserLockedVO.builder()
|
||||
.username(s.getUsername())
|
||||
.expireTime(s.getExpireTime())
|
||||
.address(origin.getAddress())
|
||||
.location(origin.getLocation())
|
||||
.userAgent(origin.getUserAgent())
|
||||
.loginTime(new Date(origin.getTimestamp()))
|
||||
.build();
|
||||
})
|
||||
.sorted(Comparator.comparing(UserLockedVO::getLoginTime).reversed())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockLockedUser(UserUnlockRequest request) {
|
||||
RedisStrings.delete(UserCacheKeyDefine.LOGIN_FAILED.format(request.getUsername()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserSessionVO> getUsersSessionList() {
|
||||
// 扫描缓存
|
||||
Set<String> keys = RedisStrings.scanKeys(UserCacheKeyDefine.LOGIN_TOKEN.format("*", "*"));
|
||||
if (Lists.isEmpty(keys)) {
|
||||
return Lists.empty();
|
||||
}
|
||||
// 获取用户会话列表
|
||||
return this.getUserSessionList(keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserSessionVO> getUserSessionList(Long userId) {
|
||||
// 扫描缓存
|
||||
@@ -76,23 +128,39 @@ public class SystemUserManagementServiceImpl implements SystemUserManagementServ
|
||||
if (Lists.isEmpty(keys)) {
|
||||
return Lists.empty();
|
||||
}
|
||||
// 获取用户会话列表
|
||||
return this.getUserSessionList(keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户会话列表
|
||||
*
|
||||
* @param keys keys
|
||||
* @return rows
|
||||
*/
|
||||
private List<UserSessionVO> getUserSessionList(Set<String> keys) {
|
||||
Long loginUserId = SecurityUtils.getLoginUserId();
|
||||
// 查询缓存
|
||||
List<LoginTokenDTO> tokens = RedisStrings.getJsonList(keys, UserCacheKeyDefine.LOGIN_TOKEN);
|
||||
if (Lists.isEmpty(tokens)) {
|
||||
return Lists.empty();
|
||||
}
|
||||
final boolean isCurrentUser = userId.equals(SecurityUtils.getLoginUserId());
|
||||
// 返回
|
||||
return tokens.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(s -> LoginTokenStatusEnum.OK.getStatus().equals(s.getStatus()))
|
||||
.map(LoginTokenDTO::getOrigin)
|
||||
.map(s -> UserSessionVO.builder()
|
||||
.current(isCurrentUser && s.getLoginTime().equals(SecurityUtils.getLoginTimestamp()))
|
||||
.address(s.getAddress())
|
||||
.location(s.getLocation())
|
||||
.userAgent(s.getUserAgent())
|
||||
.loginTime(new Date(s.getLoginTime()))
|
||||
.build())
|
||||
.map(s -> {
|
||||
RequestIdentityModel origin = s.getOrigin();
|
||||
return UserSessionVO.builder()
|
||||
.id(s.getId())
|
||||
.username(s.getUsername())
|
||||
.current(Objects1.eq(loginUserId, s.getId()) && origin.getTimestamp().equals(SecurityUtils.getLoginTimestamp()))
|
||||
.address(origin.getAddress())
|
||||
.location(origin.getLocation())
|
||||
.userAgent(origin.getUserAgent())
|
||||
.loginTime(new Date(origin.getTimestamp()))
|
||||
.build();
|
||||
})
|
||||
.sorted(Comparator.comparing(UserSessionVO::getCurrent).reversed()
|
||||
.thenComparing(Comparator.comparing(UserSessionVO::getLoginTime).reversed()))
|
||||
.collect(Collectors.toList());
|
||||
@@ -115,11 +183,8 @@ public class SystemUserManagementServiceImpl implements SystemUserManagementServ
|
||||
LoginTokenDTO tokenInfo = RedisStrings.getJson(tokenKey, UserCacheKeyDefine.LOGIN_TOKEN);
|
||||
if (tokenInfo != null) {
|
||||
tokenInfo.setStatus(LoginTokenStatusEnum.SESSION_OFFLINE.getStatus());
|
||||
LoginTokenIdentityDTO override = new LoginTokenIdentityDTO();
|
||||
override.setLoginTime(System.currentTimeMillis());
|
||||
// 设置请求信息
|
||||
Requests.fillIdentity(override);
|
||||
tokenInfo.setOverride(override);
|
||||
// 设置留痕信息
|
||||
tokenInfo.setOverride(Requests.getIdentity());
|
||||
// 更新 token
|
||||
RedisStrings.setJson(tokenKey, UserCacheKeyDefine.LOGIN_TOKEN, tokenInfo);
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ public class SystemUserServiceImpl implements SystemUserService {
|
||||
// 用户列表
|
||||
UserCacheKeyDefine.USER_LIST.getKey(),
|
||||
// 登录失败次数
|
||||
UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(request.getUsername())
|
||||
UserCacheKeyDefine.LOGIN_FAILED.format(request.getUsername())
|
||||
);
|
||||
return record.getId();
|
||||
}
|
||||
@@ -179,7 +179,7 @@ public class SystemUserServiceImpl implements SystemUserService {
|
||||
log.info("SystemUserService-updateUserStatus effect: {}, updateRecord: {}", effect, JSON.toJSONString(updateRecord));
|
||||
// 改为启用则删除登录失败次数缓存
|
||||
if (UserStatusEnum.ENABLED.equals(status)) {
|
||||
RedisUtils.delete(UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(record.getUsername()));
|
||||
RedisUtils.delete(UserCacheKeyDefine.LOGIN_FAILED.format(record.getUsername()));
|
||||
}
|
||||
// 更新用户缓存中的 status
|
||||
RedisStrings.<LoginUser>processSetJson(UserCacheKeyDefine.USER_INFO, s -> {
|
||||
@@ -320,7 +320,7 @@ public class SystemUserServiceImpl implements SystemUserService {
|
||||
int effect = systemUserDAO.updateById(update);
|
||||
log.info("SystemUserService-resetPassword record: {}, effect: {}", JSON.toJSONString(update), effect);
|
||||
// 删除登录失败次数缓存
|
||||
RedisUtils.delete(UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(record.getUsername()));
|
||||
RedisUtils.delete(UserCacheKeyDefine.LOGIN_FAILED.format(record.getUsername()));
|
||||
// 删除登录缓存
|
||||
RedisUtils.scanKeysDelete(UserCacheKeyDefine.LOGIN_TOKEN.format(id, "*"));
|
||||
// 删除续签信息
|
||||
@@ -375,7 +375,7 @@ public class SystemUserServiceImpl implements SystemUserService {
|
||||
// 用户信息缓存
|
||||
deleteKeys.add(UserCacheKeyDefine.USER_INFO.format(id));
|
||||
// 登录失败次数
|
||||
deleteKeys.add(UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(s.getUsername()));
|
||||
deleteKeys.add(UserCacheKeyDefine.LOGIN_FAILED.format(s.getUsername()));
|
||||
// 登录 token
|
||||
deleteKeys.addAll(RedisUtils.scanKeys(UserCacheKeyDefine.LOGIN_TOKEN.format(id, "*")));
|
||||
// 刷新 token
|
||||
|
||||
@@ -27,6 +27,7 @@ import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||
import cn.orionsec.kit.lang.utils.collect.Maps;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisStrings;
|
||||
import org.dromara.visor.module.infra.convert.TagRelConvert;
|
||||
import org.dromara.visor.module.infra.dao.TagDAO;
|
||||
@@ -204,16 +205,7 @@ public class TagRelServiceImpl implements TagRelService {
|
||||
|
||||
@Override
|
||||
public Integer deleteRelId(String type, Long relId) {
|
||||
// 删除数据库
|
||||
TagRelQueryRequest queryRequest = new TagRelQueryRequest();
|
||||
queryRequest.setTagType(type);
|
||||
queryRequest.setRelId(relId);
|
||||
LambdaQueryWrapper<TagRelDO> wrapper = this.buildQueryWrapper(queryRequest);
|
||||
int effect = tagRelDAO.delete(wrapper);
|
||||
// 删除缓存
|
||||
String cacheKey = TagCacheKeyDefine.TAG_REL.format(type, relId);
|
||||
redisTemplate.delete(cacheKey);
|
||||
return effect;
|
||||
return this.deleteRelIdList(type, Lists.singleton(relId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -232,6 +224,36 @@ public class TagRelServiceImpl implements TagRelService {
|
||||
return effect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer deleteTagId(Long tagId) {
|
||||
return this.deleteTagIdList(Lists.singleton(tagId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer deleteTagIdList(List<Long> tagIdList) {
|
||||
TagRelQueryRequest queryRequest = new TagRelQueryRequest();
|
||||
queryRequest.setTagIdList(tagIdList);
|
||||
LambdaQueryWrapper<TagRelDO> wrapper = this.buildQueryWrapper(queryRequest);
|
||||
// 查询数据库
|
||||
List<TagRelDO> tags = tagRelDAO.selectList(wrapper);
|
||||
if (tags.isEmpty()) {
|
||||
return Const.N_0;
|
||||
}
|
||||
// 删除数据库
|
||||
int effect = tagRelDAO.delete(wrapper);
|
||||
// 删除缓存
|
||||
String tagType = tags.get(0).getTagType();
|
||||
List<Long> relIdList = tags.stream()
|
||||
.map(TagRelDO::getRelId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
List<String> cacheKeyList = relIdList.stream()
|
||||
.map(relId -> TagCacheKeyDefine.TAG_REL.format(tagType, relId))
|
||||
.collect(Collectors.toList());
|
||||
redisTemplate.delete(cacheKeyList);
|
||||
return effect;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询 wrapper
|
||||
*
|
||||
@@ -242,6 +264,7 @@ public class TagRelServiceImpl implements TagRelService {
|
||||
return tagRelDAO.wrapper()
|
||||
.eq(TagRelDO::getId, request.getId())
|
||||
.eq(TagRelDO::getTagId, request.getTagId())
|
||||
.in(TagRelDO::getTagId, request.getTagIdList())
|
||||
.eq(TagRelDO::getTagName, request.getTagName())
|
||||
.eq(TagRelDO::getTagType, request.getTagType())
|
||||
.eq(TagRelDO::getRelId, request.getRelId())
|
||||
|
||||
@@ -22,29 +22,43 @@
|
||||
*/
|
||||
package org.dromara.visor.module.infra.service.impl;
|
||||
|
||||
import cn.orionsec.kit.lang.define.wrapper.DataGrid;
|
||||
import cn.orionsec.kit.lang.utils.Objects1;
|
||||
import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.common.constant.ErrorMessage;
|
||||
import org.dromara.visor.common.utils.Assert;
|
||||
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
||||
import org.dromara.visor.framework.mybatis.core.query.Conditions;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisLists;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisUtils;
|
||||
import org.dromara.visor.framework.redis.core.utils.barrier.CacheBarriers;
|
||||
import org.dromara.visor.module.infra.convert.TagConvert;
|
||||
import org.dromara.visor.module.infra.dao.TagDAO;
|
||||
import org.dromara.visor.module.infra.dao.TagRelDAO;
|
||||
import org.dromara.visor.module.infra.define.cache.TagCacheKeyDefine;
|
||||
import org.dromara.visor.module.infra.entity.domain.TagDO;
|
||||
import org.dromara.visor.module.infra.entity.dto.TagCacheDTO;
|
||||
import org.dromara.visor.module.infra.entity.po.TagRelCountPO;
|
||||
import org.dromara.visor.module.infra.entity.request.tag.TagCreateRequest;
|
||||
import org.dromara.visor.module.infra.entity.request.tag.TagQueryRequest;
|
||||
import org.dromara.visor.module.infra.entity.request.tag.TagUpdateRequest;
|
||||
import org.dromara.visor.module.infra.entity.vo.TagVO;
|
||||
import org.dromara.visor.module.infra.service.TagRelService;
|
||||
import org.dromara.visor.module.infra.service.TagService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 标签枚举 服务实现类
|
||||
* 数据标签 服务实现类
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
@@ -54,14 +68,15 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class TagServiceImpl implements TagService {
|
||||
|
||||
/**
|
||||
* 未使用的天数
|
||||
*/
|
||||
private static final Integer UN_USED_DAYS = 3;
|
||||
|
||||
@Resource
|
||||
private TagDAO tagDAO;
|
||||
|
||||
@Resource
|
||||
private TagRelDAO tagRelDAO;
|
||||
|
||||
@Resource
|
||||
private TagRelService tagRelService;
|
||||
|
||||
@Override
|
||||
public Long createTag(TagCreateRequest request) {
|
||||
// 转换
|
||||
@@ -86,6 +101,26 @@ public class TagServiceImpl implements TagService {
|
||||
return record.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Integer updateTag(TagUpdateRequest request) {
|
||||
Long id = request.getId();
|
||||
log.info("TagService-updateTag id: {}, request: {}", id, JSON.toJSONString(request));
|
||||
// 查询标签是否存在
|
||||
TagDO record = tagDAO.selectById(id);
|
||||
Assert.notNull(record, ErrorMessage.DATA_ABSENT);
|
||||
// 转换
|
||||
TagDO updateRecord = TagConvert.MAPPER.to(request);
|
||||
// 检查数据是否存在
|
||||
this.checkTagPresent(updateRecord);
|
||||
// 更新
|
||||
int effect = tagDAO.updateById(updateRecord);
|
||||
log.info("HostProxyService-updateHostProxyById effect: {}", effect);
|
||||
// 删除缓存
|
||||
RedisUtils.delete(TagCacheKeyDefine.TAG_NAME.format(record.getType()));
|
||||
return effect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TagVO> getTagList(String type) {
|
||||
// 查询缓存
|
||||
@@ -109,41 +144,72 @@ public class TagServiceImpl implements TagService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer deleteTagById(Long id) {
|
||||
TagDO tag = tagDAO.selectById(id);
|
||||
if (tag == null) {
|
||||
return Const.N_0;
|
||||
public DataGrid<TagVO> getTagPage(TagQueryRequest request) {
|
||||
// 查询标签
|
||||
DataGrid<TagVO> dataGrid = tagDAO.of()
|
||||
.createValidateWrapper()
|
||||
.eq(TagDO::getType, request.getType())
|
||||
.like(TagDO::getName, request.getName())
|
||||
.then()
|
||||
.page(request)
|
||||
.order(request, TagDO::getId)
|
||||
.dataGrid(TagConvert.MAPPER::to);
|
||||
// 查询数量
|
||||
if (!dataGrid.isEmpty()) {
|
||||
List<Long> tagIdList = dataGrid.stream()
|
||||
.map(TagVO::getId)
|
||||
.collect(Collectors.toList());
|
||||
// 查询数量
|
||||
Map<Long, Integer> tagRelCountMap = tagRelDAO.selectTagRelCount(tagIdList)
|
||||
.stream()
|
||||
.collect(Collectors.toMap(TagRelCountPO::getTagId,
|
||||
s -> Objects1.def(s.getCount(), Const.N_0)));
|
||||
// 设置数量
|
||||
for (TagVO tag : dataGrid) {
|
||||
Integer count = tagRelCountMap.getOrDefault(tag.getId(), Const.N_0);
|
||||
tag.setRelCount(count);
|
||||
}
|
||||
}
|
||||
// 删除数据库
|
||||
int effect = tagDAO.deleteById(id);
|
||||
log.info("TagService-deleteTagById id: {}, effect: {}", id, effect);
|
||||
// 删除缓存
|
||||
String cacheKey = TagCacheKeyDefine.TAG_NAME.format(tag.getType());
|
||||
RedisLists.removeJson(cacheKey, TagConvert.MAPPER.toCache(tag));
|
||||
return effect;
|
||||
return dataGrid;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Integer deleteTagById(Long id) {
|
||||
return this.deleteTagByIdList(Lists.singleton(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Integer deleteTagByIdList(List<Long> idList) {
|
||||
List<TagDO> tagList = tagDAO.selectBatchIds(idList);
|
||||
if (tagList.isEmpty()) {
|
||||
return Const.N_0;
|
||||
}
|
||||
// 删除数据库
|
||||
// 设置日志参数
|
||||
String name = tagList.stream()
|
||||
.map(TagDO::getName)
|
||||
.collect(Collectors.joining(Const.COMMA));
|
||||
OperatorLogs.add(OperatorLogs.NAME, name);
|
||||
// 删除标签
|
||||
int effect = tagDAO.deleteBatchIds(idList);
|
||||
// 删除关联
|
||||
tagRelService.deleteTagIdList(idList);
|
||||
log.info("TagService-deleteTagByIdList idList: {}, effect: {}", idList, effect);
|
||||
// 删除缓存
|
||||
for (TagDO tag : tagList) {
|
||||
String cacheKey = TagCacheKeyDefine.TAG_NAME.format(tag.getType());
|
||||
RedisLists.removeJson(cacheKey, TagConvert.MAPPER.toCache(tag));
|
||||
}
|
||||
List<String> deleteKeys = tagList.stream()
|
||||
.map(TagDO::getType)
|
||||
.distinct()
|
||||
.map(TagCacheKeyDefine.TAG_NAME::format)
|
||||
.collect(Collectors.toList());
|
||||
RedisUtils.delete(deleteKeys);
|
||||
return effect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearUnusedTag() {
|
||||
public void clearUnusedTag(Integer days) {
|
||||
// 查询
|
||||
List<TagDO> tagList = tagDAO.selectUnusedTag(UN_USED_DAYS);
|
||||
List<TagDO> tagList = tagDAO.selectUnusedTag(days);
|
||||
if (tagList.isEmpty()) {
|
||||
log.info("TagService.clearUnusedTag isEmpty");
|
||||
return;
|
||||
@@ -160,7 +226,25 @@ public class TagServiceImpl implements TagService {
|
||||
.distinct()
|
||||
.map(TagCacheKeyDefine.TAG_NAME::format)
|
||||
.collect(Collectors.toList());
|
||||
RedisLists.delete(cacheKeys);
|
||||
RedisUtils.delete(cacheKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数据是否存在
|
||||
*
|
||||
* @param domain domain
|
||||
*/
|
||||
private void checkTagPresent(TagDO domain) {
|
||||
// 构造条件
|
||||
LambdaQueryWrapper<TagDO> wrapper = tagDAO.wrapper()
|
||||
// 更新时忽略当前记录
|
||||
.ne(TagDO::getId, domain.getId())
|
||||
// 用其他字段做重复校验
|
||||
.eq(TagDO::getType, domain.getType())
|
||||
.eq(TagDO::getName, domain.getName());
|
||||
// 检查是否存在
|
||||
boolean present = tagDAO.of(wrapper).present();
|
||||
Assert.isFalse(present, ErrorMessage.NAME_PRESENT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,19 +26,20 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.utils.LockerUtils;
|
||||
import org.dromara.visor.module.infra.service.TagService;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* tag 定时清理任务
|
||||
* <p>
|
||||
* 提供了 web 管理删除, 所以不需要定时清理
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/4/15 23:50
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
// @Component
|
||||
public class TagAutoClearTask {
|
||||
|
||||
/**
|
||||
@@ -46,6 +47,11 @@ public class TagAutoClearTask {
|
||||
*/
|
||||
private static final String LOCK_KEY = "clear:tag:lock";
|
||||
|
||||
/**
|
||||
* 未使用的天数
|
||||
*/
|
||||
private static final Integer UN_USED_DAYS = 3;
|
||||
|
||||
@Resource
|
||||
private TagService tagService;
|
||||
|
||||
@@ -56,7 +62,7 @@ public class TagAutoClearTask {
|
||||
public void clear() {
|
||||
log.info("TagAutoClearTask.clear start");
|
||||
// 获取锁并执行
|
||||
LockerUtils.tryLockExecute(LOCK_KEY, tagService::clearUnusedTag);
|
||||
LockerUtils.tryLockExecute(LOCK_KEY, () -> tagService.clearUnusedTag(UN_USED_DAYS));
|
||||
log.info("TagAutoClearTask.clear finish");
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,28 @@
|
||||
<result column="rel_id" property="relId"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 数量查询映射结果 -->
|
||||
<resultMap id="CountResultMap" type="org.dromara.visor.module.infra.entity.po.TagRelCountPO">
|
||||
<result column="tag_id" property="tagId"/>
|
||||
<result column="total_count" property="count"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, tag_id, tag_name, tag_type, rel_id, create_time, update_time, creator, updater, deleted
|
||||
</sql>
|
||||
|
||||
<select id="selectTagRelCount" resultMap="CountResultMap">
|
||||
SELECT tag_id, count(1) total_count
|
||||
FROM tag_rel
|
||||
WHERE deleted = 0
|
||||
<if test="tagIdList != null and tagIdList.size() > 0">
|
||||
AND tag_id IN
|
||||
<foreach collection="tagIdList" item="item" open=" (" separator="," close=")">
|
||||
#{item}
|
||||
</foreach>
|
||||
</if>
|
||||
GROUP BY tag_id
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -41,11 +41,6 @@ public enum AlarmEventSourceTypeEnum {
|
||||
*/
|
||||
HOST,
|
||||
|
||||
/**
|
||||
* 拨测告警
|
||||
*/
|
||||
UPTIME,
|
||||
|
||||
;
|
||||
|
||||
public static AlarmEventSourceTypeEnum of(String value) {
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.dromara.visor.common.constant.ErrorMessage;
|
||||
import org.dromara.visor.common.utils.Assert;
|
||||
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisMaps;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisUtils;
|
||||
import org.dromara.visor.framework.redis.core.utils.barrier.CacheBarriers;
|
||||
import org.dromara.visor.module.monitor.convert.AlarmPolicyConvert;
|
||||
import org.dromara.visor.module.monitor.dao.AlarmPolicyDAO;
|
||||
@@ -114,7 +115,7 @@ public class AlarmPolicyServiceImpl implements AlarmPolicyService {
|
||||
// 重新加载上下文
|
||||
alarmEngineContext.reloadPolicy(id);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(record.getType()),
|
||||
RedisUtils.delete(AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(record.getType()),
|
||||
AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(Const.ALL));
|
||||
// 设置日志参数
|
||||
OperatorLogs.add(OperatorLogs.ID, id);
|
||||
@@ -137,7 +138,7 @@ public class AlarmPolicyServiceImpl implements AlarmPolicyService {
|
||||
// 重新加载上下文
|
||||
alarmEngineContext.reloadPolicy(id);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(record.getType()),
|
||||
RedisUtils.delete(AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(record.getType()),
|
||||
AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(Const.ALL));
|
||||
return newId;
|
||||
}
|
||||
@@ -165,7 +166,7 @@ public class AlarmPolicyServiceImpl implements AlarmPolicyService {
|
||||
// 重新加载上下文
|
||||
alarmEngineContext.reloadPolicy(id);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(record.getType()),
|
||||
RedisUtils.delete(AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(record.getType()),
|
||||
AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(Const.ALL));
|
||||
return effect;
|
||||
}
|
||||
@@ -297,7 +298,7 @@ public class AlarmPolicyServiceImpl implements AlarmPolicyService {
|
||||
.eq(AlarmPolicyDO::getName, domain.getName());
|
||||
// 检查是否存在
|
||||
boolean present = alarmPolicyDAO.of(wrapper).present();
|
||||
Assert.isFalse(present, ErrorMessage.DATA_PRESENT);
|
||||
Assert.isFalse(present, ErrorMessage.NAME_PRESENT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.dromara.visor.common.constant.ErrorMessage;
|
||||
import org.dromara.visor.common.utils.Assert;
|
||||
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisMaps;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisUtils;
|
||||
import org.dromara.visor.framework.redis.core.utils.barrier.CacheBarriers;
|
||||
import org.dromara.visor.module.monitor.context.MonitorMetricsContext;
|
||||
import org.dromara.visor.module.monitor.convert.MonitorMetricsConvert;
|
||||
@@ -84,7 +85,7 @@ public class MonitorMetricsServiceImpl implements MonitorMetricsService {
|
||||
int effect = monitorMetricsDAO.insert(record);
|
||||
Long id = record.getId();
|
||||
// 删除缓存
|
||||
RedisMaps.delete(MonitorMetricsCacheKeyDefine.MONITOR_METRICS);
|
||||
RedisUtils.delete(MonitorMetricsCacheKeyDefine.MONITOR_METRICS);
|
||||
// 设置日志参数
|
||||
OperatorLogs.add(OperatorLogs.ID, id);
|
||||
// 重新加载本地缓存
|
||||
@@ -110,7 +111,7 @@ public class MonitorMetricsServiceImpl implements MonitorMetricsService {
|
||||
int effect = monitorMetricsDAO.updateById(updateRecord);
|
||||
log.info("MonitorMetricsService-updateMonitorMetricsById effect: {}", effect);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(MonitorMetricsCacheKeyDefine.MONITOR_METRICS);
|
||||
RedisUtils.delete(MonitorMetricsCacheKeyDefine.MONITOR_METRICS);
|
||||
// 重新加载本地缓存
|
||||
monitorMetricsContext.reloadMonitorMetrics(id);
|
||||
return effect;
|
||||
@@ -203,7 +204,7 @@ public class MonitorMetricsServiceImpl implements MonitorMetricsService {
|
||||
.eq(MonitorMetricsDO::getValue, domain.getValue());
|
||||
// 检查是否存在
|
||||
boolean present = monitorMetricsDAO.of(wrapper).present();
|
||||
Assert.isFalse(present, ErrorMessage.DATA_PRESENT);
|
||||
Assert.isFalse(present, ErrorMessage.NAME_PRESENT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@
|
||||
package org.dromara.visor.module.terminal.handler.terminal.handler;
|
||||
|
||||
import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||
import cn.orionsec.kit.lang.utils.io.Files1;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.common.enums.BooleanBit;
|
||||
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
|
||||
import org.dromara.visor.module.terminal.handler.terminal.model.request.SftpListRequest;
|
||||
@@ -61,6 +63,12 @@ public class SftpListHandler extends AbstractTerminalHandler<ISftpTerminalSender
|
||||
if (HOME_PATH.equals(path)) {
|
||||
path = session.getHome();
|
||||
}
|
||||
// 格式化目录
|
||||
path = Files1.getPath(path);
|
||||
// 去除尾部的 /
|
||||
if (path.endsWith(Const.SLASH) && path.length() > 1) {
|
||||
path = path.substring(0, path.length() - 1);
|
||||
}
|
||||
// 文件列表
|
||||
list = session.list(path, BooleanBit.toBoolean(payload.getShowHiddenFile()));
|
||||
log.info("SftpListHandler-handle success sessionId: {}, path: {}", sessionId, path);
|
||||
|
||||
@@ -50,7 +50,6 @@ public class TerminalAsyncSaver {
|
||||
*/
|
||||
public static void saveOperatorLog(OperatorLogModel model) {
|
||||
TerminalThreadPools.TERMINAL_ASYNC_SAVER.execute(() -> {
|
||||
model.setCreateTime(model.getStartTime());
|
||||
operatorLogFrameworkService.insert(model);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.ErrorMessage;
|
||||
import org.dromara.visor.common.utils.Assert;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisMaps;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisUtils;
|
||||
import org.dromara.visor.framework.redis.core.utils.barrier.CacheBarriers;
|
||||
import org.dromara.visor.framework.security.core.utils.SecurityUtils;
|
||||
import org.dromara.visor.module.terminal.convert.CommandSnippetConvert;
|
||||
@@ -84,7 +85,7 @@ public class CommandSnippetServiceImpl implements CommandSnippetService {
|
||||
Long id = record.getId();
|
||||
log.info("CommandSnippetService-createCommandSnippet id: {}, effect: {}", id, effect);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(CommandSnippetCacheKeyDefine.SNIPPET.format(userId));
|
||||
RedisUtils.delete(CommandSnippetCacheKeyDefine.SNIPPET.format(userId));
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -109,7 +110,7 @@ public class CommandSnippetServiceImpl implements CommandSnippetService {
|
||||
int effect = commandSnippetDAO.update(null, update);
|
||||
log.info("CommandSnippetService-updateCommandSnippetById effect: {}", effect);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(CommandSnippetCacheKeyDefine.SNIPPET.format(userId));
|
||||
RedisUtils.delete(CommandSnippetCacheKeyDefine.SNIPPET.format(userId));
|
||||
return effect;
|
||||
}
|
||||
|
||||
@@ -169,7 +170,7 @@ public class CommandSnippetServiceImpl implements CommandSnippetService {
|
||||
public Integer setGroupNull(Long userId, Long groupId) {
|
||||
int effect = commandSnippetDAO.setGroupIdWithNull(groupId);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(CommandSnippetCacheKeyDefine.SNIPPET.format(userId));
|
||||
RedisUtils.delete(CommandSnippetCacheKeyDefine.SNIPPET.format(userId));
|
||||
return effect;
|
||||
}
|
||||
|
||||
@@ -192,7 +193,7 @@ public class CommandSnippetServiceImpl implements CommandSnippetService {
|
||||
public Integer deleteByGroupId(Long userId, Long groupId) {
|
||||
int effect = commandSnippetDAO.deleteByGroupId(groupId);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(CommandSnippetCacheKeyDefine.SNIPPET.format(userId));
|
||||
RedisUtils.delete(CommandSnippetCacheKeyDefine.SNIPPET.format(userId));
|
||||
return effect;
|
||||
}
|
||||
|
||||
@@ -217,7 +218,7 @@ public class CommandSnippetServiceImpl implements CommandSnippetService {
|
||||
.eq(CommandSnippetDO::getName, domain.getName());
|
||||
// 检查是否存在
|
||||
boolean present = commandSnippetDAO.of(wrapper).present();
|
||||
Assert.isFalse(present, ErrorMessage.DATA_PRESENT);
|
||||
Assert.isFalse(present, ErrorMessage.NAME_PRESENT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.ErrorMessage;
|
||||
import org.dromara.visor.common.utils.Assert;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisMaps;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisUtils;
|
||||
import org.dromara.visor.framework.redis.core.utils.barrier.CacheBarriers;
|
||||
import org.dromara.visor.framework.security.core.utils.SecurityUtils;
|
||||
import org.dromara.visor.module.terminal.convert.PathBookmarkConvert;
|
||||
@@ -84,7 +85,7 @@ public class PathBookmarkServiceImpl implements PathBookmarkService {
|
||||
Long id = record.getId();
|
||||
log.info("PathBookmarkService-createPathBookmark id: {}, effect: {}", id, effect);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(PathBookmarkCacheKeyDefine.PATH_BOOKMARK.format(userId));
|
||||
RedisUtils.delete(PathBookmarkCacheKeyDefine.PATH_BOOKMARK.format(userId));
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -109,7 +110,7 @@ public class PathBookmarkServiceImpl implements PathBookmarkService {
|
||||
int effect = pathBookmarkDAO.update(null, update);
|
||||
log.info("PathBookmarkService-updatePathBookmarkById effect: {}", effect);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(PathBookmarkCacheKeyDefine.PATH_BOOKMARK.format(userId));
|
||||
RedisUtils.delete(PathBookmarkCacheKeyDefine.PATH_BOOKMARK.format(userId));
|
||||
return effect;
|
||||
}
|
||||
|
||||
@@ -169,7 +170,7 @@ public class PathBookmarkServiceImpl implements PathBookmarkService {
|
||||
public Integer setGroupNull(Long userId, Long groupId) {
|
||||
int effect = pathBookmarkDAO.setGroupIdWithNull(groupId);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(PathBookmarkCacheKeyDefine.PATH_BOOKMARK.format(userId));
|
||||
RedisUtils.delete(PathBookmarkCacheKeyDefine.PATH_BOOKMARK.format(userId));
|
||||
return effect;
|
||||
}
|
||||
|
||||
@@ -192,7 +193,7 @@ public class PathBookmarkServiceImpl implements PathBookmarkService {
|
||||
public Integer deleteByGroupId(Long userId, Long groupId) {
|
||||
int effect = pathBookmarkDAO.deleteByGroupId(groupId);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(PathBookmarkCacheKeyDefine.PATH_BOOKMARK.format(userId));
|
||||
RedisUtils.delete(PathBookmarkCacheKeyDefine.PATH_BOOKMARK.format(userId));
|
||||
return effect;
|
||||
}
|
||||
|
||||
@@ -217,7 +218,7 @@ public class PathBookmarkServiceImpl implements PathBookmarkService {
|
||||
.eq(PathBookmarkDO::getName, domain.getName());
|
||||
// 检查是否存在
|
||||
boolean present = pathBookmarkDAO.of(wrapper).present();
|
||||
Assert.isFalse(present, ErrorMessage.DATA_PRESENT);
|
||||
Assert.isFalse(present, ErrorMessage.NAME_PRESENT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ VITE_API_BASE_URL=http://127.0.0.1:9200/orion-visor/api
|
||||
# websocket 路径
|
||||
VITE_WS_BASE_URL=ws://127.0.0.1:9200/orion-visor/keep-alive
|
||||
# 版本号
|
||||
VITE_APP_VERSION=2.5.4
|
||||
VITE_APP_VERSION=2.5.6
|
||||
|
||||
@@ -3,4 +3,4 @@ VITE_API_BASE_URL=/orion-visor/api
|
||||
# websocket 路径
|
||||
VITE_WS_BASE_URL=/orion-visor/keep-alive
|
||||
# 版本号
|
||||
VITE_APP_VERSION=2.5.4
|
||||
VITE_APP_VERSION=2.5.6
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "orion-visor-ui",
|
||||
"description": "Orion Visor UI",
|
||||
"version": "2.5.4",
|
||||
"version": "2.5.6",
|
||||
"private": true,
|
||||
"author": "Jiahang Li",
|
||||
"license": "Apache 2.0",
|
||||
|
||||
@@ -10,6 +10,7 @@ export interface HostAgentStatusResponse {
|
||||
latestVersion: string;
|
||||
agentInstallStatus: number;
|
||||
agentOnlineStatus: number;
|
||||
agentOnlineChangeTime: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,6 +49,8 @@ export interface HostLabelExtraSettingModel {
|
||||
// 标签规格模型
|
||||
export interface HostSpecExtraModel {
|
||||
sn: string;
|
||||
vendor: string;
|
||||
model: string;
|
||||
osName: string;
|
||||
cpuCount: number;
|
||||
cpuPhysicalCore: number;
|
||||
|
||||
@@ -1,19 +1,47 @@
|
||||
import type { TableData } from '@arco-design/web-vue';
|
||||
import type { DataGrid, Pagination, OrderDirection } from '@/types/global';
|
||||
import axios from 'axios';
|
||||
|
||||
export type TagType = 'HOST' | string
|
||||
export type TagType = 'HOST' | 'MONITOR_DASH' | string
|
||||
|
||||
/**
|
||||
* tag 创建对象
|
||||
*/
|
||||
export interface TagCreateRequest {
|
||||
name: number;
|
||||
type: TagType;
|
||||
name?: string;
|
||||
type?: TagType;
|
||||
}
|
||||
|
||||
/**
|
||||
* tag 修改对象
|
||||
*/
|
||||
export interface TagUpdateRequest extends TagCreateRequest {
|
||||
id?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* tag 查询请求
|
||||
*/
|
||||
export interface TagQueryRequest extends Pagination, OrderDirection {
|
||||
name?: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* tag 响应对象
|
||||
*/
|
||||
export interface TagQueryResponse {
|
||||
export interface TagQueryResponse extends TableData, TagItem {
|
||||
relCount: string;
|
||||
createTime: number;
|
||||
updateTime: number;
|
||||
creator: string;
|
||||
updater: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* tag 元素
|
||||
*/
|
||||
export interface TagItem {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
@@ -25,9 +53,30 @@ export function createTag(request: TagCreateRequest) {
|
||||
return axios.post('/infra/tag/create', request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改标签
|
||||
*/
|
||||
export function updateTag(request: TagUpdateRequest) {
|
||||
return axios.put('/infra/tag/update', request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询标签
|
||||
*/
|
||||
export function getTagPage(request: TagQueryRequest) {
|
||||
return axios.post<DataGrid<TagQueryResponse>>('/infra/tag/query', request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询标签
|
||||
*/
|
||||
export function getTagList(type: TagType) {
|
||||
return axios.get<Array<TagQueryResponse>>('/infra/tag/list', { params: { type } });
|
||||
return axios.get<Array<TagItem>>('/infra/tag/list', { params: { type } });
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 id 删除标签
|
||||
*/
|
||||
export function deleteTag(id: number) {
|
||||
return axios.delete('/infra/tag/delete', { params: { id } });
|
||||
}
|
||||
|
||||
@@ -60,10 +60,31 @@ export interface UserQueryResponse extends TableData {
|
||||
roles: Array<RoleQueryResponse>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 锁定用户查询响应
|
||||
*/
|
||||
export interface LockedUserQueryResponse {
|
||||
username: string;
|
||||
address: string;
|
||||
location: string;
|
||||
userAgent: string;
|
||||
expireTime: number;
|
||||
loginTime: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解锁用户请求
|
||||
*/
|
||||
export interface UserUnlockRequest {
|
||||
username: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户会话查询响应
|
||||
*/
|
||||
export interface UserSessionQueryResponse {
|
||||
id: number;
|
||||
username: string;
|
||||
visible: boolean;
|
||||
current: boolean;
|
||||
address: string;
|
||||
@@ -183,10 +204,31 @@ export function batchDeleteUser(idList: Array<number>) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户会话列表
|
||||
* 获取锁定的用户列表
|
||||
*/
|
||||
export function getLockedUserList() {
|
||||
return axios.get<Array<LockedUserQueryResponse>>('/infra/system-user/locked/list');
|
||||
}
|
||||
|
||||
/**
|
||||
* 解锁锁定的用户
|
||||
*/
|
||||
export function unlockLockedUser(request: UserUnlockRequest) {
|
||||
return axios.put('/infra/system-user/locked/unlock', request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全部用户会话列表
|
||||
*/
|
||||
export function getUsersSessionList() {
|
||||
return axios.get<Array<UserSessionQueryResponse>>('/infra/system-user/session/users/list');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个用户会话列表
|
||||
*/
|
||||
export function getUserSessionList(id: number) {
|
||||
return axios.get<Array<UserSessionQueryResponse>>('/infra/system-user/session/list', { params: { id } });
|
||||
return axios.get<Array<UserSessionQueryResponse>>('/infra/system-user/session/user/list', { params: { id } });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user