Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
120eb1ee69 | ||
|
|
252c538571 | ||
|
|
1eec373b7e | ||
|
|
aa9b96a9c1 | ||
|
|
059fb30aa4 | ||
|
|
2afaf7ad34 | ||
|
|
076a0956c5 | ||
|
|
4a91ec47bf | ||
|
|
1066b43b3d | ||
|
|
3f78125c43 | ||
|
|
144a44673b |
@@ -63,7 +63,7 @@
|
||||
|
||||
```bash
|
||||
# clone
|
||||
git clone https://github.com/dromara/orion-visor
|
||||
git clone --depth=1 https://github.com/dromara/orion-visor
|
||||
cd orion-visor
|
||||
# 启动
|
||||
docker compose up -d
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
version: '3.3'
|
||||
services:
|
||||
service:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-service:2.1.3
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-service:2.1.4
|
||||
privileged: true
|
||||
ports:
|
||||
- 1081:80
|
||||
@@ -32,7 +32,7 @@ services:
|
||||
- mysql
|
||||
- redis
|
||||
mysql:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-mysql:2.1.3
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-mysql:2.1.4
|
||||
privileged: true
|
||||
ports:
|
||||
- 3307:3306
|
||||
@@ -52,7 +52,7 @@ services:
|
||||
retries: 10
|
||||
start_period: 3s
|
||||
redis:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:2.1.3
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:2.1.4
|
||||
privileged: true
|
||||
ports:
|
||||
- 6380:6379
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
version: '3.3'
|
||||
services:
|
||||
service:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-service:2.1.3
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-service:2.1.4
|
||||
privileged: true
|
||||
ports:
|
||||
- ${SERVICE_PORT:-1081}:80
|
||||
@@ -19,9 +19,9 @@ services:
|
||||
- ${VOLUME_BASE:-/data/orion-visor-space/docker-volumes}/service/root-orion:/root/orion
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "http://127.0.0.1:9200/orion-visor/api/server/bootstrap/health" ]
|
||||
interval: 3s
|
||||
interval: 15s
|
||||
timeout: 300s
|
||||
retries: 200
|
||||
retries: 15
|
||||
start_period: 3s
|
||||
depends_on:
|
||||
mysql:
|
||||
@@ -32,7 +32,7 @@ services:
|
||||
- mysql
|
||||
- redis
|
||||
mysql:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-mysql:2.1.3
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-mysql:2.1.4
|
||||
privileged: true
|
||||
ports:
|
||||
- 3307:3306
|
||||
@@ -47,12 +47,12 @@ services:
|
||||
- ${VOLUME_BASE:-/data/orion-visor-space/docker-volumes}/mysql/etc-mysql:/etc/mysql
|
||||
healthcheck:
|
||||
test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3306" ]
|
||||
interval: 3s
|
||||
interval: 15s
|
||||
timeout: 60s
|
||||
retries: 10
|
||||
retries: 15
|
||||
start_period: 3s
|
||||
redis:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:2.1.3
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:2.1.4
|
||||
privileged: true
|
||||
ports:
|
||||
- 6380:6379
|
||||
@@ -63,12 +63,12 @@ services:
|
||||
command: sh -c "redis-server /usr/local/redis.conf --requirepass $${REDIS_PASSWORD}"
|
||||
healthcheck:
|
||||
test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ]
|
||||
interval: 3s
|
||||
interval: 15s
|
||||
timeout: 60s
|
||||
retries: 10
|
||||
retries: 15
|
||||
start_period: 3s
|
||||
adminer:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-adminer:2.1.3
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-adminer:2.1.4
|
||||
ports:
|
||||
- 8081:8080
|
||||
depends_on:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#/bin/bash
|
||||
version=2.1.3
|
||||
version=2.1.4
|
||||
docker build -t orion-visor-adminer:${version} .
|
||||
docker tag orion-visor-adminer:${version} registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-adminer:${version}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#/bin/bash
|
||||
version=2.1.3
|
||||
version=2.1.4
|
||||
cp -r ../../sql ./sql
|
||||
docker build -t orion-visor-mysql:${version} .
|
||||
rm -rf ./sql
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#/bin/bash
|
||||
version=2.1.3
|
||||
version=2.1.4
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-adminer:${version}
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-mysql:${version}
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:${version}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#/bin/bash
|
||||
version=2.1.3
|
||||
version=2.1.4
|
||||
docker build -t orion-visor-redis:${version} .
|
||||
docker tag orion-visor-redis:${version} registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:${version}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#/bin/bash
|
||||
version=2.1.3
|
||||
version=2.1.4
|
||||
mv ../../orion-visor-launch/target/orion-visor-launch.jar ./orion-visor-launch.jar
|
||||
mv ../../orion-visor-ui/dist ./dist
|
||||
docker build -t orion-visor-service:${version} .
|
||||
|
||||
@@ -29,7 +29,7 @@ server {
|
||||
location /orion-visor/api {
|
||||
proxy_pass http://localhost:9200/orion-visor/api;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<url>https://github.com/dromara/orion-visor</url>
|
||||
|
||||
<properties>
|
||||
<revision>2.1.3</revision>
|
||||
<revision>2.1.4</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>
|
||||
|
||||
@@ -14,7 +14,7 @@ public interface AppConst extends OrionConst {
|
||||
/**
|
||||
* 同 ${orion.version} 迭代时候需要手动更改
|
||||
*/
|
||||
String VERSION = "2.1.3";
|
||||
String VERSION = "2.1.4";
|
||||
|
||||
/**
|
||||
* 同 ${spring.application.name}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.orion.visor.framework.common.meta;
|
||||
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
import com.orion.lang.id.UUIds;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
/**
|
||||
* traceId 持有者
|
||||
@@ -23,16 +25,74 @@ public class TraceIdHolder {
|
||||
*/
|
||||
private static final ThreadLocal<String> HOLDER = new TransmittableThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 获取 traceId
|
||||
*
|
||||
* @return traceId
|
||||
*/
|
||||
public static String get() {
|
||||
return HOLDER.get();
|
||||
}
|
||||
|
||||
public static void set(String traceId) {
|
||||
HOLDER.set(traceId);
|
||||
/**
|
||||
* 设置 traceId
|
||||
*/
|
||||
public static void set() {
|
||||
set(createTraceId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 traceId
|
||||
*
|
||||
* @param traceId traceId
|
||||
*/
|
||||
public static void set(String traceId) {
|
||||
// 设置应用上下文
|
||||
HOLDER.set(traceId);
|
||||
// 设置日志上下文
|
||||
setMdc(traceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 traceId
|
||||
*/
|
||||
public static void remove() {
|
||||
// 移除应用上下文
|
||||
HOLDER.remove();
|
||||
// 移除日志上下文
|
||||
removeMdc();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从应用上下文 设置到日志上下文
|
||||
*/
|
||||
public static void setMdc() {
|
||||
setMdc(HOLDER.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置到日志上下文
|
||||
*
|
||||
* @param traceId traceId
|
||||
*/
|
||||
public static void setMdc(String traceId) {
|
||||
MDC.put(TRACE_ID_MDC, traceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除日志上下文
|
||||
*/
|
||||
public static void removeMdc() {
|
||||
MDC.remove(TRACE_ID_MDC);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 traceId
|
||||
*
|
||||
* @return traceId
|
||||
*/
|
||||
public static String createTraceId() {
|
||||
return UUIds.random32();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.orion.visor.framework.mybatis.core.generator.core;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.generator.config.po.TableField;
|
||||
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
|
||||
import com.orion.lang.utils.Exceptions;
|
||||
import com.orion.lang.utils.Strings;
|
||||
import com.orion.visor.framework.common.constant.Const;
|
||||
import com.orion.visor.framework.common.constant.FieldConst;
|
||||
@@ -47,7 +48,7 @@ public class DictParser {
|
||||
.stream()
|
||||
.filter(s -> variable.equals(s.getName()) || variable.equals(s.getPropertyName()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("未查询到字典映射字段 " + variable));
|
||||
.orElseThrow(() -> Exceptions.runtime("未查询到字典映射字段 " + variable));
|
||||
// 设置字段名称
|
||||
if (meta.getField() == null) {
|
||||
meta.setField(Strings.firstUpper(tableField.getPropertyName()));
|
||||
|
||||
@@ -98,6 +98,13 @@ public class SecurityUtils {
|
||||
return loginUser != null ? loginUser.getTimestamp() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空用户上下文
|
||||
*/
|
||||
public static void clearAuthentication() {
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前用户
|
||||
*
|
||||
@@ -107,7 +114,9 @@ public class SecurityUtils {
|
||||
public static void setLoginUser(LoginUser loginUser, HttpServletRequest request) {
|
||||
// 创建 authentication
|
||||
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(loginUser, null, Collections.emptyList());
|
||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
if (request != null) {
|
||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
}
|
||||
// 设置上下文
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.orion.visor.framework.web.core.filter;
|
||||
|
||||
import com.orion.lang.id.UUIds;
|
||||
import com.orion.visor.framework.common.meta.TraceIdHolder;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
@@ -23,21 +21,17 @@ public class TraceIdFilter extends OncePerRequestFilter {
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
try {
|
||||
// 获 traceId
|
||||
String traceId = UUIds.random32();
|
||||
// 设置应用上下文
|
||||
// 获取 traceId
|
||||
String traceId = TraceIdHolder.createTraceId();
|
||||
// 设置 traceId 上下文
|
||||
TraceIdHolder.set(traceId);
|
||||
// 设置日志上下文
|
||||
MDC.put(TraceIdHolder.TRACE_ID_MDC, traceId);
|
||||
// 设置响应头
|
||||
response.setHeader(TraceIdHolder.TRACE_ID_HEADER, traceId);
|
||||
// 执行请求
|
||||
filterChain.doFilter(request, response);
|
||||
} finally {
|
||||
// 清理应用上下文
|
||||
// 清空 traceId 上下文
|
||||
TraceIdHolder.remove();
|
||||
// 清理日志上下文
|
||||
MDC.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -167,6 +167,8 @@ app:
|
||||
allow-refresh: true
|
||||
# 凭证续签最大次数
|
||||
max-refresh-count: 3
|
||||
# 登录失败发送站内信阈值
|
||||
login-failed-send-threshold: 3
|
||||
# 登录失败锁定次数
|
||||
login-failed-lock-count: 5
|
||||
# 登录失败锁定时间 (分)
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.orion.visor.framework.biz.operator.log.core.annotation.OperatorLog;
|
||||
import com.orion.visor.framework.common.validator.group.Page;
|
||||
import com.orion.visor.framework.log.core.annotation.IgnoreLog;
|
||||
import com.orion.visor.framework.log.core.enums.IgnoreLogMode;
|
||||
import com.orion.visor.framework.web.core.annotation.DemoDisableApi;
|
||||
import com.orion.visor.framework.web.core.annotation.RestWrapper;
|
||||
import com.orion.visor.module.asset.define.operator.ExecJobOperatorType;
|
||||
import com.orion.visor.module.asset.entity.request.exec.*;
|
||||
@@ -39,6 +40,7 @@ public class ExecJobController {
|
||||
@Resource
|
||||
private ExecJobService execJobService;
|
||||
|
||||
@DemoDisableApi
|
||||
@OperatorLog(ExecJobOperatorType.CREATE)
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建计划任务")
|
||||
@@ -47,6 +49,7 @@ public class ExecJobController {
|
||||
return execJobService.createExecJob(request);
|
||||
}
|
||||
|
||||
@DemoDisableApi
|
||||
@OperatorLog(ExecJobOperatorType.UPDATE)
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新计划任务")
|
||||
@@ -55,6 +58,7 @@ public class ExecJobController {
|
||||
return execJobService.updateExecJobById(request);
|
||||
}
|
||||
|
||||
@DemoDisableApi
|
||||
@OperatorLog(ExecJobOperatorType.UPDATE_STATUS)
|
||||
@PutMapping("/update-status")
|
||||
@Operation(summary = "更新计划任务状态")
|
||||
@@ -88,6 +92,7 @@ public class ExecJobController {
|
||||
return execJobService.getExecJobPage(request);
|
||||
}
|
||||
|
||||
@DemoDisableApi
|
||||
@OperatorLog(ExecJobOperatorType.DELETE)
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除计划任务")
|
||||
@@ -97,6 +102,7 @@ public class ExecJobController {
|
||||
return execJobService.deleteExecJobById(id);
|
||||
}
|
||||
|
||||
@DemoDisableApi
|
||||
@OperatorLog(ExecJobOperatorType.DELETE)
|
||||
@DeleteMapping("/batch-delete")
|
||||
@Operation(summary = "批量删除计划任务")
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.orion.lang.utils.Strings;
|
||||
import com.orion.net.host.SessionHolder;
|
||||
import com.orion.net.host.SessionLogger;
|
||||
import com.orion.net.host.SessionStore;
|
||||
import com.orion.visor.framework.common.constant.AppConst;
|
||||
import com.orion.visor.framework.common.constant.Const;
|
||||
import com.orion.visor.framework.common.utils.CryptoUtils;
|
||||
import com.orion.visor.module.asset.entity.dto.HostTerminalConnectDTO;
|
||||
@@ -43,6 +44,8 @@ public class SessionStores {
|
||||
SessionHolder sessionHolder = SessionHolder.create();
|
||||
sessionHolder.setLogger(SessionLogger.INFO);
|
||||
SessionStore session = createSessionStore(conn, sessionHolder);
|
||||
// 设置版本
|
||||
session.getSession().setClientVersion("SSH-2.0-ORION_VISOR_V" + AppConst.VERSION);
|
||||
// 连接
|
||||
session.connect();
|
||||
log.info("SessionStores-open-success hostId: {}, address: {}, username: {}", hostId, address, username);
|
||||
|
||||
@@ -65,13 +65,15 @@ public class TerminalConnectHandler extends AbstractTerminalHandler<TerminalConn
|
||||
// 移除会话连接信息
|
||||
channel.getAttributes().remove(sessionId);
|
||||
Exception ex = null;
|
||||
ITerminalSession session = null;
|
||||
try {
|
||||
// 连接主机
|
||||
ITerminalSession session = this.connect(sessionId, connect, channel, payload);
|
||||
session = this.connect(sessionId, connect, channel, payload);
|
||||
// 添加会话到 manager
|
||||
hostTerminalManager.addSession(session);
|
||||
} catch (Exception e) {
|
||||
ex = e;
|
||||
Streams.close(session);
|
||||
// 修改连接状态为失败
|
||||
Map<String, Object> extra = Maps.newMap(4);
|
||||
extra.put(ExtraFieldConst.ERROR_MESSAGE, this.getConnectErrorMessage(e));
|
||||
|
||||
@@ -75,6 +75,10 @@ public class HostTerminalServiceImpl implements HostTerminalService {
|
||||
|
||||
@Override
|
||||
public List<HostTerminalThemeVO> getTerminalThemes() {
|
||||
// if (true) {
|
||||
// String arr = "";
|
||||
// return JSON.parseArray(arr, HostTerminalThemeVO.class);
|
||||
// }
|
||||
List<JSONObject> themes = dictValueApi.getDictValue(THEME_DICT_KEY);
|
||||
return themes.stream()
|
||||
.map(s -> HostTerminalThemeVO.builder()
|
||||
|
||||
@@ -28,13 +28,15 @@ public class TerminalThemeGenerator {
|
||||
List<File> files = Files1.listFiles("D:\\idea-project\\iTerm2-Color-Schemes\\vhs");
|
||||
// 过滤的 theme
|
||||
List<String> schemaFilter = Lists.of(
|
||||
"Dracula", "Atom",
|
||||
"catppuccin-mocha", "MaterialDesignColors",
|
||||
"catppuccin-macchiato", "OneHalfDark",
|
||||
"Apple System Colors", "Builtin Tango Light",
|
||||
"Duotone Dark", "BlulocoLight",
|
||||
"Chester", "CLRS",
|
||||
"Calamity", "Tomorrow"
|
||||
"Dracula", "Builtin Tango Light",
|
||||
"Atom", "AtomOneLight",
|
||||
"OneHalfDark", "OneHalfLight",
|
||||
"Apple System Colors", "Tomorrow",
|
||||
"catppuccin-mocha", "catppuccin-latte",
|
||||
"catppuccin-macchiato", "BlulocoLight",
|
||||
"catppuccin-frappe", "MaterialDesignColors",
|
||||
"GitHub Dark", "Github",
|
||||
"DimmedMonokai", "Duotone Dark"
|
||||
);
|
||||
// 颜色大写
|
||||
ValueFilter colorFilter = (Object object, String name, Object value) -> {
|
||||
@@ -60,7 +62,7 @@ public class TerminalThemeGenerator {
|
||||
theme.setDark(Colors.isDarkColor(background));
|
||||
theme.setSchema(JSON.parseObject(JSON.toJSONString(schema), TerminalThemeSchema.class));
|
||||
return theme;
|
||||
}).collect(Collectors.toList());
|
||||
}).skip(0).limit(50).collect(Collectors.toList());
|
||||
// 排序
|
||||
if (!Lists.isEmpty(schemaFilter)) {
|
||||
arr.sort(Comparator.comparing(s -> schemaFilter.indexOf(s.getName())));
|
||||
@@ -70,11 +72,12 @@ public class TerminalThemeGenerator {
|
||||
for (TerminalTheme theme : arr) {
|
||||
System.out.println("name: " + theme.name);
|
||||
System.out.println("dark: " + theme.dark);
|
||||
System.out.println("value: \n" + JSON.toJSONString(theme.schema, colorFilter));
|
||||
System.out.println("value: " + JSON.toJSONString(theme.schema, colorFilter));
|
||||
System.out.println("json: " + JSON.toJSONString(theme, colorFilter));
|
||||
System.out.println();
|
||||
}
|
||||
// String json = JSON.toJSONString(arr, colorFilter);
|
||||
// System.out.println("\n" + json);
|
||||
String json = JSON.toJSONString(arr, colorFilter);
|
||||
System.out.println("\n" + json);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.orion.visor.module.infra.api;
|
||||
|
||||
import com.orion.visor.module.infra.entity.dto.user.SystemUserAuthDTO;
|
||||
|
||||
/**
|
||||
* 认证服务实现
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/8/14 21:37
|
||||
*/
|
||||
public interface AuthenticationApi {
|
||||
|
||||
/**
|
||||
* 通过密码认证
|
||||
*
|
||||
* @param username username
|
||||
* @param password password
|
||||
* @param addFailedCount addFailedCount
|
||||
* @return result
|
||||
*/
|
||||
SystemUserAuthDTO authByPassword(String username, String password, boolean addFailedCount);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.orion.visor.module.infra.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 权限 对外服务类
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/8/19 15:22
|
||||
*/
|
||||
public interface PermissionApi {
|
||||
|
||||
/**
|
||||
* 用户是否为管理员用户
|
||||
*
|
||||
* @param id id
|
||||
* @return isAdmin
|
||||
*/
|
||||
boolean isAdminUser(Long id);
|
||||
|
||||
/**
|
||||
* 检查当前用户是否含有此角色
|
||||
*
|
||||
* @param userId userId
|
||||
* @param role role
|
||||
* @return 是否包含
|
||||
*/
|
||||
boolean hasRole(Long userId, String role);
|
||||
|
||||
/**
|
||||
* 检查当前用户是否含有任意角色
|
||||
*
|
||||
* @param userId userId
|
||||
* @param roles roles
|
||||
* @return 是否包含
|
||||
*/
|
||||
boolean hasAnyRole(Long userId, List<String> roles);
|
||||
|
||||
/**
|
||||
* 检查当前用户是否含有此权限
|
||||
*
|
||||
* @param userId userId
|
||||
* @param permission permission
|
||||
* @return 是否包含
|
||||
*/
|
||||
boolean hasPermission(Long userId, String permission);
|
||||
|
||||
/**
|
||||
* 检查当前用户是否含任意权限
|
||||
*
|
||||
* @param userId userId
|
||||
* @param permissions permissions
|
||||
* @return 是否包含
|
||||
*/
|
||||
boolean hasAnyPermission(Long userId, List<String> permissions);
|
||||
|
||||
}
|
||||
@@ -11,6 +11,22 @@ import com.orion.visor.module.infra.entity.dto.user.SystemUserDTO;
|
||||
*/
|
||||
public interface SystemUserApi {
|
||||
|
||||
/**
|
||||
* 通过 id 查询用户名
|
||||
*
|
||||
* @param id id
|
||||
* @return username
|
||||
*/
|
||||
String getUsernameById(Long id);
|
||||
|
||||
/**
|
||||
* 通过 id 查询花名
|
||||
*
|
||||
* @param id id
|
||||
* @return nickname
|
||||
*/
|
||||
String getNicknameById(Long id);
|
||||
|
||||
/**
|
||||
* 通过 id 查询用户
|
||||
*
|
||||
@@ -19,12 +35,4 @@ public interface SystemUserApi {
|
||||
*/
|
||||
SystemUserDTO getUserById(Long id);
|
||||
|
||||
/**
|
||||
* 用户是否为管理员用户
|
||||
*
|
||||
* @param id id
|
||||
* @return isAdmin
|
||||
*/
|
||||
boolean isAdminUser(Long id);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.orion.visor.module.infra.entity.dto.user;
|
||||
|
||||
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/8/14 21:52
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "SystemUserAuthDTO", description = "用户认证 业务对象")
|
||||
public class SystemUserAuthDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "id")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "花名")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "密码是否正确")
|
||||
private Boolean passRight;
|
||||
|
||||
@Schema(description = "认证是否通过")
|
||||
private Boolean authed;
|
||||
|
||||
@Schema(description = "错误信息")
|
||||
private String errorMessage;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.orion.visor.module.infra.api.impl;
|
||||
|
||||
import com.orion.visor.framework.common.constant.ErrorMessage;
|
||||
import com.orion.visor.framework.common.utils.Valid;
|
||||
import com.orion.visor.module.infra.api.AuthenticationApi;
|
||||
import com.orion.visor.module.infra.entity.domain.SystemUserDO;
|
||||
import com.orion.visor.module.infra.entity.dto.user.SystemUserAuthDTO;
|
||||
import com.orion.visor.module.infra.service.AuthenticationService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 认证服务实现
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/8/14 21:37
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AuthenticationApiImpl implements AuthenticationApi {
|
||||
|
||||
@Resource
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
@Override
|
||||
public SystemUserAuthDTO authByPassword(String username, String password, boolean addFailedCount) {
|
||||
SystemUserAuthDTO result = new SystemUserAuthDTO();
|
||||
try {
|
||||
// 登录预检
|
||||
SystemUserDO user = authenticationService.preCheckLogin(username, password);
|
||||
result.setId(user.getId());
|
||||
result.setUsername(user.getUsername());
|
||||
result.setNickname(user.getNickname());
|
||||
// 检查用户密码
|
||||
boolean passRight = authenticationService.checkUserPassword(user, password, addFailedCount);
|
||||
result.setPassRight(passRight);
|
||||
Valid.isTrue(passRight, ErrorMessage.USERNAME_PASSWORD_ERROR);
|
||||
// 检查用户状态
|
||||
authenticationService.checkUserStatus(user);
|
||||
result.setAuthed(true);
|
||||
} catch (Exception e) {
|
||||
result.setAuthed(false);
|
||||
result.setErrorMessage(e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.orion.visor.module.infra.api.impl;
|
||||
|
||||
import com.orion.visor.module.infra.api.PermissionApi;
|
||||
import com.orion.visor.module.infra.service.PermissionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 权限 对外服务类实现
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/8/19 15:25
|
||||
*/
|
||||
@Service
|
||||
public class PermissionApiImpl implements PermissionApi {
|
||||
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
|
||||
@Override
|
||||
public boolean isAdminUser(Long id) {
|
||||
return permissionService.isAdminUser(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRole(Long userId, String role) {
|
||||
return permissionService.hasRole(userId, role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnyRole(Long userId, List<String> roles) {
|
||||
return permissionService.hasAnyRole(userId, roles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Long userId, String permission) {
|
||||
return permissionService.hasPermission(userId, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnyPermission(Long userId, List<String> permissions) {
|
||||
return permissionService.hasAnyPermission(userId, permissions);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import com.orion.visor.module.infra.convert.SystemUserProviderConvert;
|
||||
import com.orion.visor.module.infra.dao.SystemUserDAO;
|
||||
import com.orion.visor.module.infra.entity.domain.SystemUserDO;
|
||||
import com.orion.visor.module.infra.entity.dto.user.SystemUserDTO;
|
||||
import com.orion.visor.module.infra.service.SystemUserService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -23,8 +22,25 @@ public class SystemUserApiImpl implements SystemUserApi {
|
||||
@Resource
|
||||
private SystemUserDAO systemUserDAO;
|
||||
|
||||
@Resource
|
||||
private SystemUserService systemUserService;
|
||||
@Override
|
||||
public String getUsernameById(Long id) {
|
||||
return systemUserDAO.of()
|
||||
.createWrapper()
|
||||
.select(SystemUserDO::getUsername)
|
||||
.eq(SystemUserDO::getId, id)
|
||||
.then()
|
||||
.getOne(SystemUserDO::getUsername);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNicknameById(Long id) {
|
||||
return systemUserDAO.of()
|
||||
.createWrapper()
|
||||
.select(SystemUserDO::getNickname)
|
||||
.eq(SystemUserDO::getId, id)
|
||||
.then()
|
||||
.getOne(SystemUserDO::getNickname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemUserDTO getUserById(Long id) {
|
||||
@@ -35,9 +51,4 @@ public class SystemUserApiImpl implements SystemUserApi {
|
||||
return SystemUserProviderConvert.MAPPER.to(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdminUser(Long id) {
|
||||
return systemUserService.isAdminUser(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.orion.visor.framework.log.core.enums.IgnoreLogMode;
|
||||
import com.orion.visor.framework.web.core.annotation.RestWrapper;
|
||||
import com.orion.visor.module.infra.entity.vo.SystemMenuVO;
|
||||
import com.orion.visor.module.infra.entity.vo.UserPermissionVO;
|
||||
import com.orion.visor.module.infra.service.PermissionService;
|
||||
import com.orion.visor.module.infra.service.UserPermissionService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -26,22 +26,23 @@ import java.util.List;
|
||||
* @version 1.0.0
|
||||
* @since 2023/7/14 11:20
|
||||
*/
|
||||
@Tag(name = "infra - 权限服务")
|
||||
@Tag(name = "infra - 用户权限服务")
|
||||
@Slf4j
|
||||
@Validated
|
||||
@RestWrapper
|
||||
@RestController
|
||||
@RequestMapping("/infra/permission")
|
||||
public class PermissionController {
|
||||
@RequestMapping("/infra/user-permission")
|
||||
@SuppressWarnings({"ELValidationInJSP", "SpringElInspection"})
|
||||
public class UserPermissionController {
|
||||
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
private UserPermissionService userPermissionService;
|
||||
|
||||
@PutMapping("/refresh-cache")
|
||||
@Operation(summary = "刷新角色权限缓存")
|
||||
@PreAuthorize("@ss.hasPermission('infra:system-menu:management:refresh-cache')")
|
||||
public Boolean refreshCache() {
|
||||
permissionService.initPermissionCache();
|
||||
userPermissionService.initPermissionCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -49,14 +50,14 @@ public class PermissionController {
|
||||
@GetMapping("/menu")
|
||||
@Operation(summary = "获取用户菜单")
|
||||
public List<SystemMenuVO> getUserMenuList() {
|
||||
return permissionService.getUserMenuList();
|
||||
return userPermissionService.getUserMenuList();
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/user")
|
||||
@Operation(summary = "获取用户权限聚合信息")
|
||||
public UserPermissionVO getUserPermission() {
|
||||
return permissionService.getUserPermission();
|
||||
return userPermissionService.getUserPermission();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,11 +34,22 @@ public interface SystemRoleDAO extends IMapper<SystemRoleDO> {
|
||||
/**
|
||||
* 通过 userId 和 roleCode 查询 roleId (检查用户是否包含某个角色)
|
||||
*
|
||||
* @param userId userId
|
||||
* @param code code
|
||||
* @param userId userId
|
||||
* @param codeList codeList
|
||||
* @return roleId
|
||||
*/
|
||||
Long getRoleIdByUserIdAndRoleCode(@Param("userId") Long userId, @Param("code") String code);
|
||||
List<Long> getRoleIdByUserIdAndRoleCode(@Param("userId") Long userId,
|
||||
@Param("codeList") List<String> codeList);
|
||||
|
||||
/**
|
||||
* 通过 roleId 和 permission 查询 permission (检查角色是否包含某个权限)
|
||||
*
|
||||
* @param roleIdList roleIdList
|
||||
* @param permissionList permissionList
|
||||
* @return permission
|
||||
*/
|
||||
List<String> getPermissionByRoleIdAndPermission(@Param("roleIdList") List<Long> roleIdList,
|
||||
@Param("permissionList") List<String> permissionList);
|
||||
|
||||
/**
|
||||
* 查询用户角色
|
||||
|
||||
@@ -31,6 +31,11 @@ public class AppAuthenticationConfig {
|
||||
*/
|
||||
private Integer maxRefreshCount;
|
||||
|
||||
/**
|
||||
* 登录失败发送站内信阈值
|
||||
*/
|
||||
private Integer loginFailedSendThreshold;
|
||||
|
||||
/**
|
||||
* 登录失败锁定次数
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.orion.visor.module.infra.define.message;
|
||||
|
||||
import com.orion.visor.module.infra.define.SystemMessageDefine;
|
||||
import com.orion.visor.module.infra.enums.MessageClassifyEnum;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 用户 系统消息定义
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/5/14 17:23
|
||||
*/
|
||||
@Getter
|
||||
public enum SystemUserMessageDefine implements SystemMessageDefine {
|
||||
|
||||
/**
|
||||
* 登录失败
|
||||
*/
|
||||
LOGIN_FAILED(MessageClassifyEnum.NOTICE,
|
||||
"登录失败",
|
||||
"您的账号在 <sb>${time}</sb> 登录系统时身份认证失败, 您的密码可能已经泄漏。如非本人操作请尽快修改密码。(<sb>${address} - ${location}</sb>)"),
|
||||
|
||||
;
|
||||
|
||||
SystemUserMessageDefine(MessageClassifyEnum classify, String title, String content) {
|
||||
this.classify = classify;
|
||||
this.type = this.name();
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息分类
|
||||
*/
|
||||
private final MessageClassifyEnum classify;
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
private final String type;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private final String title;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
private final String content;
|
||||
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import com.orion.visor.module.infra.entity.dto.LoginTokenDTO;
|
||||
import com.orion.visor.module.infra.enums.LoginTokenStatusEnum;
|
||||
import com.orion.visor.module.infra.enums.UserStatusEnum;
|
||||
import com.orion.visor.module.infra.service.AuthenticationService;
|
||||
import com.orion.visor.module.infra.service.PermissionService;
|
||||
import com.orion.visor.module.infra.service.UserPermissionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -27,30 +27,30 @@ public class SecurityFrameworkServiceImpl implements SecurityFrameworkService {
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
private UserPermissionService userPermissionService;
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
// 检查是否有权限
|
||||
return permissionService.hasPermission(permission);
|
||||
return userPermissionService.hasPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnyPermission(String... permissions) {
|
||||
// 检查是否有权限
|
||||
return permissionService.hasAnyPermission(permissions);
|
||||
return userPermissionService.hasAnyPermission(permissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRole(String role) {
|
||||
// 检查是否有角色
|
||||
return permissionService.hasRole(role);
|
||||
return userPermissionService.hasRole(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnyRole(String... roles) {
|
||||
// 检查是否有角色
|
||||
return permissionService.hasAnyRole(roles);
|
||||
return userPermissionService.hasAnyRole(roles);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.orion.visor.module.infra.service;
|
||||
|
||||
import com.orion.visor.framework.common.security.LoginUser;
|
||||
import com.orion.visor.module.infra.entity.domain.SystemUserDO;
|
||||
import com.orion.visor.module.infra.entity.dto.LoginTokenDTO;
|
||||
import com.orion.visor.module.infra.entity.request.user.UserLoginRequest;
|
||||
import com.orion.visor.module.infra.entity.vo.UserLoginVO;
|
||||
@@ -48,4 +49,30 @@ public interface AuthenticationService {
|
||||
*/
|
||||
LoginTokenDTO getLoginTokenInfo(String loginToken);
|
||||
|
||||
/**
|
||||
* 登录预检查
|
||||
*
|
||||
* @param username username
|
||||
* @param password password
|
||||
* @return user
|
||||
*/
|
||||
SystemUserDO preCheckLogin(String username, String password);
|
||||
|
||||
/**
|
||||
* 检查用户密码
|
||||
*
|
||||
* @param user user
|
||||
* @param password password
|
||||
* @param addFailedCount addFailedCount
|
||||
* @return passRight
|
||||
*/
|
||||
boolean checkUserPassword(SystemUserDO user, String password, boolean addFailedCount);
|
||||
|
||||
/**
|
||||
* 检查用户状态
|
||||
*
|
||||
* @param user user
|
||||
*/
|
||||
void checkUserStatus(SystemUserDO user);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,92 +1,58 @@
|
||||
package com.orion.visor.module.infra.service;
|
||||
|
||||
import com.orion.visor.module.infra.entity.domain.SystemRoleDO;
|
||||
import com.orion.visor.module.infra.entity.dto.SystemMenuCacheDTO;
|
||||
import com.orion.visor.module.infra.entity.vo.SystemMenuVO;
|
||||
import com.orion.visor.module.infra.entity.vo.UserPermissionVO;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 权限服务
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/7/16 1:03
|
||||
* @since 2024/8/19 15:29
|
||||
*/
|
||||
public interface PermissionService {
|
||||
|
||||
/**
|
||||
* 获取 角色缓存
|
||||
* 检测用户是否是为管理员
|
||||
*
|
||||
* @return cache
|
||||
* @param userId userId
|
||||
* @return 是否为管理员
|
||||
*/
|
||||
Map<Long, SystemRoleDO> getRoleCache();
|
||||
boolean isAdminUser(Long userId);
|
||||
|
||||
/**
|
||||
* 获取 菜单缓存 以作角色权限直接引用
|
||||
* 检查当前用户是否含有此角色
|
||||
*
|
||||
* @return cache
|
||||
*/
|
||||
List<SystemMenuCacheDTO> getMenuCache();
|
||||
|
||||
/**
|
||||
* 获取 角色菜单关联
|
||||
*
|
||||
* @return cache
|
||||
*/
|
||||
Map<Long, List<SystemMenuCacheDTO>> getRoleMenuCache();
|
||||
|
||||
/**
|
||||
* 初始化权限缓存
|
||||
*/
|
||||
void initPermissionCache();
|
||||
|
||||
/**
|
||||
* 检查当前用户是否含有此角色 (有效性判断)
|
||||
*
|
||||
* @param role role
|
||||
* @param userId userId
|
||||
* @param role role
|
||||
* @return 是否包含
|
||||
*/
|
||||
boolean hasRole(String role);
|
||||
boolean hasRole(Long userId, String role);
|
||||
|
||||
/**
|
||||
* 检查当前用户是否含有任意角色 (有效性判断)
|
||||
* 检查当前用户是否含有任意角色
|
||||
*
|
||||
* @param roles roles
|
||||
* @param userId userId
|
||||
* @param roles roles
|
||||
* @return 是否包含
|
||||
*/
|
||||
boolean hasAnyRole(String... roles);
|
||||
boolean hasAnyRole(Long userId, List<String> roles);
|
||||
|
||||
/**
|
||||
* 检查当前用户是否含有此权限 (有效性判断)
|
||||
* 检查当前用户是否含有此权限
|
||||
*
|
||||
* @param userId userId
|
||||
* @param permission permission
|
||||
* @return 是否包含
|
||||
*/
|
||||
boolean hasPermission(String permission);
|
||||
boolean hasPermission(Long userId, String permission);
|
||||
|
||||
/**
|
||||
* 检查当前用户是否含任意权限 (有效性判断)
|
||||
* 检查当前用户是否含任意权限
|
||||
*
|
||||
* @param userId userId
|
||||
* @param permissions permissions
|
||||
* @return 是否包含
|
||||
*/
|
||||
boolean hasAnyPermission(String... permissions);
|
||||
|
||||
/**
|
||||
* 获取用户菜单
|
||||
*
|
||||
* @return 菜单
|
||||
*/
|
||||
List<SystemMenuVO> getUserMenuList();
|
||||
|
||||
/**
|
||||
* 获取用户权限
|
||||
*
|
||||
* @return 权限信息
|
||||
*/
|
||||
UserPermissionVO getUserPermission();
|
||||
boolean hasAnyPermission(Long userId, List<String> permissions);
|
||||
|
||||
}
|
||||
|
||||
@@ -92,12 +92,4 @@ public interface SystemUserService {
|
||||
*/
|
||||
void resetPassword(UserResetPasswordRequest request);
|
||||
|
||||
/**
|
||||
* 检测用户是否是为管理员
|
||||
*
|
||||
* @param userId userId
|
||||
* @return 是否为管理员
|
||||
*/
|
||||
boolean isAdminUser(Long userId);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.orion.visor.module.infra.service;
|
||||
|
||||
import com.orion.visor.module.infra.entity.domain.SystemRoleDO;
|
||||
import com.orion.visor.module.infra.entity.dto.SystemMenuCacheDTO;
|
||||
import com.orion.visor.module.infra.entity.vo.SystemMenuVO;
|
||||
import com.orion.visor.module.infra.entity.vo.UserPermissionVO;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 用户权限服务
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/7/16 1:03
|
||||
*/
|
||||
public interface UserPermissionService {
|
||||
|
||||
/**
|
||||
* 获取 角色缓存
|
||||
*
|
||||
* @return cache
|
||||
*/
|
||||
Map<Long, SystemRoleDO> getRoleCache();
|
||||
|
||||
/**
|
||||
* 获取 菜单缓存 以作角色权限直接引用
|
||||
*
|
||||
* @return cache
|
||||
*/
|
||||
List<SystemMenuCacheDTO> getMenuCache();
|
||||
|
||||
/**
|
||||
* 获取 角色菜单关联
|
||||
*
|
||||
* @return cache
|
||||
*/
|
||||
Map<Long, List<SystemMenuCacheDTO>> getRoleMenuCache();
|
||||
|
||||
/**
|
||||
* 初始化权限缓存
|
||||
*/
|
||||
void initPermissionCache();
|
||||
|
||||
/**
|
||||
* 检查当前用户是否含有此角色 (有效性判断)
|
||||
*
|
||||
* @param role role
|
||||
* @return 是否包含
|
||||
*/
|
||||
boolean hasRole(String role);
|
||||
|
||||
/**
|
||||
* 检查当前用户是否含有任意角色 (有效性判断)
|
||||
*
|
||||
* @param roles roles
|
||||
* @return 是否包含
|
||||
*/
|
||||
boolean hasAnyRole(String... roles);
|
||||
|
||||
/**
|
||||
* 检查当前用户是否含有此权限 (有效性判断)
|
||||
*
|
||||
* @param permission permission
|
||||
* @return 是否包含
|
||||
*/
|
||||
boolean hasPermission(String permission);
|
||||
|
||||
/**
|
||||
* 检查当前用户是否含任意权限 (有效性判断)
|
||||
*
|
||||
* @param permissions permissions
|
||||
* @return 是否包含
|
||||
*/
|
||||
boolean hasAnyPermission(String... permissions);
|
||||
|
||||
/**
|
||||
* 获取用户菜单
|
||||
*
|
||||
* @return 菜单
|
||||
*/
|
||||
List<SystemMenuVO> getUserMenuList();
|
||||
|
||||
/**
|
||||
* 获取用户权限
|
||||
*
|
||||
* @return 权限信息
|
||||
*/
|
||||
UserPermissionVO getUserPermission();
|
||||
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
package com.orion.visor.module.infra.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.orion.lang.annotation.Keep;
|
||||
import com.orion.lang.define.wrapper.Pair;
|
||||
import com.orion.lang.utils.Exceptions;
|
||||
import com.orion.lang.utils.Strings;
|
||||
import com.orion.lang.utils.collect.Lists;
|
||||
import com.orion.lang.utils.crypto.Signatures;
|
||||
import com.orion.lang.utils.time.Dates;
|
||||
import com.orion.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
||||
import com.orion.visor.framework.common.annotation.Keep;
|
||||
import com.orion.visor.framework.common.constant.Const;
|
||||
import com.orion.visor.framework.common.constant.ErrorMessage;
|
||||
import com.orion.visor.framework.common.constant.ExtraFieldConst;
|
||||
import com.orion.visor.framework.common.security.LoginUser;
|
||||
import com.orion.visor.framework.common.security.UserRole;
|
||||
import com.orion.visor.framework.common.utils.CryptoUtils;
|
||||
@@ -17,30 +20,30 @@ import com.orion.visor.framework.common.utils.Valid;
|
||||
import com.orion.visor.framework.redis.core.utils.RedisStrings;
|
||||
import com.orion.visor.framework.redis.core.utils.RedisUtils;
|
||||
import com.orion.visor.framework.security.core.utils.SecurityUtils;
|
||||
import com.orion.visor.module.infra.api.SystemMessageApi;
|
||||
import com.orion.visor.module.infra.convert.SystemUserConvert;
|
||||
import com.orion.visor.module.infra.dao.SystemUserDAO;
|
||||
import com.orion.visor.module.infra.dao.SystemUserRoleDAO;
|
||||
import com.orion.visor.module.infra.define.cache.UserCacheKeyDefine;
|
||||
import com.orion.visor.module.infra.define.config.AppAuthenticationConfig;
|
||||
import com.orion.visor.module.infra.define.message.SystemUserMessageDefine;
|
||||
import com.orion.visor.module.infra.entity.domain.SystemUserDO;
|
||||
import com.orion.visor.module.infra.entity.dto.LoginTokenDTO;
|
||||
import com.orion.visor.module.infra.entity.dto.LoginTokenIdentityDTO;
|
||||
import com.orion.visor.module.infra.entity.dto.message.SystemMessageDTO;
|
||||
import com.orion.visor.module.infra.entity.request.user.UserLoginRequest;
|
||||
import com.orion.visor.module.infra.entity.vo.UserLoginVO;
|
||||
import com.orion.visor.module.infra.enums.LoginTokenStatusEnum;
|
||||
import com.orion.visor.module.infra.enums.UserStatusEnum;
|
||||
import com.orion.visor.module.infra.service.AuthenticationService;
|
||||
import com.orion.visor.module.infra.service.PermissionService;
|
||||
import com.orion.visor.module.infra.service.UserPermissionService;
|
||||
import com.orion.web.servlet.web.Servlets;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -64,7 +67,10 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
private SystemUserRoleDAO systemUserRoleDAO;
|
||||
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
private UserPermissionService userPermissionService;
|
||||
|
||||
@Resource
|
||||
private SystemMessageApi systemMessageApi;
|
||||
|
||||
@Keep
|
||||
@Resource
|
||||
@@ -72,39 +78,35 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
|
||||
@Override
|
||||
public UserLoginVO login(UserLoginRequest request, HttpServletRequest servletRequest) {
|
||||
// 设置日志上下文的用户 否则登录失败不会记录日志
|
||||
OperatorLogs.setUser(SystemUserConvert.MAPPER.toLoginUser(request));
|
||||
// 登录前检查
|
||||
this.preCheckLogin(request);
|
||||
// 获取登录用户
|
||||
SystemUserDO user = systemUserDAO.of()
|
||||
.createWrapper()
|
||||
.eq(SystemUserDO::getUsername, request.getUsername())
|
||||
.then()
|
||||
.getOne();
|
||||
Valid.notNull(user, ErrorMessage.USERNAME_PASSWORD_ERROR);
|
||||
// 重新设置日志上下文
|
||||
OperatorLogs.setUser(SystemUserConvert.MAPPER.toLoginUser(user));
|
||||
// 检查密码
|
||||
boolean passwordCorrect = this.checkPassword(request, user);
|
||||
Valid.isTrue(passwordCorrect, ErrorMessage.USERNAME_PASSWORD_ERROR);
|
||||
// 检查用户状态
|
||||
UserStatusEnum.checkUserStatus(user.getStatus());
|
||||
// 设置上次登录时间
|
||||
this.setLastLoginTime(user.getId());
|
||||
// 删除用户缓存
|
||||
this.deleteUserCache(user);
|
||||
// 重设用户缓存
|
||||
this.setUserCache(user);
|
||||
// 获取登录信息
|
||||
String remoteAddr = IpUtils.getRemoteAddr(servletRequest);
|
||||
String location = IpUtils.getLocation(remoteAddr);
|
||||
String userAgent = Servlets.getUserAgent(servletRequest);
|
||||
// 设置日志上下文的用户 否则登录失败不会记录日志
|
||||
OperatorLogs.setUser(SystemUserConvert.MAPPER.toLoginUser(request));
|
||||
// 登录前检查
|
||||
SystemUserDO user = this.preCheckLogin(request.getUsername(), request.getPassword());
|
||||
// 重新设置日志上下文
|
||||
OperatorLogs.setUser(SystemUserConvert.MAPPER.toLoginUser(user));
|
||||
// 用户密码校验
|
||||
boolean passRight = this.checkUserPassword(user, request.getPassword(), true);
|
||||
// 发送站内信
|
||||
this.sendLoginFailedErrorMessage(passRight, user, remoteAddr, location);
|
||||
Valid.isTrue(passRight, ErrorMessage.USERNAME_PASSWORD_ERROR);
|
||||
// 用户状态校验
|
||||
this.checkUserStatus(user);
|
||||
Long id = user.getId();
|
||||
// 设置上次登录时间
|
||||
this.setLastLoginTime(id);
|
||||
// 删除用户缓存
|
||||
this.deleteUserCache(user);
|
||||
// 重设用户缓存
|
||||
this.setUserCache(user);
|
||||
long current = System.currentTimeMillis();
|
||||
// 不允许多端登录
|
||||
if (!appAuthenticationConfig.getAllowMultiDevice()) {
|
||||
// 无效化其他缓存
|
||||
this.invalidOtherDeviceToken(user.getId(), current, remoteAddr, location, userAgent);
|
||||
this.invalidOtherDeviceToken(id, current, remoteAddr, location, userAgent);
|
||||
}
|
||||
// 生成 loginToken
|
||||
String token = this.generatorLoginToken(user, current, remoteAddr, location, userAgent);
|
||||
@@ -189,62 +191,83 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
return refresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 token pair
|
||||
*
|
||||
* @param loginToken loginToken
|
||||
* @return pair
|
||||
*/
|
||||
private Pair<Long, Long> getLoginTokenPair(String loginToken) {
|
||||
if (loginToken == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
String value = CryptoUtils.decryptBase62(loginToken);
|
||||
String[] pair = value.split(":");
|
||||
return Pair.of(Long.valueOf(pair[0]), Long.valueOf(pair[1]));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录预检查
|
||||
*
|
||||
* @param request request
|
||||
*/
|
||||
private void preCheckLogin(UserLoginRequest request) {
|
||||
@Override
|
||||
public SystemUserDO preCheckLogin(String username, String password) {
|
||||
// 检查密码长度是否正确 MD5 长度为 32
|
||||
if (request.getPassword().length() != Const.MD5_LEN) {
|
||||
if (password.length() != Const.MD5_LEN) {
|
||||
throw Exceptions.argument(ErrorMessage.USERNAME_PASSWORD_ERROR);
|
||||
}
|
||||
// 检查登录失败次数
|
||||
String failedCountKey = UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(request.getUsername());
|
||||
String failedCountKey = UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(username);
|
||||
String failedCount = redisTemplate.opsForValue().get(failedCountKey);
|
||||
if (failedCount != null
|
||||
&& Integer.parseInt(failedCount) >= appAuthenticationConfig.getLoginFailedLockCount()) {
|
||||
throw Exceptions.argument(ErrorMessage.MAX_LOGIN_FAILED);
|
||||
}
|
||||
// 获取登录用户
|
||||
SystemUserDO user = systemUserDAO.of()
|
||||
.createWrapper()
|
||||
.eq(SystemUserDO::getUsername, username)
|
||||
.then()
|
||||
.getOne();
|
||||
Valid.notNull(user, ErrorMessage.USERNAME_PASSWORD_ERROR);
|
||||
return user;
|
||||
}
|
||||
|
||||
@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, appAuthenticationConfig.getLoginFailedLockTime(), TimeUnit.MINUTES);
|
||||
}
|
||||
return passRight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkUserStatus(SystemUserDO user) {
|
||||
// 检查用户状态
|
||||
UserStatusEnum.checkUserStatus(user.getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查密码
|
||||
* 发送登录失败错误消息
|
||||
*
|
||||
* @param request request
|
||||
* @param user user
|
||||
* @return 是否正确
|
||||
* @param passRight passRight
|
||||
* @param user user
|
||||
* @param remoteAddr remoteAddr
|
||||
* @param location location
|
||||
*/
|
||||
@SuppressWarnings("ALL")
|
||||
private boolean checkPassword(UserLoginRequest request, SystemUserDO user) {
|
||||
// 密码正确
|
||||
if (user.getPassword().equals(Signatures.md5(request.getPassword()))) {
|
||||
return true;
|
||||
private void sendLoginFailedErrorMessage(boolean passRight, SystemUserDO user,
|
||||
String remoteAddr, String location) {
|
||||
if (passRight) {
|
||||
return;
|
||||
}
|
||||
// 刷新登录失败缓存
|
||||
String failedCountKey = UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(request.getUsername());
|
||||
redisTemplate.opsForValue().increment(failedCountKey);
|
||||
RedisUtils.setExpire(failedCountKey, appAuthenticationConfig.getLoginFailedLockTime(), TimeUnit.MINUTES);
|
||||
return false;
|
||||
String failedCountKey = UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(user.getUsername());
|
||||
String failedCountStr = redisTemplate.opsForValue().get(failedCountKey);
|
||||
if (failedCountStr == null || !Strings.isInteger(failedCountStr)) {
|
||||
return;
|
||||
}
|
||||
// 直接用相等 因为只触发一次
|
||||
if (!appAuthenticationConfig.getLoginFailedSendThreshold().equals(Integer.valueOf(failedCountStr))) {
|
||||
return;
|
||||
}
|
||||
// 发送站内信
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put(ExtraFieldConst.ADDRESS, remoteAddr);
|
||||
params.put(ExtraFieldConst.LOCATION, location);
|
||||
params.put(ExtraFieldConst.TIME, Dates.current());
|
||||
SystemMessageDTO message = SystemMessageDTO.builder()
|
||||
.receiverId(user.getId())
|
||||
.receiverUsername(user.getUsername())
|
||||
.relKey(user.getUsername())
|
||||
.params(params)
|
||||
.build();
|
||||
// 发送
|
||||
systemMessageApi.create(SystemUserMessageDefine.LOGIN_FAILED, message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,6 +296,25 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
redisTemplate.delete(Lists.of(userInfoKey, loginFailedCountKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 token pair
|
||||
*
|
||||
* @param loginToken loginToken
|
||||
* @return pair
|
||||
*/
|
||||
private Pair<Long, Long> getLoginTokenPair(String loginToken) {
|
||||
if (loginToken == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
String value = CryptoUtils.decryptBase62(loginToken);
|
||||
String[] pair = value.split(":");
|
||||
return Pair.of(Long.valueOf(pair[0]), Long.valueOf(pair[1]));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户缓存
|
||||
*
|
||||
@@ -283,7 +325,7 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
Long id = user.getId();
|
||||
// 查询用户角色
|
||||
List<Long> roleIds = systemUserRoleDAO.selectRoleIdByUserId(id);
|
||||
List<UserRole> roleList = permissionService.getRoleCache()
|
||||
List<UserRole> roleList = userPermissionService.getRoleCache()
|
||||
.values()
|
||||
.stream()
|
||||
.filter(s -> roleIds.contains(s.getId()))
|
||||
|
||||
@@ -1,305 +1,67 @@
|
||||
package com.orion.visor.module.infra.service.impl;
|
||||
|
||||
import com.orion.lang.utils.Arrays1;
|
||||
import com.orion.lang.utils.collect.Lists;
|
||||
import com.orion.lang.utils.collect.Maps;
|
||||
import com.orion.visor.framework.common.constant.Const;
|
||||
import com.orion.visor.framework.common.security.LoginUser;
|
||||
import com.orion.visor.framework.common.security.UserRole;
|
||||
import com.orion.visor.framework.security.core.utils.SecurityUtils;
|
||||
import com.orion.visor.module.infra.convert.SystemMenuConvert;
|
||||
import com.orion.visor.module.infra.convert.SystemUserConvert;
|
||||
import com.orion.visor.module.infra.dao.SystemMenuDAO;
|
||||
import com.orion.visor.module.infra.dao.SystemRoleDAO;
|
||||
import com.orion.visor.module.infra.dao.SystemRoleMenuDAO;
|
||||
import com.orion.visor.module.infra.define.RoleDefine;
|
||||
import com.orion.visor.module.infra.entity.domain.SystemMenuDO;
|
||||
import com.orion.visor.module.infra.entity.domain.SystemRoleDO;
|
||||
import com.orion.visor.module.infra.entity.domain.SystemRoleMenuDO;
|
||||
import com.orion.visor.module.infra.entity.dto.SystemMenuCacheDTO;
|
||||
import com.orion.visor.module.infra.entity.vo.SystemMenuVO;
|
||||
import com.orion.visor.module.infra.entity.vo.UserCollectInfoVO;
|
||||
import com.orion.visor.module.infra.entity.vo.UserPermissionVO;
|
||||
import com.orion.visor.module.infra.enums.MenuStatusEnum;
|
||||
import com.orion.visor.module.infra.enums.MenuTypeEnum;
|
||||
import com.orion.visor.module.infra.enums.PreferenceTypeEnum;
|
||||
import com.orion.visor.module.infra.enums.RoleStatusEnum;
|
||||
import com.orion.visor.module.infra.service.PermissionService;
|
||||
import com.orion.visor.module.infra.service.PreferenceService;
|
||||
import com.orion.visor.module.infra.service.SystemMenuService;
|
||||
import com.orion.visor.module.infra.service.TipsService;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Function;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 权限服务
|
||||
* 权限 服务实现类
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/7/16 1:05
|
||||
* @since 2024/8/19 15:29
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class PermissionServiceImpl implements PermissionService {
|
||||
|
||||
@Getter
|
||||
private final Map<Long, SystemRoleDO> roleCache = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
private final List<SystemMenuCacheDTO> menuCache = new ArrayList<>();
|
||||
|
||||
@Getter
|
||||
private final Map<Long, List<SystemMenuCacheDTO>> roleMenuCache = new HashMap<>();
|
||||
|
||||
@Resource
|
||||
private SystemRoleDAO systemRoleDAO;
|
||||
|
||||
@Resource
|
||||
private SystemMenuDAO systemMenuDAO;
|
||||
|
||||
@Resource
|
||||
private SystemRoleMenuDAO systemRoleMenuDAO;
|
||||
|
||||
@Resource
|
||||
private SystemMenuService systemMenuService;
|
||||
|
||||
@Resource
|
||||
private PreferenceService preferenceService;
|
||||
|
||||
@Resource
|
||||
private TipsService tipsService;
|
||||
|
||||
@PostConstruct
|
||||
@Override
|
||||
public void initPermissionCache() {
|
||||
long start = System.currentTimeMillis();
|
||||
log.info("initPermissionCache-start");
|
||||
roleCache.clear();
|
||||
menuCache.clear();
|
||||
roleMenuCache.clear();
|
||||
// 加载所有角色
|
||||
List<SystemRoleDO> roles = systemRoleDAO.selectList(null);
|
||||
for (SystemRoleDO role : roles) {
|
||||
roleCache.put(role.getId(), role);
|
||||
}
|
||||
// 加载所有菜单信息
|
||||
List<SystemMenuDO> menuList = systemMenuDAO.selectList(null);
|
||||
List<SystemMenuCacheDTO> menus = SystemMenuConvert.MAPPER.toCache(menuList);
|
||||
Map<Long, SystemMenuCacheDTO> menuMapping = menus.stream()
|
||||
.collect(Collectors.toMap(SystemMenuCacheDTO::getId, Function.identity()));
|
||||
menuCache.addAll(menus);
|
||||
// 查询所有角色菜单
|
||||
systemRoleMenuDAO.selectList(null)
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(SystemRoleMenuDO::getRoleId,
|
||||
Collectors.mapping(SystemRoleMenuDO::getMenuId, Collectors.toList())))
|
||||
.forEach((roleId, menuIdList) -> {
|
||||
// 获取菜单引用
|
||||
List<SystemMenuCacheDTO> roleMenus = menuIdList.stream()
|
||||
.map(menuMapping::get)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
// 获取角色引用
|
||||
roleMenuCache.put(roleId, roleMenus);
|
||||
});
|
||||
log.info("initPermissionCache-end used: {}ms", System.currentTimeMillis() - start);
|
||||
public boolean isAdminUser(Long userId) {
|
||||
return this.hasAnyRole(userId, Lists.of(RoleDefine.ADMIN_CODE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRole(String role) {
|
||||
// 获取用户角色
|
||||
Map<Long, String> roles = this.getUserEnabledRoles();
|
||||
public boolean hasRole(Long userId, String role) {
|
||||
return this.hasAnyRole(userId, Lists.of(role));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnyRole(Long userId, List<String> roles) {
|
||||
return !systemRoleDAO.getRoleIdByUserIdAndRoleCode(userId, roles).isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Long userId, String permission) {
|
||||
return this.hasAnyPermission(userId, Lists.singleton(permission));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnyPermission(Long userId, List<String> permissions) {
|
||||
// 查询用户角色
|
||||
List<SystemRoleDO> roles = systemRoleDAO.selectRoleByUserId(userId);
|
||||
roles.removeIf(s -> !RoleStatusEnum.ENABLED.getStatus().equals(s.getStatus()));
|
||||
if (roles.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// 检查是否为超级管理员或包含此角色
|
||||
return RoleDefine.containsAdmin(roles.values()) || roles.containsValue(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnyRole(String... roles) {
|
||||
if (Arrays1.isEmpty(roles)) {
|
||||
// 判断是否为 admin
|
||||
boolean isAdmin = roles.stream().anyMatch(s -> s.getCode().equals(RoleDefine.ADMIN_CODE));
|
||||
if (isAdmin) {
|
||||
return true;
|
||||
}
|
||||
// 获取用户角色
|
||||
Map<Long, String> enableRoles = this.getUserEnabledRoles();
|
||||
if (enableRoles.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// 检查是否为超级管理员 || 有此角色
|
||||
return RoleDefine.containsAdmin(enableRoles.values())
|
||||
|| Arrays.stream(roles).anyMatch(enableRoles::containsValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
// 获取用户角色
|
||||
Map<Long, String> roles = this.getUserEnabledRoles();
|
||||
if (roles.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// 检查是否为超级管理员
|
||||
if (RoleDefine.containsAdmin(roles.values())) {
|
||||
return true;
|
||||
}
|
||||
// 检查普通角色是否有此权限
|
||||
return roles.keySet()
|
||||
.stream()
|
||||
.anyMatch(s -> this.checkRoleHasPermission(s, permission));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnyPermission(String... permissions) {
|
||||
if (Arrays1.isEmpty(permissions)) {
|
||||
return true;
|
||||
}
|
||||
// 获取用户角色
|
||||
Map<Long, String> roles = this.getUserEnabledRoles();
|
||||
if (roles.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// 检查是否为超级管理员
|
||||
if (RoleDefine.containsAdmin(roles.values())) {
|
||||
return true;
|
||||
}
|
||||
// 检查用户角色是否包含权限
|
||||
return Arrays.stream(permissions)
|
||||
.anyMatch(perm -> roles.keySet()
|
||||
.stream()
|
||||
.anyMatch(s -> this.checkRoleHasPermission(s, perm)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SystemMenuVO> getUserMenuList() {
|
||||
// 获取用户角色
|
||||
Map<Long, String> roles = this.getUserEnabledRoles();
|
||||
if (roles.isEmpty()) {
|
||||
return Lists.empty();
|
||||
}
|
||||
// 查询角色菜单
|
||||
Stream<SystemMenuCacheDTO> mergeStream;
|
||||
if (RoleDefine.containsAdmin(roles.values())) {
|
||||
// 管理员拥有全部菜单
|
||||
mergeStream = menuCache.stream();
|
||||
} else {
|
||||
// 当前用户所适配的角色菜单
|
||||
mergeStream = roles.keySet()
|
||||
.stream()
|
||||
.map(roleMenuCache::get)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.distinct();
|
||||
}
|
||||
// 状态过滤
|
||||
List<SystemMenuVO> menus = mergeStream
|
||||
.filter(s -> MenuStatusEnum.ENABLED.getStatus().equals(s.getStatus()))
|
||||
.filter(s -> !MenuTypeEnum.FUNCTION.getType().equals(s.getType()))
|
||||
.map(SystemMenuConvert.MAPPER::to)
|
||||
List<Long> roleIdList = roles.stream()
|
||||
.map(SystemRoleDO::getId)
|
||||
.collect(Collectors.toList());
|
||||
// 构建菜单树
|
||||
return systemMenuService.buildSystemMenuTree(menus);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public UserPermissionVO getUserPermission() {
|
||||
// 获取用户信息
|
||||
UserCollectInfoVO user = SystemUserConvert.MAPPER.toCollectInfo(SecurityUtils.getLoginUser());
|
||||
Long id = user.getId();
|
||||
// 获取用户系统偏好
|
||||
Future<Map<String, Object>> systemPreference = preferenceService.getPreferenceAsync(id, PreferenceTypeEnum.SYSTEM);
|
||||
// 获取用户角色
|
||||
Map<Long, String> roles = this.getUserEnabledRoles();
|
||||
// 获取用户权限
|
||||
List<String> permissions;
|
||||
if (roles.isEmpty()) {
|
||||
permissions = Lists.empty();
|
||||
} else {
|
||||
if (RoleDefine.containsAdmin(roles.values())) {
|
||||
// 管理员拥有全部权限
|
||||
permissions = Lists.of(Const.ASTERISK);
|
||||
} else {
|
||||
// 当前用户所适配的角色的权限
|
||||
permissions = roles.keySet()
|
||||
.stream()
|
||||
.map(roleMenuCache::get)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(s -> MenuStatusEnum.ENABLED.getStatus().equals(s.getStatus()))
|
||||
.map(SystemMenuCacheDTO::getPermission)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
// 设置已提示的 key
|
||||
user.setTippedKeys(tipsService.getTippedKeys());
|
||||
// 获取异步结果
|
||||
user.setSystemPreference(systemPreference.get());
|
||||
// 组装数据
|
||||
return UserPermissionVO.builder()
|
||||
.user(user)
|
||||
.roles(roles.values())
|
||||
.permissions(permissions)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查角色是否有权限
|
||||
*
|
||||
* @param roleId roleId
|
||||
* @param permission permission
|
||||
* @return 是否有权限
|
||||
*/
|
||||
private boolean checkRoleHasPermission(Long roleId, String permission) {
|
||||
// 获取角色权限列表
|
||||
List<SystemMenuCacheDTO> menus = roleMenuCache.get(roleId);
|
||||
if (Lists.isEmpty(menus)) {
|
||||
return false;
|
||||
}
|
||||
// 检查是否有此权限
|
||||
return menus.stream()
|
||||
.filter(s -> MenuStatusEnum.ENABLED.getStatus().equals(s.getStatus()))
|
||||
.map(SystemMenuCacheDTO::getPermission)
|
||||
.filter(Objects::nonNull)
|
||||
.anyMatch(permission::equals);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户启用的角色
|
||||
*
|
||||
* @return roles
|
||||
*/
|
||||
private Map<Long, String> getUserEnabledRoles() {
|
||||
// 获取当前用户角色
|
||||
List<UserRole> userRoles = Optional.ofNullable(SecurityUtils.getLoginUser())
|
||||
.map(LoginUser::getRoles)
|
||||
.orElse(Lists.empty());
|
||||
if (Lists.isEmpty(userRoles)) {
|
||||
return Maps.empty();
|
||||
}
|
||||
// 获取角色编码
|
||||
Map<Long, String> roles = userRoles.stream()
|
||||
.map(UserRole::getId)
|
||||
.map(roleCache::get)
|
||||
.filter(Objects::nonNull)
|
||||
// 过滤未启用的角色
|
||||
.filter(r -> RoleStatusEnum.ENABLED.getStatus().equals(r.getStatus()))
|
||||
.collect(Collectors.toMap(SystemRoleDO::getId, SystemRoleDO::getCode));
|
||||
if (Maps.isEmpty(roles)) {
|
||||
return Maps.empty();
|
||||
}
|
||||
return roles;
|
||||
return !systemRoleDAO.getPermissionByRoleIdAndPermission(roleIdList, permissions).isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import com.orion.visor.module.infra.entity.vo.SystemMenuVO;
|
||||
import com.orion.visor.module.infra.enums.MenuStatusEnum;
|
||||
import com.orion.visor.module.infra.enums.MenuTypeEnum;
|
||||
import com.orion.visor.module.infra.enums.MenuVisibleEnum;
|
||||
import com.orion.visor.module.infra.service.PermissionService;
|
||||
import com.orion.visor.module.infra.service.UserPermissionService;
|
||||
import com.orion.visor.module.infra.service.SystemMenuService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
@@ -51,7 +51,7 @@ public class SystemMenuServiceImpl implements SystemMenuService {
|
||||
private SystemRoleMenuDAO systemRoleMenuDAO;
|
||||
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
private UserPermissionService userPermissionService;
|
||||
|
||||
@Override
|
||||
public Long createSystemMenu(SystemMenuCreateRequest request) {
|
||||
@@ -68,7 +68,7 @@ public class SystemMenuServiceImpl implements SystemMenuService {
|
||||
int effect = systemMenuDAO.insert(record);
|
||||
log.info("SystemMenuService-createSystemMenu effect: {}, record: {}", effect, JSON.toJSONString(record));
|
||||
// 保存至缓存
|
||||
List<SystemMenuCacheDTO> menuCache = permissionService.getMenuCache();
|
||||
List<SystemMenuCacheDTO> menuCache = userPermissionService.getMenuCache();
|
||||
menuCache.add(SystemMenuConvert.MAPPER.toCache(record));
|
||||
return record.getId();
|
||||
}
|
||||
@@ -89,7 +89,7 @@ public class SystemMenuServiceImpl implements SystemMenuService {
|
||||
// 重新查询转换为缓存
|
||||
SystemMenuCacheDTO cache = SystemMenuConvert.MAPPER.toCache(systemMenuDAO.selectById(id));
|
||||
// 获取原始缓存
|
||||
permissionService.getMenuCache()
|
||||
userPermissionService.getMenuCache()
|
||||
.stream()
|
||||
.filter(s -> s.getId().equals(id))
|
||||
.findFirst()
|
||||
@@ -115,7 +115,7 @@ public class SystemMenuServiceImpl implements SystemMenuService {
|
||||
Integer type = request.getType();
|
||||
Integer status = request.getStatus();
|
||||
// 从缓存中查询
|
||||
List<SystemMenuVO> menus = permissionService.getMenuCache()
|
||||
List<SystemMenuVO> menus = userPermissionService.getMenuCache()
|
||||
.stream()
|
||||
.filter(s -> Strings.isBlank(name) || s.getName().contains(name))
|
||||
.filter(s -> type == null || s.getType().equals(type))
|
||||
@@ -197,7 +197,7 @@ public class SystemMenuServiceImpl implements SystemMenuService {
|
||||
// 添加日志参数
|
||||
OperatorLogs.add(OperatorLogs.NAME, record.getName());
|
||||
// 从缓存中查询
|
||||
List<SystemMenuCacheDTO> cache = permissionService.getMenuCache();
|
||||
List<SystemMenuCacheDTO> cache = userPermissionService.getMenuCache();
|
||||
// 获取要更新的id
|
||||
List<Long> updateIdList = this.getChildrenIdList(id, cache, record.getType());
|
||||
// 修改状态
|
||||
@@ -229,7 +229,7 @@ public class SystemMenuServiceImpl implements SystemMenuService {
|
||||
// 添加日志参数
|
||||
OperatorLogs.add(OperatorLogs.NAME, record.getName());
|
||||
// 从缓存中查询
|
||||
List<SystemMenuCacheDTO> cache = permissionService.getMenuCache();
|
||||
List<SystemMenuCacheDTO> cache = userPermissionService.getMenuCache();
|
||||
// 获取要删除的id
|
||||
List<Long> deletedIdList = this.getChildrenIdList(id, cache, record.getType());
|
||||
// 删除菜单
|
||||
@@ -239,7 +239,7 @@ public class SystemMenuServiceImpl implements SystemMenuService {
|
||||
// 删除菜单缓存
|
||||
cache.removeIf(s -> deletedIdList.contains(s.getId()));
|
||||
// 删除引用缓存
|
||||
permissionService.getRoleMenuCache()
|
||||
userPermissionService.getRoleMenuCache()
|
||||
.values()
|
||||
.forEach(roleMenus -> roleMenus.removeIf(s -> deletedIdList.contains(s.getId())));
|
||||
log.info("SystemMenuService-deleteSystemMenu deletedIdList: {}, effect: {}", deletedIdList, effect);
|
||||
|
||||
@@ -16,7 +16,7 @@ import com.orion.visor.module.infra.entity.domain.SystemRoleDO;
|
||||
import com.orion.visor.module.infra.entity.domain.SystemRoleMenuDO;
|
||||
import com.orion.visor.module.infra.entity.dto.SystemMenuCacheDTO;
|
||||
import com.orion.visor.module.infra.entity.request.menu.SystemRoleGrantMenuRequest;
|
||||
import com.orion.visor.module.infra.service.PermissionService;
|
||||
import com.orion.visor.module.infra.service.UserPermissionService;
|
||||
import com.orion.visor.module.infra.service.SystemRoleMenuService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -49,7 +49,7 @@ public class SystemRoleMenuServiceImpl implements SystemRoleMenuService {
|
||||
private SystemRoleMenuDAO systemRoleMenuDAO;
|
||||
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
private UserPermissionService userPermissionService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@@ -104,7 +104,7 @@ public class SystemRoleMenuServiceImpl implements SystemRoleMenuService {
|
||||
effect += insertMenuIdList.size();
|
||||
}
|
||||
// 更新缓存
|
||||
Map<Long, List<SystemMenuCacheDTO>> cache = permissionService.getRoleMenuCache();
|
||||
Map<Long, List<SystemMenuCacheDTO>> cache = userPermissionService.getRoleMenuCache();
|
||||
List<SystemMenuCacheDTO> roleCache = cache.computeIfAbsent(roleId, s -> new ArrayList<>());
|
||||
roleCache.clear();
|
||||
roleCache.addAll(SystemMenuConvert.MAPPER.toCache(menuList));
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.orion.visor.module.infra.entity.request.role.SystemRoleUpdateRequest;
|
||||
import com.orion.visor.module.infra.entity.vo.SystemRoleVO;
|
||||
import com.orion.visor.module.infra.enums.RoleStatusEnum;
|
||||
import com.orion.visor.module.infra.service.DataPermissionService;
|
||||
import com.orion.visor.module.infra.service.PermissionService;
|
||||
import com.orion.visor.module.infra.service.UserPermissionService;
|
||||
import com.orion.visor.module.infra.service.SystemRoleService;
|
||||
import com.orion.visor.module.infra.service.SystemUserRoleService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -51,7 +51,7 @@ public class SystemRoleServiceImpl implements SystemRoleService {
|
||||
private SystemRoleMenuDAO systemRoleMenuDAO;
|
||||
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
private UserPermissionService userPermissionService;
|
||||
|
||||
@Resource
|
||||
private SystemUserRoleService systemUserRoleService;
|
||||
@@ -72,7 +72,7 @@ public class SystemRoleServiceImpl implements SystemRoleService {
|
||||
int effect = systemRoleDAO.insert(record);
|
||||
log.info("SystemRoleService-createSystemRole effect: {}, domain: {}", effect, JSON.toJSONString(record));
|
||||
// 设置到缓存
|
||||
permissionService.getRoleCache().put(record.getId(), record);
|
||||
userPermissionService.getRoleCache().put(record.getId(), record);
|
||||
return record.getId();
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public class SystemRoleServiceImpl implements SystemRoleService {
|
||||
int effect = systemRoleDAO.updateById(updateRecord);
|
||||
log.info("SystemRoleService-updateSystemRoleById effect: {}, updateRecord: {}", effect, JSON.toJSONString(updateRecord));
|
||||
// 设置到缓存
|
||||
SystemRoleDO roleCache = permissionService.getRoleCache().get(id);
|
||||
SystemRoleDO roleCache = userPermissionService.getRoleCache().get(id);
|
||||
roleCache.setName(updateRecord.getName());
|
||||
return effect;
|
||||
}
|
||||
@@ -117,7 +117,7 @@ public class SystemRoleServiceImpl implements SystemRoleService {
|
||||
int effect = systemRoleDAO.updateById(updateRecord);
|
||||
log.info("SystemRoleService-updateRoleStatus effect: {}, updateRecord: {}", effect, JSON.toJSONString(updateRecord));
|
||||
// 修改本地缓存状态
|
||||
SystemRoleDO roleCache = permissionService.getRoleCache().get(id);
|
||||
SystemRoleDO roleCache = userPermissionService.getRoleCache().get(id);
|
||||
roleCache.setStatus(status);
|
||||
// 删除数据权限缓存
|
||||
dataPermissionService.clearRoleCache(id);
|
||||
@@ -180,9 +180,9 @@ public class SystemRoleServiceImpl implements SystemRoleService {
|
||||
// 删除角色菜单关联
|
||||
effect += systemRoleMenuDAO.deleteByRoleId(id);
|
||||
// 删除角色缓存
|
||||
permissionService.getRoleCache().remove(id);
|
||||
userPermissionService.getRoleCache().remove(id);
|
||||
// 删除菜单缓存
|
||||
permissionService.getRoleMenuCache().remove(id);
|
||||
userPermissionService.getRoleMenuCache().remove(id);
|
||||
// 删除用户缓存中的角色
|
||||
systemUserRoleService.deleteUserCacheRoleAsync(id, userIdList);
|
||||
// 删除数据权限缓存
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.orion.visor.module.infra.dao.OperatorLogDAO;
|
||||
import com.orion.visor.module.infra.dao.SystemRoleDAO;
|
||||
import com.orion.visor.module.infra.dao.SystemUserDAO;
|
||||
import com.orion.visor.module.infra.dao.SystemUserRoleDAO;
|
||||
import com.orion.visor.module.infra.define.RoleDefine;
|
||||
import com.orion.visor.module.infra.define.cache.TipsCacheKeyDefine;
|
||||
import com.orion.visor.module.infra.define.cache.UserCacheKeyDefine;
|
||||
import com.orion.visor.module.infra.define.config.AppAuthenticationConfig;
|
||||
@@ -302,11 +301,6 @@ public class SystemUserServiceImpl implements SystemUserService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdminUser(Long userId) {
|
||||
return systemRoleDAO.getRoleIdByUserIdAndRoleCode(userId, RoleDefine.ADMIN_CODE) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户名否存在
|
||||
*
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
package com.orion.visor.module.infra.service.impl;
|
||||
|
||||
import com.orion.lang.utils.Arrays1;
|
||||
import com.orion.lang.utils.collect.Lists;
|
||||
import com.orion.lang.utils.collect.Maps;
|
||||
import com.orion.visor.framework.common.constant.Const;
|
||||
import com.orion.visor.framework.common.security.LoginUser;
|
||||
import com.orion.visor.framework.common.security.UserRole;
|
||||
import com.orion.visor.framework.security.core.utils.SecurityUtils;
|
||||
import com.orion.visor.module.infra.convert.SystemMenuConvert;
|
||||
import com.orion.visor.module.infra.convert.SystemUserConvert;
|
||||
import com.orion.visor.module.infra.dao.SystemMenuDAO;
|
||||
import com.orion.visor.module.infra.dao.SystemRoleDAO;
|
||||
import com.orion.visor.module.infra.dao.SystemRoleMenuDAO;
|
||||
import com.orion.visor.module.infra.define.RoleDefine;
|
||||
import com.orion.visor.module.infra.entity.domain.SystemMenuDO;
|
||||
import com.orion.visor.module.infra.entity.domain.SystemRoleDO;
|
||||
import com.orion.visor.module.infra.entity.domain.SystemRoleMenuDO;
|
||||
import com.orion.visor.module.infra.entity.dto.SystemMenuCacheDTO;
|
||||
import com.orion.visor.module.infra.entity.vo.SystemMenuVO;
|
||||
import com.orion.visor.module.infra.entity.vo.UserCollectInfoVO;
|
||||
import com.orion.visor.module.infra.entity.vo.UserPermissionVO;
|
||||
import com.orion.visor.module.infra.enums.MenuStatusEnum;
|
||||
import com.orion.visor.module.infra.enums.MenuTypeEnum;
|
||||
import com.orion.visor.module.infra.enums.PreferenceTypeEnum;
|
||||
import com.orion.visor.module.infra.enums.RoleStatusEnum;
|
||||
import com.orion.visor.module.infra.service.PreferenceService;
|
||||
import com.orion.visor.module.infra.service.SystemMenuService;
|
||||
import com.orion.visor.module.infra.service.TipsService;
|
||||
import com.orion.visor.module.infra.service.UserPermissionService;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 用户权限服务
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/7/16 1:05
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class UserPermissionServiceImpl implements UserPermissionService {
|
||||
|
||||
@Getter
|
||||
private final Map<Long, SystemRoleDO> roleCache = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
private final List<SystemMenuCacheDTO> menuCache = new ArrayList<>();
|
||||
|
||||
@Getter
|
||||
private final Map<Long, List<SystemMenuCacheDTO>> roleMenuCache = new HashMap<>();
|
||||
|
||||
@Resource
|
||||
private SystemRoleDAO systemRoleDAO;
|
||||
|
||||
@Resource
|
||||
private SystemMenuDAO systemMenuDAO;
|
||||
|
||||
@Resource
|
||||
private SystemRoleMenuDAO systemRoleMenuDAO;
|
||||
|
||||
@Resource
|
||||
private SystemMenuService systemMenuService;
|
||||
|
||||
@Resource
|
||||
private PreferenceService preferenceService;
|
||||
|
||||
@Resource
|
||||
private TipsService tipsService;
|
||||
|
||||
@PostConstruct
|
||||
@Override
|
||||
public void initPermissionCache() {
|
||||
long start = System.currentTimeMillis();
|
||||
log.info("initPermissionCache-start");
|
||||
roleCache.clear();
|
||||
menuCache.clear();
|
||||
roleMenuCache.clear();
|
||||
// 加载所有角色
|
||||
List<SystemRoleDO> roles = systemRoleDAO.selectList(null);
|
||||
for (SystemRoleDO role : roles) {
|
||||
roleCache.put(role.getId(), role);
|
||||
}
|
||||
// 加载所有菜单信息
|
||||
List<SystemMenuDO> menuList = systemMenuDAO.selectList(null);
|
||||
List<SystemMenuCacheDTO> menus = SystemMenuConvert.MAPPER.toCache(menuList);
|
||||
Map<Long, SystemMenuCacheDTO> menuMapping = menus.stream()
|
||||
.collect(Collectors.toMap(SystemMenuCacheDTO::getId, Function.identity()));
|
||||
menuCache.addAll(menus);
|
||||
// 查询所有角色菜单
|
||||
systemRoleMenuDAO.selectList(null)
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(SystemRoleMenuDO::getRoleId,
|
||||
Collectors.mapping(SystemRoleMenuDO::getMenuId, Collectors.toList())))
|
||||
.forEach((roleId, menuIdList) -> {
|
||||
// 获取菜单引用
|
||||
List<SystemMenuCacheDTO> roleMenus = menuIdList.stream()
|
||||
.map(menuMapping::get)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
// 获取角色引用
|
||||
roleMenuCache.put(roleId, roleMenus);
|
||||
});
|
||||
log.info("initPermissionCache-end used: {}ms", System.currentTimeMillis() - start);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRole(String role) {
|
||||
// 获取用户角色
|
||||
Map<Long, String> roles = this.getUserEnabledRoles();
|
||||
if (roles.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// 检查是否为超级管理员或包含此角色
|
||||
return RoleDefine.containsAdmin(roles.values()) || roles.containsValue(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnyRole(String... roles) {
|
||||
if (Arrays1.isEmpty(roles)) {
|
||||
return true;
|
||||
}
|
||||
// 获取用户角色
|
||||
Map<Long, String> enableRoles = this.getUserEnabledRoles();
|
||||
if (enableRoles.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// 检查是否为超级管理员 || 有此角色
|
||||
return RoleDefine.containsAdmin(enableRoles.values())
|
||||
|| Arrays.stream(roles).anyMatch(enableRoles::containsValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
// 获取用户角色
|
||||
Map<Long, String> roles = this.getUserEnabledRoles();
|
||||
if (roles.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// 检查是否为超级管理员
|
||||
if (RoleDefine.containsAdmin(roles.values())) {
|
||||
return true;
|
||||
}
|
||||
// 检查普通角色是否有此权限
|
||||
return roles.keySet()
|
||||
.stream()
|
||||
.anyMatch(s -> this.checkRoleHasPermission(s, permission));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnyPermission(String... permissions) {
|
||||
if (Arrays1.isEmpty(permissions)) {
|
||||
return true;
|
||||
}
|
||||
// 获取用户角色
|
||||
Map<Long, String> roles = this.getUserEnabledRoles();
|
||||
if (roles.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// 检查是否为超级管理员
|
||||
if (RoleDefine.containsAdmin(roles.values())) {
|
||||
return true;
|
||||
}
|
||||
// 检查用户角色是否包含权限
|
||||
return Arrays.stream(permissions)
|
||||
.anyMatch(perm -> roles.keySet()
|
||||
.stream()
|
||||
.anyMatch(s -> this.checkRoleHasPermission(s, perm)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SystemMenuVO> getUserMenuList() {
|
||||
// 获取用户角色
|
||||
Map<Long, String> roles = this.getUserEnabledRoles();
|
||||
if (roles.isEmpty()) {
|
||||
return Lists.empty();
|
||||
}
|
||||
// 查询角色菜单
|
||||
Stream<SystemMenuCacheDTO> mergeStream;
|
||||
if (RoleDefine.containsAdmin(roles.values())) {
|
||||
// 管理员拥有全部菜单
|
||||
mergeStream = menuCache.stream();
|
||||
} else {
|
||||
// 当前用户所适配的角色菜单
|
||||
mergeStream = roles.keySet()
|
||||
.stream()
|
||||
.map(roleMenuCache::get)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.distinct();
|
||||
}
|
||||
// 状态过滤
|
||||
List<SystemMenuVO> menus = mergeStream
|
||||
.filter(s -> MenuStatusEnum.ENABLED.getStatus().equals(s.getStatus()))
|
||||
.filter(s -> !MenuTypeEnum.FUNCTION.getType().equals(s.getType()))
|
||||
.map(SystemMenuConvert.MAPPER::to)
|
||||
.collect(Collectors.toList());
|
||||
// 构建菜单树
|
||||
return systemMenuService.buildSystemMenuTree(menus);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public UserPermissionVO getUserPermission() {
|
||||
// 获取用户信息
|
||||
UserCollectInfoVO user = SystemUserConvert.MAPPER.toCollectInfo(SecurityUtils.getLoginUser());
|
||||
Long id = user.getId();
|
||||
// 获取用户系统偏好
|
||||
Future<Map<String, Object>> systemPreference = preferenceService.getPreferenceAsync(id, PreferenceTypeEnum.SYSTEM);
|
||||
// 获取用户角色
|
||||
Map<Long, String> roles = this.getUserEnabledRoles();
|
||||
// 获取用户权限
|
||||
List<String> permissions;
|
||||
if (roles.isEmpty()) {
|
||||
permissions = Lists.empty();
|
||||
} else {
|
||||
if (RoleDefine.containsAdmin(roles.values())) {
|
||||
// 管理员拥有全部权限
|
||||
permissions = Lists.of(Const.ASTERISK);
|
||||
} else {
|
||||
// 当前用户所适配的角色的权限
|
||||
permissions = roles.keySet()
|
||||
.stream()
|
||||
.map(roleMenuCache::get)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(s -> MenuStatusEnum.ENABLED.getStatus().equals(s.getStatus()))
|
||||
.map(SystemMenuCacheDTO::getPermission)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
// 设置已提示的 key
|
||||
user.setTippedKeys(tipsService.getTippedKeys());
|
||||
// 获取异步结果
|
||||
user.setSystemPreference(systemPreference.get());
|
||||
// 组装数据
|
||||
return UserPermissionVO.builder()
|
||||
.user(user)
|
||||
.roles(roles.values())
|
||||
.permissions(permissions)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查角色是否有权限
|
||||
*
|
||||
* @param roleId roleId
|
||||
* @param permission permission
|
||||
* @return 是否有权限
|
||||
*/
|
||||
private boolean checkRoleHasPermission(Long roleId, String permission) {
|
||||
// 获取角色权限列表
|
||||
List<SystemMenuCacheDTO> menus = roleMenuCache.get(roleId);
|
||||
if (Lists.isEmpty(menus)) {
|
||||
return false;
|
||||
}
|
||||
// 检查是否有此权限
|
||||
return menus.stream()
|
||||
.filter(s -> MenuStatusEnum.ENABLED.getStatus().equals(s.getStatus()))
|
||||
.map(SystemMenuCacheDTO::getPermission)
|
||||
.filter(Objects::nonNull)
|
||||
.anyMatch(permission::equals);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户启用的角色
|
||||
*
|
||||
* @return roles
|
||||
*/
|
||||
private Map<Long, String> getUserEnabledRoles() {
|
||||
// 获取当前用户角色
|
||||
List<UserRole> userRoles = Optional.ofNullable(SecurityUtils.getLoginUser())
|
||||
.map(LoginUser::getRoles)
|
||||
.orElse(Lists.empty());
|
||||
if (Lists.isEmpty(userRoles)) {
|
||||
return Maps.empty();
|
||||
}
|
||||
// 获取角色编码
|
||||
Map<Long, String> roles = userRoles.stream()
|
||||
.map(UserRole::getId)
|
||||
.map(roleCache::get)
|
||||
.filter(Objects::nonNull)
|
||||
// 过滤未启用的角色
|
||||
.filter(r -> RoleStatusEnum.ENABLED.getStatus().equals(r.getStatus()))
|
||||
.collect(Collectors.toMap(SystemRoleDO::getId, SystemRoleDO::getCode));
|
||||
if (Maps.isEmpty(roles)) {
|
||||
return Maps.empty();
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,6 +22,11 @@
|
||||
"type": "java.lang.Integer",
|
||||
"description": "凭证续签最大次数."
|
||||
},
|
||||
{
|
||||
"name": "app.authentication.loginFailedSendThreshold",
|
||||
"type": "java.lang.Integer",
|
||||
"description": "登录失败发送站内信阈值."
|
||||
},
|
||||
{
|
||||
"name": "app.authentication.loginFailedLockCount",
|
||||
"type": "java.lang.Integer",
|
||||
|
||||
@@ -24,12 +24,42 @@
|
||||
SELECT role_id
|
||||
FROM system_user_role
|
||||
WHERE user_id = #{userId}
|
||||
AND deleted = 0
|
||||
AND role_id IN (SELECT id FROM system_role WHERE CODE = #{code} AND deleted = 0) LIMIT 1
|
||||
AND deleted = 0
|
||||
AND role_id IN
|
||||
(SELECT id
|
||||
FROM system_role
|
||||
WHERE deleted = 0
|
||||
AND status = 1
|
||||
AND code IN
|
||||
<foreach collection="codeList" item="item" open="(" close=")" separator=",">
|
||||
#{item}
|
||||
</foreach>
|
||||
)
|
||||
</select>
|
||||
|
||||
<select id="getPermissionByRoleIdAndPermission" resultType="java.lang.String">
|
||||
SELECT m.permission
|
||||
FROM system_menu m
|
||||
LEFT JOIN system_role_menu rm ON rm.menu_id = m.id
|
||||
WHERE rm.deleted = 0
|
||||
AND m.deleted = 0
|
||||
AND m.type = 3
|
||||
AND m.status = 1
|
||||
<if test="permissionList != null and permissionList.size() > 0">
|
||||
AND m.permission IN
|
||||
<foreach collection="permissionList" item="item" open="(" close=")" separator=",">
|
||||
#{item}
|
||||
</foreach>
|
||||
</if>
|
||||
AND rm.role_id IN
|
||||
<foreach collection="roleIdList" item="item" open="(" close=")" separator=",">
|
||||
#{item}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<select id="selectRoleByUserId" resultMap="BaseResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
SELECT
|
||||
<include refid="Base_Column_List"/>
|
||||
FROM system_role
|
||||
WHERE deleted = 0
|
||||
AND id IN (SELECT role_id FROM system_user_role WHERE user_id = #{userId} AND deleted = 0)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
VITE_API_BASE_URL= 'http://127.0.0.1:9200/orion-visor/api'
|
||||
VITE_WS_BASE_URL= 'ws://127.0.0.1:9200/orion-visor/keep-alive'
|
||||
VITE_APP_VERSION= '2.1.3'
|
||||
VITE_APP_VERSION= '2.1.4'
|
||||
VITE_APP_RELEASE= 'community'
|
||||
VITE_SFTP_PREVIEW_MB= 2
|
||||
VITE_DEMO_MODE= false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
VITE_API_BASE_URL= '/orion-visor/api'
|
||||
VITE_WS_BASE_URL= '/orion-visor/keep-alive'
|
||||
VITE_APP_VERSION= '2.1.3'
|
||||
VITE_APP_VERSION= '2.1.4'
|
||||
VITE_APP_RELEASE= 'community'
|
||||
VITE_SFTP_PREVIEW_MB= 2
|
||||
VITE_DEMO_MODE= false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "orion-visor-ui",
|
||||
"description": "Orion Visor UI",
|
||||
"version": "2.1.3",
|
||||
"version": "2.1.4",
|
||||
"private": true,
|
||||
"author": "Jiahang Li",
|
||||
"license": "Apache 2.0",
|
||||
|
||||
@@ -93,5 +93,5 @@ export function deleteMenu(id: number) {
|
||||
* 刷新缓存
|
||||
*/
|
||||
export function refreshCache() {
|
||||
return axios.put('/infra/permission/refresh-cache');
|
||||
return axios.put('/infra/user-permission/refresh-cache');
|
||||
}
|
||||
|
||||
@@ -50,12 +50,12 @@ export function logout() {
|
||||
* 获取用户信息
|
||||
*/
|
||||
export function getUserPermission() {
|
||||
return axios.get<UserPermissionResponse>('/infra/permission/user');
|
||||
return axios.get<UserPermissionResponse>('/infra/user-permission/user');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单列表
|
||||
*/
|
||||
export function getMenuList() {
|
||||
return axios.get<Array<MenuQueryResponse>>('/infra/permission/menu');
|
||||
return axios.get<Array<MenuQueryResponse>>('/infra/user-permission/menu');
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<!-- 子标题 -->
|
||||
<div v-if="!isDemoMode" class="login-form-sub-title">{{ $t('login.form.sub.title') }}</div>
|
||||
<!-- 演示模式 -->
|
||||
<div v-else class="login-form-sub-title ">演示模式账号: admin/admin</div>
|
||||
<div v-else class="login-form-sub-title">{{ $t('login.form.demo.title') }}</div>
|
||||
<!-- 错误信息 -->
|
||||
<div class="login-form-error-msg">{{ errorMessage }}</div>
|
||||
<!-- 登录表单 -->
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export default {
|
||||
'login.form.title': '登录 Orion Visor',
|
||||
'login.form.sub.title': '一站式服务器运维解决方案',
|
||||
'login.form.demo.title': '演示模式账号: admin/admin',
|
||||
'login.form.userName.errMsg': '用户名不能为空',
|
||||
'login.form.password.errMsg': '密码不能为空',
|
||||
'login.form.login.errMsg': '登录出错, 轻刷新重试',
|
||||
|
||||
@@ -49,22 +49,21 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { SidebarAction } from '../../types/define';
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
import { computed } from 'vue';
|
||||
import { useTerminalStore } from '@/store';
|
||||
import IconActions from '../layout/icon-actions.vue';
|
||||
|
||||
const { isFullscreen, toggle: toggleFullScreen } = useFullscreen();
|
||||
const emits = defineEmits(['fullscreen']);
|
||||
|
||||
const { tabManager } = useTerminalStore();
|
||||
|
||||
// 顶部操作
|
||||
const actions = computed<Array<SidebarAction>>(() => [
|
||||
const actions: Array<SidebarAction> = [
|
||||
{
|
||||
icon: isFullscreen.value ? 'icon-fullscreen-exit' : 'icon-fullscreen',
|
||||
content: isFullscreen.value ? '点击退出全屏模式' : '点击切换全屏模式',
|
||||
click: toggleFullScreen
|
||||
icon: 'icon-fullscreen',
|
||||
content: '全屏模式',
|
||||
click: () => emits('fullscreen')
|
||||
},
|
||||
]);
|
||||
];
|
||||
|
||||
</script>
|
||||
|
||||
@@ -101,17 +100,17 @@
|
||||
}
|
||||
|
||||
&-tabs {
|
||||
width: calc(100% - @logo-width - var(--sidebar-icon-wrapper-size));
|
||||
width: calc(100% - @logo-width - 100px);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&-right {
|
||||
width: var(--sidebar-icon-wrapper-size);
|
||||
width: 100px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
&-actions {
|
||||
width: var(--sidebar-icon-wrapper-size);
|
||||
width: 100px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@
|
||||
width: 100%;
|
||||
height: calc(100% - @ssh-header-height);
|
||||
position: relative;
|
||||
padding: 8px 2px 2px 8px;
|
||||
padding: 8px 4px 4px 8px;
|
||||
|
||||
.ssh-inst {
|
||||
width: 100%;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<template>
|
||||
<div class="host-terminal-layout" v-if="render">
|
||||
<div v-if="render"
|
||||
class="host-terminal-layout"
|
||||
:class="{ 'terminal-full-layout': fullscreen }">
|
||||
<!-- 头部区域 -->
|
||||
<header class="host-terminal-layout-header">
|
||||
<layout-header />
|
||||
<layout-header @fullscreen="enterFullscreen" />
|
||||
</header>
|
||||
<!-- 主体区域 -->
|
||||
<main class="host-terminal-layout-main">
|
||||
@@ -29,6 +31,14 @@
|
||||
@screenshot="screenshot" />
|
||||
</div>
|
||||
</main>
|
||||
<!-- 退出全屏 -->
|
||||
<a-button v-if="fullscreen"
|
||||
class="exit-fullscreen"
|
||||
shape="circle"
|
||||
title="退出全屏"
|
||||
@click="exitFullscreen">
|
||||
<icon-fullscreen-exit />
|
||||
</a-button>
|
||||
<!-- 命令片段列表抽屉 -->
|
||||
<command-snippet-drawer ref="snippetRef" @closed="autoFocus" />
|
||||
<!-- 路径书签列表抽屉 -->
|
||||
@@ -50,6 +60,7 @@
|
||||
import { dictKeys, PanelSessionType, TerminalTabs } from './types/const';
|
||||
import { useCacheStore, useDictStore, useTerminalStore } from '@/store';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import debug from '@/utils/env';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
@@ -66,6 +77,7 @@
|
||||
|
||||
const { fetchPreference, getCurrentSession, openSession, preference, loadHosts, hosts, tabManager } = useTerminalStore();
|
||||
const { loading, setLoading } = useLoading(true);
|
||||
const { enter: enterFull, exit: exitFull } = useFullscreen();
|
||||
const route = useRoute();
|
||||
|
||||
const originTitle = document.title;
|
||||
@@ -73,6 +85,7 @@
|
||||
const snippetRef = ref();
|
||||
const pathRef = ref();
|
||||
const transferRef = ref();
|
||||
const fullscreen = ref();
|
||||
|
||||
// 终端截屏
|
||||
const screenshot = () => {
|
||||
@@ -82,10 +95,18 @@
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭视口处理
|
||||
const handleBeforeUnload = (event: any) => {
|
||||
event.preventDefault();
|
||||
event.returnValue = confirm('系统可能不会保存您所做的更改');
|
||||
// 进入全屏
|
||||
const enterFullscreen = () => {
|
||||
fullscreen.value = true;
|
||||
// 进入全屏
|
||||
enterFull();
|
||||
};
|
||||
|
||||
// 退出全屏
|
||||
const exitFullscreen = () => {
|
||||
fullscreen.value = false;
|
||||
// 退出全屏
|
||||
exitFull();
|
||||
};
|
||||
|
||||
// 自动聚焦
|
||||
@@ -93,6 +114,12 @@
|
||||
getCurrentSession<ISshSession>(PanelSessionType.SSH.type)?.focus();
|
||||
};
|
||||
|
||||
// 关闭视口处理
|
||||
const handleBeforeUnload = (event: any) => {
|
||||
event.preventDefault();
|
||||
event.returnValue = confirm('系统可能不会保存您所做的更改');
|
||||
};
|
||||
|
||||
// 打开默认打开页面
|
||||
onBeforeMount(() => {
|
||||
// 打开默认 tab
|
||||
@@ -105,18 +132,19 @@
|
||||
});
|
||||
|
||||
// 加载用户终端偏好
|
||||
onBeforeMount(async () => {
|
||||
onBeforeMount(() => {
|
||||
// 加载偏好
|
||||
await fetchPreference();
|
||||
// 设置系统主题配色
|
||||
const dark = preference.theme.dark;
|
||||
document.body.setAttribute('terminal-theme', dark ? 'dark' : 'light');
|
||||
render.value = true;
|
||||
fetchPreference().then(() => {
|
||||
// 设置系统主题配色
|
||||
const dark = preference.theme.dark;
|
||||
document.body.setAttribute('terminal-theme', dark ? 'dark' : 'light');
|
||||
render.value = true;
|
||||
});
|
||||
});
|
||||
|
||||
// 加载字典值
|
||||
onBeforeMount(async () => {
|
||||
await useDictStore().loadKeys(dictKeys);
|
||||
onBeforeMount(() => {
|
||||
useDictStore().loadKeys(dictKeys);
|
||||
});
|
||||
|
||||
// 加载主机信息
|
||||
@@ -176,6 +204,24 @@
|
||||
position: relative;
|
||||
color: var(--color-content-text-2);
|
||||
|
||||
&.terminal-full-layout {
|
||||
.host-terminal-layout-header, .host-terminal-layout-left, .host-terminal-layout-right {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.host-terminal-layout-main {
|
||||
height: 100%;
|
||||
|
||||
:deep(.host-terminal-layout-content) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.terminal-panels-container) {
|
||||
height: 100vh !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-header {
|
||||
width: 100%;
|
||||
height: var(--header-height);
|
||||
@@ -212,6 +258,13 @@
|
||||
background: var(--color-bg-content);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.exit-fullscreen {
|
||||
position: absolute;
|
||||
right: 24px;
|
||||
bottom: 24px;
|
||||
z-index: 9999;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -83,15 +83,21 @@
|
||||
<template #keyName="{record}">
|
||||
{{ record.keyName }}<span style="margin: 0 4px;">-</span>{{ record.keyDescription }}
|
||||
</template>
|
||||
<!-- 值 -->
|
||||
<!-- 配置值 -->
|
||||
<template #value="{ record }">
|
||||
<span class="copy-left" title="复制" @click="copy(record.value)">
|
||||
<icon-copy />
|
||||
</span>
|
||||
<a-tooltip position="tl" :content="record.value">
|
||||
<span>{{ record.value }}</span>
|
||||
<a-tooltip position="tl"
|
||||
:content="record.value"
|
||||
@click="copy(record.value, true)">
|
||||
<span class="text-copy">{{ record.value }}</span>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<!-- 额外参数 -->
|
||||
<template #extra="{ record }">
|
||||
<span class="text-copy"
|
||||
@click="copy(record.extra, true)">
|
||||
{{ record.extra }}
|
||||
</span>
|
||||
</template>
|
||||
<!-- 操作 -->
|
||||
<template #handle="{ record }">
|
||||
<div class="table-handle-wrapper">
|
||||
|
||||
@@ -272,11 +272,13 @@
|
||||
|
||||
// 添加后回调
|
||||
const addedCallback = () => {
|
||||
formRef.value.resetFields();
|
||||
loadMenuData(true);
|
||||
};
|
||||
|
||||
// 更新后回调
|
||||
const updatedCallback = () => {
|
||||
formRef.value.resetFields();
|
||||
loadMenuData(true);
|
||||
};
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ const columns = [
|
||||
title: '类型',
|
||||
dataIndex: 'type',
|
||||
slotName: 'type',
|
||||
width: 80,
|
||||
width: 68,
|
||||
}, {
|
||||
title: '排序',
|
||||
dataIndex: 'sort',
|
||||
@@ -32,20 +32,21 @@ const columns = [
|
||||
title: '权限标识',
|
||||
dataIndex: 'permission',
|
||||
slotName: 'permission',
|
||||
minWidth: 138,
|
||||
minWidth: 168,
|
||||
ellipsis: true,
|
||||
tooltip: true
|
||||
}, {
|
||||
title: '组件名称',
|
||||
dataIndex: 'component',
|
||||
slotName: 'component',
|
||||
minWidth: 138,
|
||||
minWidth: 218,
|
||||
ellipsis: true,
|
||||
tooltip: true,
|
||||
}, {
|
||||
title: '链接路径',
|
||||
dataIndex: 'path',
|
||||
slotName: 'path',
|
||||
width: 168,
|
||||
ellipsis: true,
|
||||
tooltip: true,
|
||||
}, {
|
||||
|
||||
@@ -29,8 +29,20 @@
|
||||
</template>
|
||||
<!-- 操作日志 -->
|
||||
<template #originLogInfo="{ record }">
|
||||
<icon-copy class="copy-left" @click="copy(record.originLogInfo, true)" />
|
||||
<span v-html="replaceHtmlTag(record.logInfo)" />
|
||||
<!-- 操作日志 -->
|
||||
<a-tooltip position="tl"
|
||||
:content="record.originLogInfo">
|
||||
<span v-html="replaceHtmlTag(record.logInfo)"
|
||||
class="text-copy"
|
||||
@click="copy(record.originLogInfo, true)" />
|
||||
</a-tooltip>
|
||||
<!-- 错误消息 -->
|
||||
<br v-if="record.errorMessage">
|
||||
<span v-if="record.errorMessage"
|
||||
class="table-cell-sub-value text-copy error-message"
|
||||
@click="copy(record.errorMessage, true)">
|
||||
{{ record.errorMessage }}
|
||||
</span>
|
||||
</template>
|
||||
<!-- 留痕地址 -->
|
||||
<template #address="{ record }">
|
||||
@@ -170,4 +182,8 @@
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.error-message {
|
||||
color: rgb(var(--red-6));
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -77,8 +77,20 @@
|
||||
</template>
|
||||
<!-- 操作日志 -->
|
||||
<template #originLogInfo="{ record }">
|
||||
<icon-copy class="copy-left" @click="copy(record.originLogInfo, true)" />
|
||||
<span v-html="replaceHtmlTag(record.logInfo)" />
|
||||
<!-- 操作日志 -->
|
||||
<a-tooltip position="tl"
|
||||
:content="record.originLogInfo">
|
||||
<span v-html="replaceHtmlTag(record.logInfo)"
|
||||
class="text-copy"
|
||||
@click="copy(record.originLogInfo, true)" />
|
||||
</a-tooltip>
|
||||
<!-- 错误消息 -->
|
||||
<br v-if="record.errorMessage">
|
||||
<span v-if="record.errorMessage"
|
||||
class="table-cell-sub-value text-copy error-message"
|
||||
@click="copy(record.errorMessage, true)">
|
||||
{{ record.errorMessage }}
|
||||
</span>
|
||||
</template>
|
||||
<!-- 留痕地址 -->
|
||||
<template #address="{ record }">
|
||||
@@ -226,4 +238,8 @@
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.error-message {
|
||||
color: rgb(var(--red-6));
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -33,7 +33,6 @@ const columns = [
|
||||
minWidth: 238,
|
||||
align: 'left',
|
||||
ellipsis: true,
|
||||
tooltip: true,
|
||||
}, {
|
||||
title: '留痕地址',
|
||||
dataIndex: 'address',
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -22,7 +22,7 @@
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<revision>2.1.3</revision>
|
||||
<revision>2.1.4</revision>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<maven.surefire.plugin.version>3.0.0-M5</maven.surefire.plugin.version>
|
||||
|
||||
@@ -43,7 +43,7 @@ INSERT INTO `dict_key` VALUES (39, 'pathBookmarkType', 'STRING', '[]', '路径
|
||||
INSERT INTO `dict_key` VALUES (40, 'sftpTransferStatus', 'STRING', '[{\"name\": \"status\", \"type\": \"STRING\"}, {\"name\": \"color\", \"type\": \"COLOR\"}, {\"name\": \"icon\", \"type\": \"STRING\"}]', 'SFTP 传输状态', '2024-05-06 11:54:49', '2024-05-06 11:54:49', '1', '1', 0);
|
||||
INSERT INTO `dict_key` VALUES (41, 'uploadTaskStatus', 'STRING', '[{\"name\": \"color\", \"type\": \"COLOR\"}]', '上传任务状态', '2024-05-07 22:18:48', '2024-05-08 22:06:23', '1', '1', 0);
|
||||
INSERT INTO `dict_key` VALUES (42, 'uploadTaskFileStatus', 'STRING', '[{\"name\": \"status\", \"type\": \"STRING\"}]', '上传任务文件状态', '2024-05-08 10:30:29', '2024-05-10 17:34:13', '1', '1', 0);
|
||||
INSERT INTO `dict_key` VALUES (43, 'messageType', 'STRING', '[{\"name\": \"tagLabel\", \"type\": \"STRING\"}, {\"name\": \"tagVisible\", \"type\": \"STRING\"}, {\"name\": \"tagColor\", \"type\": \"STRING\"}, {\"name\": \"redirectComponent\", \"type\": \"STRING\"}]', '消息类型', '2024-05-13 12:07:56', '2024-05-31 17:31:37', '1', '1', 0);
|
||||
INSERT INTO `dict_key` VALUES (43, 'messageType', 'STRING', '[{\"name\": \"tagLabel\", \"type\": \"STRING\"}, {\"name\": \"tagVisible\", \"type\": \"BOOLEAN\"}, {\"name\": \"tagColor\", \"type\": \"COLOR\"}, {\"name\": \"redirectComponent\", \"type\": \"STRING\"}]', '消息类型', '2024-05-13 12:07:56', '2024-08-19 12:28:30', '1', '1', 0);
|
||||
INSERT INTO `dict_key` VALUES (44, 'messageClassify', 'STRING', '[]', '消息分类', '2024-05-13 15:06:27', '2024-05-31 17:31:37', '1', '1', 0);
|
||||
INSERT INTO `dict_key` VALUES (53, 'terminalTheme', 'STRING', '[{\"name\": \"dark\", \"type\": \"BOOLEAN\"}]', '终端主题', '2024-07-04 19:14:34', '2024-07-04 19:14:34', '1', '1', 0);
|
||||
INSERT INTO `dict_key` VALUES (57, 'hostStatus', 'STRING', '[{\"name\": \"color\", \"type\": \"COLOR\"}, {\"name\": \"status\", \"type\": \"STRING\"}]', '主机状态', '2024-07-17 12:51:10', '2024-07-22 16:53:23', '1', '1', 0);
|
||||
@@ -288,27 +288,32 @@ INSERT INTO `dict_value` VALUES (291, 2, 'operatorLogType', 'upload-task:cancel'
|
||||
INSERT INTO `dict_value` VALUES (292, 2, 'operatorLogType', 'upload-task:delete', '删除上传记录', '{}', 30, '2024-05-08 22:23:44', '2024-05-08 22:23:44', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (293, 2, 'operatorLogType', 'upload-task:clear', '清理上传记录', '{}', 40, '2024-05-08 22:23:59', '2024-05-08 22:23:59', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (294, 41, 'uploadTaskStatus', 'FAILED', '已失败', '{\"color\": \"red\"}', 40, '2024-05-10 11:29:17', '2024-05-10 11:29:17', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (295, 43, 'messageType', 'EXEC_FAILED', '执行失败', '{\"tagColor\": \"red\", \"tagLabel\": \"部分失败\", \"tagVisible\": \"true\", \"redirectComponent\": \"execCommand\"}', 10, '2024-05-13 12:07:56', '2024-05-31 17:31:18', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (296, 43, 'messageType', 'UPLOAD_FAILED', '上传失败', '{\"tagColor\": \"red\", \"tagLabel\": \"部分失败\", \"tagVisible\": \"true\", \"redirectComponent\": \"batchUpload\"}', 20, '2024-05-13 12:07:56', '2024-05-31 17:31:18', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (295, 43, 'messageType', 'EXEC_FAILED', '执行失败', '{\"tagColor\": \"red\", \"tagLabel\": \"部分失败\", \"tagVisible\": true, \"redirectComponent\": \"execCommand\"}', 10, '2024-05-13 12:07:56', '2024-08-19 12:28:48', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (296, 43, 'messageType', 'UPLOAD_FAILED', '上传失败', '{\"tagColor\": \"red\", \"tagLabel\": \"部分失败\", \"tagVisible\": true, \"redirectComponent\": \"batchUpload\"}', 20, '2024-05-13 12:07:56', '2024-08-19 12:28:51', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (297, 44, 'messageClassify', 'NOTICE', '通知', '{}', 10, '2024-05-13 15:06:27', '2024-05-31 17:31:18', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (298, 44, 'messageClassify', 'TODO', '待办', '{}', 20, '2024-05-13 15:06:27', '2024-05-31 17:31:18', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (353, 53, 'terminalTheme', '{\"background\":\"#1E1F29\",\"foreground\":\"#F8F8F2\",\"cursor\":\"#BBBBBB\",\"selectionBackground\":\"#44475A\",\"black\":\"#000000\",\"red\":\"#FF5555\",\"green\":\"#50FA7B\",\"yellow\":\"#F1FA8C\",\"blue\":\"#BD93F9\",\"cyan\":\"#8BE9FD\",\"white\":\"#BBBBBB\",\"brightBlack\":\"#555555\",\"brightRed\":\"#FF5555\",\"brightGreen\":\"#50FA7B\",\"brightYellow\":\"#F1FA8C\",\"brightBlue\":\"#BD93F9\",\"brightCyan\":\"#8BE9FD\",\"brightWhite\":\"#FFFFFF\"}', 'Dracula', '{\"dark\": true}', 10, '2024-07-04 19:15:42', '2024-07-04 19:15:42', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (354, 53, 'terminalTheme', '{\"background\":\"#161719\",\"foreground\":\"#C5C8C6\",\"cursor\":\"#D0D0D0\",\"selectionBackground\":\"#444444\",\"black\":\"#000000\",\"red\":\"#FD5FF1\",\"green\":\"#87C38A\",\"yellow\":\"#FFD7B1\",\"blue\":\"#85BEFD\",\"cyan\":\"#85BEFD\",\"white\":\"#E0E0E0\",\"brightBlack\":\"#000000\",\"brightRed\":\"#FD5FF1\",\"brightGreen\":\"#94FA36\",\"brightYellow\":\"#F5FFA8\",\"brightBlue\":\"#96CBFE\",\"brightCyan\":\"#85BEFD\",\"brightWhite\":\"#E0E0E0\"}', 'Atom', '{\"dark\": true}', 20, '2024-07-04 19:21:38', '2024-07-04 19:21:38', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (355, 53, 'terminalTheme', '{\"background\":\"#1E1E2E\",\"foreground\":\"#CDD6F4\",\"cursor\":\"#F5E0DC\",\"selectionBackground\":\"#585B70\",\"black\":\"#45475A\",\"red\":\"#F38BA8\",\"green\":\"#A6E3A1\",\"yellow\":\"#F9E2AF\",\"blue\":\"#89B4FA\",\"cyan\":\"#94E2D5\",\"white\":\"#BAC2DE\",\"brightBlack\":\"#585B70\",\"brightRed\":\"#F38BA8\",\"brightGreen\":\"#A6E3A1\",\"brightYellow\":\"#F9E2AF\",\"brightBlue\":\"#89B4FA\",\"brightCyan\":\"#94E2D5\",\"brightWhite\":\"#A6ADC8\"}', 'catppuccin-mocha', '{\"dark\": true}', 30, '2024-07-04 19:21:49', '2024-07-04 19:21:49', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (356, 53, 'terminalTheme', '{\"background\":\"#1D262A\",\"foreground\":\"#E7EBED\",\"cursor\":\"#EAEAEA\",\"selectionBackground\":\"#4E6A78\",\"black\":\"#435B67\",\"red\":\"#FC3841\",\"green\":\"#5CF19E\",\"yellow\":\"#FED032\",\"blue\":\"#37B6FF\",\"cyan\":\"#59FFD1\",\"white\":\"#FFFFFF\",\"brightBlack\":\"#A1B0B8\",\"brightRed\":\"#FC746D\",\"brightGreen\":\"#ADF7BE\",\"brightYellow\":\"#FEE16C\",\"brightBlue\":\"#70CFFF\",\"brightCyan\":\"#9AFFE6\",\"brightWhite\":\"#FFFFFF\"}', 'MaterialDesignColors', '{\"dark\": true}', 40, '2024-07-04 19:22:02', '2024-07-04 19:22:02', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (357, 53, 'terminalTheme', '{\"background\":\"#24273A\",\"foreground\":\"#CAD3F5\",\"cursor\":\"#F4DBD6\",\"selectionBackground\":\"#5B6078\",\"black\":\"#494D64\",\"red\":\"#ED8796\",\"green\":\"#A6DA95\",\"yellow\":\"#EED49F\",\"blue\":\"#8AADF4\",\"cyan\":\"#8BD5CA\",\"white\":\"#B8C0E0\",\"brightBlack\":\"#5B6078\",\"brightRed\":\"#ED8796\",\"brightGreen\":\"#A6DA95\",\"brightYellow\":\"#EED49F\",\"brightBlue\":\"#8AADF4\",\"brightCyan\":\"#8BD5CA\",\"brightWhite\":\"#A5ADCB\"}', 'catppuccin-macchiato', '{\"dark\": true}', 50, '2024-07-04 19:22:16', '2024-07-04 19:22:16', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (358, 53, 'terminalTheme', '{\"background\":\"#282C34\",\"foreground\":\"#DCDFE4\",\"cursor\":\"#A3B3CC\",\"selectionBackground\":\"#474E5D\",\"black\":\"#282C34\",\"red\":\"#E06C75\",\"green\":\"#98C379\",\"yellow\":\"#E5C07B\",\"blue\":\"#61AFEF\",\"cyan\":\"#56B6C2\",\"white\":\"#DCDFE4\",\"brightBlack\":\"#282C34\",\"brightRed\":\"#E06C75\",\"brightGreen\":\"#98C379\",\"brightYellow\":\"#E5C07B\",\"brightBlue\":\"#61AFEF\",\"brightCyan\":\"#56B6C2\",\"brightWhite\":\"#DCDFE4\"}', 'OneHalfDark', '{\"dark\": true}', 60, '2024-07-04 19:22:26', '2024-07-04 19:22:26', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (359, 53, 'terminalTheme', '{\"background\":\"#1E1E1E\",\"foreground\":\"#FFFFFF\",\"cursor\":\"#98989D\",\"selectionBackground\":\"#3F638B\",\"black\":\"#1A1A1A\",\"red\":\"#CC372E\",\"green\":\"#26A439\",\"yellow\":\"#CDAC08\",\"blue\":\"#0869CB\",\"cyan\":\"#479EC2\",\"white\":\"#98989D\",\"brightBlack\":\"#464646\",\"brightRed\":\"#FF453A\",\"brightGreen\":\"#32D74B\",\"brightYellow\":\"#FFD60A\",\"brightBlue\":\"#0A84FF\",\"brightCyan\":\"#76D6FF\",\"brightWhite\":\"#FFFFFF\"}', 'Apple System Colors', '{\"dark\": true}', 70, '2024-07-04 19:22:45', '2024-07-04 19:22:45', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (360, 53, 'terminalTheme', '{\"background\":\"#FFFFFF\",\"foreground\":\"#000000\",\"cursor\":\"#000000\",\"selectionBackground\":\"#B5D5FF\",\"black\":\"#000000\",\"red\":\"#CC0000\",\"green\":\"#4E9A06\",\"yellow\":\"#C4A000\",\"blue\":\"#3465A4\",\"cyan\":\"#06989A\",\"white\":\"#D3D7CF\",\"brightBlack\":\"#555753\",\"brightRed\":\"#EF2929\",\"brightGreen\":\"#8AE234\",\"brightYellow\":\"#FCE94F\",\"brightBlue\":\"#729FCF\",\"brightCyan\":\"#34E2E2\",\"brightWhite\":\"#EEEEEC\"}', 'Builtin Tango Light', '{\"dark\": false}', 80, '2024-07-04 19:22:57', '2024-07-04 19:22:57', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (361, 53, 'terminalTheme', '{\"background\":\"#1F1D27\",\"foreground\":\"#B7A1FF\",\"cursor\":\"#FF9839\",\"selectionBackground\":\"#353147\",\"black\":\"#1F1D27\",\"red\":\"#D9393E\",\"green\":\"#2DCD73\",\"yellow\":\"#D9B76E\",\"blue\":\"#FFC284\",\"cyan\":\"#2488FF\",\"white\":\"#B7A1FF\",\"brightBlack\":\"#353147\",\"brightRed\":\"#D9393E\",\"brightGreen\":\"#2DCD73\",\"brightYellow\":\"#D9B76E\",\"brightBlue\":\"#FFC284\",\"brightCyan\":\"#2488FF\",\"brightWhite\":\"#EAE5FF\"}', 'Duotone Dark', '{\"dark\": true}', 90, '2024-07-04 19:23:13', '2024-07-04 19:23:13', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (362, 53, 'terminalTheme', '{\"background\":\"#F9F9F9\",\"foreground\":\"#373A41\",\"cursor\":\"#F32759\",\"selectionBackground\":\"#DAF0FF\",\"black\":\"#373A41\",\"red\":\"#D52753\",\"green\":\"#23974A\",\"yellow\":\"#DF631C\",\"blue\":\"#275FE4\",\"cyan\":\"#27618D\",\"white\":\"#BABBC2\",\"brightBlack\":\"#676A77\",\"brightRed\":\"#FF6480\",\"brightGreen\":\"#3CBC66\",\"brightYellow\":\"#C5A332\",\"brightBlue\":\"#0099E1\",\"brightCyan\":\"#6D93BB\",\"brightWhite\":\"#D3D3D3\"}', 'BlulocoLight', '{\"dark\": false}', 100, '2024-07-04 19:23:32', '2024-07-04 19:23:32', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (363, 53, 'terminalTheme', '{\"background\":\"#2C3643\",\"foreground\":\"#FFFFFF\",\"cursor\":\"#B4B1B1\",\"selectionBackground\":\"#67747C\",\"black\":\"#080200\",\"red\":\"#FA5E5B\",\"green\":\"#16C98D\",\"yellow\":\"#FFC83F\",\"blue\":\"#288AD6\",\"cyan\":\"#28DDDE\",\"white\":\"#E7E7E7\",\"brightBlack\":\"#6F6B68\",\"brightRed\":\"#FA5E5B\",\"brightGreen\":\"#16C98D\",\"brightYellow\":\"#FEEF6D\",\"brightBlue\":\"#278AD6\",\"brightCyan\":\"#27DEDE\",\"brightWhite\":\"#FFFFFF\"}', 'Chester', '{\"dark\": true}', 110, '2024-07-04 19:23:41', '2024-07-04 19:23:41', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (364, 53, 'terminalTheme', '{\"background\":\"#FFFFFF\",\"foreground\":\"#262626\",\"cursor\":\"#6FD3FC\",\"selectionBackground\":\"#6FD3FC\",\"black\":\"#000000\",\"red\":\"#F8282A\",\"green\":\"#328A5D\",\"yellow\":\"#FA701D\",\"blue\":\"#135CD0\",\"cyan\":\"#33C3C1\",\"white\":\"#B3B3B3\",\"brightBlack\":\"#555753\",\"brightRed\":\"#FB0416\",\"brightGreen\":\"#2CC631\",\"brightYellow\":\"#FDD727\",\"brightBlue\":\"#1670FF\",\"brightCyan\":\"#3AD5CE\",\"brightWhite\":\"#EEEEEC\"}', 'CLRS', '{\"dark\": false}', 120, '2024-07-04 19:24:06', '2024-07-04 19:24:06', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (365, 53, 'terminalTheme', '{\"background\":\"#2F2833\",\"foreground\":\"#D5CED9\",\"cursor\":\"#D5CED9\",\"selectionBackground\":\"#7E6C88\",\"black\":\"#2F2833\",\"red\":\"#FC644D\",\"green\":\"#A5F69C\",\"yellow\":\"#E9D7A5\",\"blue\":\"#3B79C7\",\"cyan\":\"#74D3DE\",\"white\":\"#D5CED9\",\"brightBlack\":\"#7E6C88\",\"brightRed\":\"#FC644D\",\"brightGreen\":\"#A5F69C\",\"brightYellow\":\"#E9D7A5\",\"brightBlue\":\"#3B79C7\",\"brightCyan\":\"#74D3DE\",\"brightWhite\":\"#FFFFFF\"}', 'Calamity', '{\"dark\": true}', 130, '2024-07-04 19:24:17', '2024-07-04 19:24:17', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (366, 53, 'terminalTheme', '{\"background\":\"#FFFFFF\",\"foreground\":\"#4D4D4C\",\"cursor\":\"#4D4D4C\",\"selectionBackground\":\"#D6D6D6\",\"black\":\"#000000\",\"red\":\"#C82829\",\"green\":\"#718C00\",\"yellow\":\"#EAB700\",\"blue\":\"#4271AE\",\"cyan\":\"#3E999F\",\"white\":\"#FFFFFF\",\"brightBlack\":\"#000000\",\"brightRed\":\"#C82829\",\"brightGreen\":\"#718C00\",\"brightYellow\":\"#EAB700\",\"brightBlue\":\"#4271AE\",\"brightCyan\":\"#3E999F\",\"brightWhite\":\"#FFFFFF\"}', 'Tomorrow', '{\"dark\": false}', 140, '2024-07-04 19:24:27', '2024-07-04 21:07:57', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (353, 53, 'terminalTheme', '{\"background\":\"#1E1F29\",\"foreground\":\"#F8F8F2\",\"cursor\":\"#BBBBBB\",\"selectionBackground\":\"#44475A\",\"black\":\"#000000\",\"red\":\"#FF5555\",\"green\":\"#50FA7B\",\"yellow\":\"#F1FA8C\",\"blue\":\"#BD93F9\",\"cyan\":\"#8BE9FD\",\"white\":\"#BBBBBB\",\"brightBlack\":\"#555555\",\"brightRed\":\"#FF5555\",\"brightGreen\":\"#50FA7B\",\"brightYellow\":\"#F1FA8C\",\"brightBlue\":\"#BD93F9\",\"brightCyan\":\"#8BE9FD\",\"brightWhite\":\"#FFFFFF\"}', 'Dracula', '{\"dark\": true}', 10, '2024-07-04 19:15:42', '2024-08-19 18:49:12', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (354, 53, 'terminalTheme', '{\"background\":\"#FFFFFF\",\"foreground\":\"#000000\",\"cursor\":\"#000000\",\"selectionBackground\":\"#B5D5FF\",\"black\":\"#000000\",\"red\":\"#CC0000\",\"green\":\"#4E9A06\",\"yellow\":\"#C4A000\",\"blue\":\"#3465A4\",\"cyan\":\"#06989A\",\"white\":\"#D3D7CF\",\"brightBlack\":\"#555753\",\"brightRed\":\"#EF2929\",\"brightGreen\":\"#8AE234\",\"brightYellow\":\"#FCE94F\",\"brightBlue\":\"#729FCF\",\"brightCyan\":\"#34E2E2\",\"brightWhite\":\"#EEEEEC\"}', 'Builtin Tango Light', '{\"dark\": false}', 20, '2024-07-04 19:21:38', '2024-08-19 18:49:31', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (355, 53, 'terminalTheme', '{\"background\":\"#161719\",\"foreground\":\"#C5C8C6\",\"cursor\":\"#D0D0D0\",\"selectionBackground\":\"#444444\",\"black\":\"#000000\",\"red\":\"#FD5FF1\",\"green\":\"#87C38A\",\"yellow\":\"#FFD7B1\",\"blue\":\"#85BEFD\",\"cyan\":\"#85BEFD\",\"white\":\"#E0E0E0\",\"brightBlack\":\"#000000\",\"brightRed\":\"#FD5FF1\",\"brightGreen\":\"#94FA36\",\"brightYellow\":\"#F5FFA8\",\"brightBlue\":\"#96CBFE\",\"brightCyan\":\"#85BEFD\",\"brightWhite\":\"#E0E0E0\"}', 'Atom', '{\"dark\": true}', 30, '2024-07-04 19:21:49', '2024-08-19 18:49:49', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (356, 53, 'terminalTheme', '{\"background\":\"#F9F9F9\",\"foreground\":\"#2A2C33\",\"cursor\":\"#BBBBBB\",\"selectionBackground\":\"#EDEDED\",\"black\":\"#000000\",\"red\":\"#DE3E35\",\"green\":\"#3F953A\",\"yellow\":\"#D2B67C\",\"blue\":\"#2F5AF3\",\"cyan\":\"#3F953A\",\"white\":\"#BBBBBB\",\"brightBlack\":\"#000000\",\"brightRed\":\"#DE3E35\",\"brightGreen\":\"#3F953A\",\"brightYellow\":\"#D2B67C\",\"brightBlue\":\"#2F5AF3\",\"brightCyan\":\"#3F953A\",\"brightWhite\":\"#FFFFFF\"}', 'AtomOneLight', '{\"dark\": false}', 40, '2024-07-04 19:22:02', '2024-08-19 18:50:00', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (357, 53, 'terminalTheme', '{\"background\":\"#282C34\",\"foreground\":\"#DCDFE4\",\"cursor\":\"#A3B3CC\",\"selectionBackground\":\"#474E5D\",\"black\":\"#282C34\",\"red\":\"#E06C75\",\"green\":\"#98C379\",\"yellow\":\"#E5C07B\",\"blue\":\"#61AFEF\",\"cyan\":\"#56B6C2\",\"white\":\"#DCDFE4\",\"brightBlack\":\"#282C34\",\"brightRed\":\"#E06C75\",\"brightGreen\":\"#98C379\",\"brightYellow\":\"#E5C07B\",\"brightBlue\":\"#61AFEF\",\"brightCyan\":\"#56B6C2\",\"brightWhite\":\"#DCDFE4\"}', 'OneHalfDark', '{\"dark\": true}', 50, '2024-07-04 19:22:16', '2024-08-19 18:50:15', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (358, 53, 'terminalTheme', '{\"background\":\"#FAFAFA\",\"foreground\":\"#383A42\",\"cursor\":\"#BFCEFF\",\"selectionBackground\":\"#BFCEFF\",\"black\":\"#383A42\",\"red\":\"#E45649\",\"green\":\"#50A14F\",\"yellow\":\"#C18401\",\"blue\":\"#0184BC\",\"cyan\":\"#0997B3\",\"white\":\"#FAFAFA\",\"brightBlack\":\"#4F525E\",\"brightRed\":\"#E06C75\",\"brightGreen\":\"#98C379\",\"brightYellow\":\"#E5C07B\",\"brightBlue\":\"#61AFEF\",\"brightCyan\":\"#56B6C2\",\"brightWhite\":\"#FFFFFF\"}', 'OneHalfLight', '{\"dark\": false}', 60, '2024-07-04 19:22:26', '2024-08-19 18:50:27', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (359, 53, 'terminalTheme', '{\"background\":\"#1E1E1E\",\"foreground\":\"#FFFFFF\",\"cursor\":\"#98989D\",\"selectionBackground\":\"#3F638B\",\"black\":\"#1A1A1A\",\"red\":\"#CC372E\",\"green\":\"#26A439\",\"yellow\":\"#CDAC08\",\"blue\":\"#0869CB\",\"cyan\":\"#479EC2\",\"white\":\"#98989D\",\"brightBlack\":\"#464646\",\"brightRed\":\"#FF453A\",\"brightGreen\":\"#32D74B\",\"brightYellow\":\"#FFD60A\",\"brightBlue\":\"#0A84FF\",\"brightCyan\":\"#76D6FF\",\"brightWhite\":\"#FFFFFF\"}', 'Apple System Colors', '{\"dark\": true}', 70, '2024-07-04 19:22:45', '2024-08-19 18:50:46', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (360, 53, 'terminalTheme', '{\"background\":\"#FFFFFF\",\"foreground\":\"#4D4D4C\",\"cursor\":\"#4D4D4C\",\"selectionBackground\":\"#D6D6D6\",\"black\":\"#000000\",\"red\":\"#C82829\",\"green\":\"#718C00\",\"yellow\":\"#EAB700\",\"blue\":\"#4271AE\",\"cyan\":\"#3E999F\",\"white\":\"#FFFFFF\",\"brightBlack\":\"#000000\",\"brightRed\":\"#C82829\",\"brightGreen\":\"#718C00\",\"brightYellow\":\"#EAB700\",\"brightBlue\":\"#4271AE\",\"brightCyan\":\"#3E999F\",\"brightWhite\":\"#FFFFFF\"}', 'Tomorrow', '{\"dark\": false}', 80, '2024-07-04 19:22:57', '2024-08-19 18:51:03', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (361, 53, 'terminalTheme', '{\"background\":\"#1E1E2E\",\"foreground\":\"#CDD6F4\",\"cursor\":\"#F5E0DC\",\"selectionBackground\":\"#585B70\",\"black\":\"#45475A\",\"red\":\"#F38BA8\",\"green\":\"#A6E3A1\",\"yellow\":\"#F9E2AF\",\"blue\":\"#89B4FA\",\"cyan\":\"#94E2D5\",\"white\":\"#BAC2DE\",\"brightBlack\":\"#585B70\",\"brightRed\":\"#F38BA8\",\"brightGreen\":\"#A6E3A1\",\"brightYellow\":\"#F9E2AF\",\"brightBlue\":\"#89B4FA\",\"brightCyan\":\"#94E2D5\",\"brightWhite\":\"#A6ADC8\"}', 'catppuccin-mocha', '{\"dark\": true}', 90, '2024-07-04 19:23:13', '2024-08-19 18:51:23', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (362, 53, 'terminalTheme', '{\"background\":\"#EFF1F5\",\"foreground\":\"#4C4F69\",\"cursor\":\"#DC8A78\",\"selectionBackground\":\"#ACB0BE\",\"black\":\"#5C5F77\",\"red\":\"#D20F39\",\"green\":\"#40A02B\",\"yellow\":\"#DF8E1D\",\"blue\":\"#1E66F5\",\"cyan\":\"#179299\",\"white\":\"#ACB0BE\",\"brightBlack\":\"#6C6F85\",\"brightRed\":\"#D20F39\",\"brightGreen\":\"#40A02B\",\"brightYellow\":\"#DF8E1D\",\"brightBlue\":\"#1E66F5\",\"brightCyan\":\"#179299\",\"brightWhite\":\"#BCC0CC\"}', 'catppuccin-latte', '{\"dark\": false}', 100, '2024-07-04 19:23:32', '2024-08-19 18:51:43', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (363, 53, 'terminalTheme', '{\"background\":\"#24273A\",\"foreground\":\"#CAD3F5\",\"cursor\":\"#F4DBD6\",\"selectionBackground\":\"#5B6078\",\"black\":\"#494D64\",\"red\":\"#ED8796\",\"green\":\"#A6DA95\",\"yellow\":\"#EED49F\",\"blue\":\"#8AADF4\",\"cyan\":\"#8BD5CA\",\"white\":\"#B8C0E0\",\"brightBlack\":\"#5B6078\",\"brightRed\":\"#ED8796\",\"brightGreen\":\"#A6DA95\",\"brightYellow\":\"#EED49F\",\"brightBlue\":\"#8AADF4\",\"brightCyan\":\"#8BD5CA\",\"brightWhite\":\"#A5ADCB\"}', 'catppuccin-macchiato', '{\"dark\": true}', 110, '2024-07-04 19:23:41', '2024-08-19 18:51:55', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (364, 53, 'terminalTheme', '{\"background\":\"#F9F9F9\",\"foreground\":\"#373A41\",\"cursor\":\"#F32759\",\"selectionBackground\":\"#DAF0FF\",\"black\":\"#373A41\",\"red\":\"#D52753\",\"green\":\"#23974A\",\"yellow\":\"#DF631C\",\"blue\":\"#275FE4\",\"cyan\":\"#27618D\",\"white\":\"#BABBC2\",\"brightBlack\":\"#676A77\",\"brightRed\":\"#FF6480\",\"brightGreen\":\"#3CBC66\",\"brightYellow\":\"#C5A332\",\"brightBlue\":\"#0099E1\",\"brightCyan\":\"#6D93BB\",\"brightWhite\":\"#D3D3D3\"}', 'BlulocoLight', '{\"dark\": false}', 120, '2024-07-04 19:24:06', '2024-08-19 18:52:12', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (365, 53, 'terminalTheme', '{\"background\":\"#303446\",\"foreground\":\"#C6D0F5\",\"cursor\":\"#F2D5CF\",\"selectionBackground\":\"#626880\",\"black\":\"#51576D\",\"red\":\"#E78284\",\"green\":\"#A6D189\",\"yellow\":\"#E5C890\",\"blue\":\"#8CAAEE\",\"cyan\":\"#81C8BE\",\"white\":\"#B5BFE2\",\"brightBlack\":\"#626880\",\"brightRed\":\"#E78284\",\"brightGreen\":\"#A6D189\",\"brightYellow\":\"#E5C890\",\"brightBlue\":\"#8CAAEE\",\"brightCyan\":\"#81C8BE\",\"brightWhite\":\"#A5ADCE\"}', 'catppuccin-frappe', '{\"dark\": true}', 130, '2024-07-04 19:24:17', '2024-08-19 18:52:24', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (366, 53, 'terminalTheme', '{\"background\":\"#1D262A\",\"foreground\":\"#E7EBED\",\"cursor\":\"#EAEAEA\",\"selectionBackground\":\"#4E6A78\",\"black\":\"#435B67\",\"red\":\"#FC3841\",\"green\":\"#5CF19E\",\"yellow\":\"#FED032\",\"blue\":\"#37B6FF\",\"cyan\":\"#59FFD1\",\"white\":\"#FFFFFF\",\"brightBlack\":\"#A1B0B8\",\"brightRed\":\"#FC746D\",\"brightGreen\":\"#ADF7BE\",\"brightYellow\":\"#FEE16C\",\"brightBlue\":\"#70CFFF\",\"brightCyan\":\"#9AFFE6\",\"brightWhite\":\"#FFFFFF\"}', 'MaterialDesignColors', '{\"dark\": true}', 140, '2024-07-04 19:24:27', '2024-08-19 18:52:56', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (385, 57, 'hostStatus', 'ENABLED', '启用', '{\"color\": \"arcoblue\", \"status\": \"normal\", \"buttonStatus\": \"normal\"}', 10, '2024-07-17 12:51:10', '2024-07-22 16:53:53', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (386, 57, 'hostStatus', 'DISABLED', '停用', '{\"color\": \"orangered\", \"status\": \"error\", \"buttonStatus\": \"danger\"}', 20, '2024-07-17 12:51:10', '2024-07-22 16:53:46', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (387, 58, 'hostType', 'SSH', 'SSH', '{\"color\": \"arcoblue\"}', 10, '2024-07-17 12:51:10', '2024-07-17 15:57:24', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (401, 43, 'messageType', 'LOGIN_FAILED', '登录失败', '{\"tagColor\": \"red\", \"tagLabel\": \"登录失败\", \"tagVisible\": true, \"redirectComponent\": \"0\"}', 50, '2024-08-19 18:34:27', '2024-08-19 18:34:27', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (402, 53, 'terminalTheme', '{\"background\":\"#101216\",\"foreground\":\"#8B949E\",\"cursor\":\"#C9D1D9\",\"selectionBackground\":\"#3B5070\",\"black\":\"#000000\",\"red\":\"#F78166\",\"green\":\"#56D364\",\"yellow\":\"#E3B341\",\"blue\":\"#6CA4F8\",\"cyan\":\"#2B7489\",\"white\":\"#FFFFFF\",\"brightBlack\":\"#4D4D4D\",\"brightRed\":\"#F78166\",\"brightGreen\":\"#56D364\",\"brightYellow\":\"#E3B341\",\"brightBlue\":\"#6CA4F8\",\"brightCyan\":\"#2B7489\",\"brightWhite\":\"#FFFFFF\"}', 'GitHub Dark', '{\"dark\": true}', 150, '2024-08-19 18:53:14', '2024-08-19 18:53:20', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (403, 53, 'terminalTheme', '{\"background\":\"#F4F4F4\",\"foreground\":\"#3E3E3E\",\"cursor\":\"#3F3F3F\",\"selectionBackground\":\"#A9C1E2\",\"black\":\"#3E3E3E\",\"red\":\"#970B16\",\"green\":\"#07962A\",\"yellow\":\"#F8EEC7\",\"blue\":\"#003E8A\",\"cyan\":\"#89D1EC\",\"white\":\"#FFFFFF\",\"brightBlack\":\"#666666\",\"brightRed\":\"#DE0000\",\"brightGreen\":\"#87D5A2\",\"brightYellow\":\"#F1D007\",\"brightBlue\":\"#2E6CBA\",\"brightCyan\":\"#1CFAFE\",\"brightWhite\":\"#FFFFFF\"}', 'Github', '{\"dark\": false}', 160, '2024-08-19 18:53:39', '2024-08-19 18:53:39', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (404, 53, 'terminalTheme', '{\"background\":\"#1F1F1F\",\"foreground\":\"#B9BCBA\",\"cursor\":\"#F83E19\",\"selectionBackground\":\"#2A2D32\",\"black\":\"#3A3D43\",\"red\":\"#BE3F48\",\"green\":\"#879A3B\",\"yellow\":\"#C5A635\",\"blue\":\"#4F76A1\",\"cyan\":\"#578FA4\",\"white\":\"#B9BCBA\",\"brightBlack\":\"#888987\",\"brightRed\":\"#FB001F\",\"brightGreen\":\"#0F722F\",\"brightYellow\":\"#C47033\",\"brightBlue\":\"#186DE3\",\"brightCyan\":\"#2E706D\",\"brightWhite\":\"#FDFFB9\"}', 'DimmedMonokai', '{\"dark\": true}', 170, '2024-08-19 18:53:52', '2024-08-19 18:53:52', '1', '1', 0);
|
||||
INSERT INTO `dict_value` VALUES (405, 53, 'terminalTheme', '{\"background\":\"#1F1D27\",\"foreground\":\"#B7A1FF\",\"cursor\":\"#FF9839\",\"selectionBackground\":\"#353147\",\"black\":\"#1F1D27\",\"red\":\"#D9393E\",\"green\":\"#2DCD73\",\"yellow\":\"#D9B76E\",\"blue\":\"#FFC284\",\"cyan\":\"#2488FF\",\"white\":\"#B7A1FF\",\"brightBlack\":\"#353147\",\"brightRed\":\"#D9393E\",\"brightGreen\":\"#2DCD73\",\"brightYellow\":\"#D9B76E\",\"brightBlue\":\"#FFC284\",\"brightCyan\":\"#2488FF\",\"brightWhite\":\"#EAE5FF\"}', 'Duotone Dark', '{\"dark\": true}', 180, '2024-08-19 18:54:09', '2024-08-19 18:54:09', '1', '1', 0);
|
||||
|
||||
-- 菜单配置
|
||||
INSERT INTO `system_menu` VALUES (1, 0, '工作台', NULL, 1, 10, 1, 1, 1, 0, 'IconComputer', NULL, 'workplace', '2023-07-28 10:51:50', '2023-09-11 15:27:52', '1', '1', 0);
|
||||
@@ -389,7 +394,7 @@ INSERT INTO `system_menu` VALUES (154, 148, '清空连接日志', 'asset:host-co
|
||||
INSERT INTO `system_menu` VALUES (155, 148, '强制断开连接', 'asset:host-connect-log:management:force-offline', 3, 40, 1, 1, 1, 0, NULL, NULL, NULL, '2024-03-04 13:41:02', '2024-03-05 23:32:01', '1', '1', 0);
|
||||
INSERT INTO `system_menu` VALUES (156, 122, '删除操作日志', 'infra:operator-log:delete', 3, 20, 1, 1, 1, 0, NULL, NULL, NULL, '2024-03-04 17:06:55', '2024-03-04 17:08:22', '1', '1', 0);
|
||||
INSERT INTO `system_menu` VALUES (157, 122, '清空操作日志', 'infra:operator-log:management:clear', 3, 30, 1, 1, 1, 0, NULL, NULL, NULL, '2024-03-04 17:07:25', '2024-04-11 11:16:17', '1', '2', 0);
|
||||
INSERT INTO `system_menu` VALUES (158, 152, '文件操作日志', NULL, 2, 30, 1, 1, 1, 0, 'IconFile', NULL, 'sftpLog', '2024-03-05 15:30:13', '2024-05-07 11:11:24', '1', '1', 0);
|
||||
INSERT INTO `system_menu` VALUES (158, 152, '文件操作日志', NULL, 2, 40, 1, 1, 1, 0, 'IconFile', NULL, 'sftpLog', '2024-03-05 15:30:13', '2024-08-04 20:23:19', '1', '1', 0);
|
||||
INSERT INTO `system_menu` VALUES (159, 158, '查询文件操作日志', 'asset:host-sftp-log:management:query', 3, 10, 1, 1, 1, 0, NULL, NULL, NULL, '2024-03-05 15:31:02', '2024-04-12 14:49:18', '1', '1', 0);
|
||||
INSERT INTO `system_menu` VALUES (160, 158, '删除文件操作日志', 'asset:host-sftp-log:management:delete', 3, 20, 1, 1, 1, 0, NULL, NULL, NULL, '2024-03-05 15:31:17', '2024-04-12 14:49:21', '1', '1', 0);
|
||||
INSERT INTO `system_menu` VALUES (161, 176, '执行模板', NULL, 2, 50, 1, 1, 1, 0, 'IconBookmark', NULL, 'execTemplate', '2024-03-07 18:32:41', '2024-05-14 15:58:51', '1', '1', 0);
|
||||
|
||||
Reference in New Issue
Block a user