增加SSH连接。
This commit is contained in:
parent
598ab2503d
commit
cca2fd8c4a
@ -19,4 +19,9 @@ public interface ISSHAuditLogRepository extends IBaseRepository<SSHAuditLog, Lon
|
|||||||
* 统计用户当前活跃的SSH会话数
|
* 统计用户当前活跃的SSH会话数
|
||||||
*/
|
*/
|
||||||
long countByUserIdAndDisconnectTimeIsNull(Long userId);
|
long countByUserIdAndDisconnectTimeIsNull(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统计用户对指定服务器当前活跃的SSH会话数
|
||||||
|
*/
|
||||||
|
long countByUserIdAndServerIdAndDisconnectTimeIsNull(Long userId, Long serverId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,4 +47,13 @@ public interface ISSHAuditLogService extends IBaseService<SSHAuditLog, SSHAuditL
|
|||||||
* @return 活跃会话数
|
* @return 活跃会话数
|
||||||
*/
|
*/
|
||||||
long countUserActiveSessions(Long userId);
|
long countUserActiveSessions(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户对指定服务器当前活跃的SSH会话数
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param serverId 服务器ID
|
||||||
|
* @return 活跃会话数
|
||||||
|
*/
|
||||||
|
long countUserActiveSessionsForServer(Long userId, Long serverId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import java.time.Duration;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SSH审计日志服务实现
|
* SSH审计日志服务实现
|
||||||
@ -37,47 +38,72 @@ public class SSHAuditLogServiceImpl
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private IUserService userService;
|
private IUserService userService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每个sessionId的锁对象,用于防止并发创建重复的审计日志
|
||||||
|
* Key: sessionId, Value: 锁对象
|
||||||
|
*/
|
||||||
|
private final ConcurrentHashMap<String, Object> sessionLocks = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public SSHAuditLogServiceImpl(ISSHAuditLogRepository auditLogRepository) {
|
public SSHAuditLogServiceImpl(ISSHAuditLogRepository auditLogRepository) {
|
||||||
this.auditLogRepository = auditLogRepository;
|
this.auditLogRepository = auditLogRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定sessionId的锁对象(如果不存在则创建)
|
||||||
|
*/
|
||||||
|
private Object getSessionLock(String sessionId) {
|
||||||
|
return sessionLocks.computeIfAbsent(sessionId, k -> new Object());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Long createAuditLog(Long userId, Server server, String sessionId, String clientIp, String userAgent) {
|
public Long createAuditLog(Long userId, Server server, String sessionId, String clientIp, String userAgent) {
|
||||||
log.info("创建SSH审计日志: userId={}, serverId={}, sessionId={}", userId, server.getId(), sessionId);
|
// ⚠️ 关键:使用 sessionId 粒度的锁,确保同一个 sessionId 的创建操作串行执行
|
||||||
|
Object lock = getSessionLock(sessionId);
|
||||||
|
|
||||||
|
synchronized (lock) {
|
||||||
|
log.info("创建SSH审计日志: userId={}, serverId={}, sessionId={}", userId, server.getId(), sessionId);
|
||||||
|
|
||||||
SSHAuditLog auditLog = new SSHAuditLog();
|
// ⚠️ 双重检查:在锁内再次检查是否已存在(防止并发重复创建)
|
||||||
|
SSHAuditLog existing = auditLogRepository.findBySessionId(sessionId);
|
||||||
// 用户信息
|
if (existing != null) {
|
||||||
auditLog.setUserId(userId);
|
log.warn("SSH审计日志已存在,跳过创建: id={}, sessionId={}", existing.getId(), sessionId);
|
||||||
User user = userService.findEntityById(userId);
|
return existing.getId();
|
||||||
if (user != null) {
|
}
|
||||||
auditLog.setUsername(user.getUsername());
|
|
||||||
|
SSHAuditLog auditLog = new SSHAuditLog();
|
||||||
|
|
||||||
|
// 用户信息
|
||||||
|
auditLog.setUserId(userId);
|
||||||
|
User user = userService.findEntityById(userId);
|
||||||
|
if (user != null) {
|
||||||
|
auditLog.setUsername(user.getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 服务器信息
|
||||||
|
auditLog.setServerId(server.getId());
|
||||||
|
auditLog.setServerName(server.getServerName());
|
||||||
|
auditLog.setServerIp(server.getHostIp());
|
||||||
|
|
||||||
|
// 会话信息
|
||||||
|
auditLog.setSessionId(sessionId);
|
||||||
|
auditLog.setConnectTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
// 客户端信息
|
||||||
|
auditLog.setClientIp(clientIp);
|
||||||
|
auditLog.setUserAgent(userAgent);
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
auditLog.setCommandCount(0);
|
||||||
|
auditLog.setCommands("[]");
|
||||||
|
auditLog.setStatus("CONNECTED");
|
||||||
|
|
||||||
|
SSHAuditLog saved = auditLogRepository.save(auditLog);
|
||||||
|
log.info("SSH审计日志创建成功: id={}", saved.getId());
|
||||||
|
|
||||||
|
return saved.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 服务器信息
|
|
||||||
auditLog.setServerId(server.getId());
|
|
||||||
auditLog.setServerName(server.getServerName());
|
|
||||||
auditLog.setServerIp(server.getHostIp());
|
|
||||||
|
|
||||||
// 会话信息
|
|
||||||
auditLog.setSessionId(sessionId);
|
|
||||||
auditLog.setConnectTime(LocalDateTime.now());
|
|
||||||
|
|
||||||
// 客户端信息
|
|
||||||
auditLog.setClientIp(clientIp);
|
|
||||||
auditLog.setUserAgent(userAgent);
|
|
||||||
|
|
||||||
// 初始化
|
|
||||||
auditLog.setCommandCount(0);
|
|
||||||
auditLog.setCommands("[]");
|
|
||||||
auditLog.setStatus("CONNECTED");
|
|
||||||
|
|
||||||
SSHAuditLog saved = auditLogRepository.save(auditLog);
|
|
||||||
log.info("SSH审计日志创建成功: id={}", saved.getId());
|
|
||||||
|
|
||||||
return saved.getId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -136,6 +162,10 @@ public class SSHAuditLogServiceImpl
|
|||||||
log.info("SSH审计日志关闭: sessionId={}, status={}, duration={}秒",
|
log.info("SSH审计日志关闭: sessionId={}, status={}, duration={}秒",
|
||||||
sessionId, status, auditLog.getDurationSeconds());
|
sessionId, status, auditLog.getDurationSeconds());
|
||||||
|
|
||||||
|
// ⚠️ 清理锁对象,避免内存泄漏
|
||||||
|
sessionLocks.remove(sessionId);
|
||||||
|
log.debug("清理sessionId锁对象: sessionId={}", sessionId);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("关闭审计日志失败: sessionId={}", sessionId, e);
|
log.error("关闭审计日志失败: sessionId={}", sessionId, e);
|
||||||
}
|
}
|
||||||
@ -146,6 +176,11 @@ public class SSHAuditLogServiceImpl
|
|||||||
return auditLogRepository.countByUserIdAndDisconnectTimeIsNull(userId);
|
return auditLogRepository.countByUserIdAndDisconnectTimeIsNull(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countUserActiveSessionsForServer(Long userId, Long serverId) {
|
||||||
|
return auditLogRepository.countByUserIdAndServerIdAndDisconnectTimeIsNull(userId, serverId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析命令JSON
|
* 解析命令JSON
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user