增加SSH连接。

This commit is contained in:
dengqichen 2025-12-05 17:21:50 +08:00
parent 598ab2503d
commit cca2fd8c4a
3 changed files with 80 additions and 31 deletions

View File

@ -19,4 +19,9 @@ public interface ISSHAuditLogRepository extends IBaseRepository<SSHAuditLog, Lon
* 统计用户当前活跃的SSH会话数
*/
long countByUserIdAndDisconnectTimeIsNull(Long userId);
/**
* 统计用户对指定服务器当前活跃的SSH会话数
*/
long countByUserIdAndServerIdAndDisconnectTimeIsNull(Long userId, Long serverId);
}

View File

@ -47,4 +47,13 @@ public interface ISSHAuditLogService extends IBaseService<SSHAuditLog, SSHAuditL
* @return 活跃会话数
*/
long countUserActiveSessions(Long userId);
/**
* 检查用户对指定服务器当前活跃的SSH会话数
*
* @param userId 用户ID
* @param serverId 服务器ID
* @return 活跃会话数
*/
long countUserActiveSessionsForServer(Long userId, Long serverId);
}

View File

@ -22,6 +22,7 @@ import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* SSH审计日志服务实现
@ -38,15 +39,39 @@ public class SSHAuditLogServiceImpl
@Resource
private IUserService userService;
/**
* 每个sessionId的锁对象用于防止并发创建重复的审计日志
* Key: sessionId, Value: 锁对象
*/
private final ConcurrentHashMap<String, Object> sessionLocks = new ConcurrentHashMap<>();
public SSHAuditLogServiceImpl(ISSHAuditLogRepository auditLogRepository) {
this.auditLogRepository = auditLogRepository;
}
/**
* 获取指定sessionId的锁对象如果不存在则创建
*/
private Object getSessionLock(String sessionId) {
return sessionLocks.computeIfAbsent(sessionId, k -> new Object());
}
@Override
@Transactional(rollbackFor = Exception.class)
public Long createAuditLog(Long userId, Server server, String sessionId, String clientIp, String userAgent) {
// 关键使用 sessionId 粒度的锁确保同一个 sessionId 的创建操作串行执行
Object lock = getSessionLock(sessionId);
synchronized (lock) {
log.info("创建SSH审计日志: userId={}, serverId={}, sessionId={}", userId, server.getId(), sessionId);
// 双重检查在锁内再次检查是否已存在防止并发重复创建
SSHAuditLog existing = auditLogRepository.findBySessionId(sessionId);
if (existing != null) {
log.warn("SSH审计日志已存在跳过创建: id={}, sessionId={}", existing.getId(), sessionId);
return existing.getId();
}
SSHAuditLog auditLog = new SSHAuditLog();
// 用户信息
@ -79,6 +104,7 @@ public class SSHAuditLogServiceImpl
return saved.getId();
}
}
@Override
@Transactional(rollbackFor = Exception.class)
@ -136,6 +162,10 @@ public class SSHAuditLogServiceImpl
log.info("SSH审计日志关闭: sessionId={}, status={}, duration={}秒",
sessionId, status, auditLog.getDurationSeconds());
// 清理锁对象避免内存泄漏
sessionLocks.remove(sessionId);
log.debug("清理sessionId锁对象: sessionId={}", sessionId);
} catch (Exception e) {
log.error("关闭审计日志失败: sessionId={}", sessionId, e);
}
@ -146,6 +176,11 @@ public class SSHAuditLogServiceImpl
return auditLogRepository.countByUserIdAndDisconnectTimeIsNull(userId);
}
@Override
public long countUserActiveSessionsForServer(Long userId, Long serverId) {
return auditLogRepository.countByUserIdAndServerIdAndDisconnectTimeIsNull(userId, serverId);
}
/**
* 解析命令JSON
*/