feat: 优化日志记录,避免在登录和错误处理时输出敏感信息
This commit is contained in:
@@ -28,7 +28,8 @@ public class AuthController {
|
||||
@PostMapping("/login")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public Mono<LoginResponse> login(@Valid @RequestBody LoginRequest req) {
|
||||
log.info("/api/auth/login called username={}", req.getUsername());
|
||||
// Avoid logging raw usernames at info level
|
||||
log.debug("/api/auth/login called");
|
||||
return authService.login(req);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ public class QrProxyController {
|
||||
// 通过codeNo查询machineId
|
||||
String machineId = linkStatusService.getMechainIdByCode(codeNo);
|
||||
if (machineId == null) {
|
||||
log.warn("无法找到codeNo对应的machineId: {}", codeNo);
|
||||
log.warn("无法找到codeNo对应的machineId");
|
||||
return createNotFoundResponseMono();
|
||||
}
|
||||
|
||||
@@ -70,11 +70,11 @@ public class QrProxyController {
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=qr.png")
|
||||
.body(bytes))
|
||||
.onErrorResume(WebClientResponseException.NotFound.class, ex -> {
|
||||
log.warn("图片不存在: path={}", path);
|
||||
log.warn("图片不存在");
|
||||
return createNotFoundResponseMono();
|
||||
})
|
||||
.onErrorResume(WebClientResponseException.class, ex -> {
|
||||
log.warn("获取图片失败: path={}, status={}, error={}", path, ex.getStatusCode(), ex.getMessage());
|
||||
log.warn("获取图片失败: status={}, error={}", ex.getStatusCode(), ex.getMessage());
|
||||
return Mono.just(ResponseEntity.status(ex.getStatusCode()).build());
|
||||
});
|
||||
}
|
||||
@@ -86,7 +86,7 @@ public class QrProxyController {
|
||||
.flatMap(linkStatus -> {
|
||||
String machineId = linkStatus.getMachineId();
|
||||
if (machineId == null) {
|
||||
log.warn("无法找到codeNo对应的machineId: {}", codeNo);
|
||||
log.warn("无法找到codeNo对应的machineId");
|
||||
return createNotFoundResponseMono();
|
||||
}
|
||||
|
||||
@@ -98,16 +98,16 @@ public class QrProxyController {
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=homepage.png")
|
||||
.body(bytes))
|
||||
.onErrorResume(WebClientResponseException.NotFound.class, ex -> {
|
||||
log.warn("图片不存在: path={}", path);
|
||||
log.warn("图片不存在");
|
||||
return createNotFoundResponseMono();
|
||||
})
|
||||
.onErrorResume(WebClientResponseException.class, ex -> {
|
||||
log.warn("获取图片失败: path={}, status={}, error={}", path, ex.getStatusCode(), ex.getMessage());
|
||||
log.warn("获取图片失败: status={}, error={}", ex.getStatusCode(), ex.getMessage());
|
||||
return Mono.just(ResponseEntity.status(ex.getStatusCode()).build());
|
||||
});
|
||||
})
|
||||
.onErrorResume(Exception.class, ex -> {
|
||||
log.error("获取链接状态失败: codeNo={}, error={}", codeNo, ex.getMessage());
|
||||
log.error("获取链接状态失败: {}", ex.getMessage());
|
||||
return createInternalServerErrorResponseMono();
|
||||
});
|
||||
}
|
||||
@@ -119,7 +119,7 @@ public class QrProxyController {
|
||||
.flatMap(linkStatus -> {
|
||||
String machineId = linkStatus.getMachineId();
|
||||
if (machineId == null) {
|
||||
log.warn("无法找到codeNo对应的machineId: {}", codeNo);
|
||||
log.warn("无法找到codeNo对应的machineId");
|
||||
return createNotFoundResponseMono();
|
||||
}
|
||||
|
||||
@@ -131,16 +131,16 @@ public class QrProxyController {
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=first-reward.png")
|
||||
.body(bytes))
|
||||
.onErrorResume(WebClientResponseException.NotFound.class, ex -> {
|
||||
log.warn("图片不存在: path={}", path);
|
||||
log.warn("图片不存在");
|
||||
return createNotFoundResponseMono();
|
||||
})
|
||||
.onErrorResume(WebClientResponseException.class, ex -> {
|
||||
log.warn("获取图片失败: path={}, status={}, error={}", path, ex.getStatusCode(), ex.getMessage());
|
||||
log.warn("获取图片失败: status={}, error={}", ex.getStatusCode(), ex.getMessage());
|
||||
return Mono.just(ResponseEntity.status(ex.getStatusCode()).build());
|
||||
});
|
||||
})
|
||||
.onErrorResume(Exception.class, ex -> {
|
||||
log.error("获取链接状态失败: codeNo={}, error={}", codeNo, ex.getMessage());
|
||||
log.error("获取链接状态失败: {}", ex.getMessage());
|
||||
return createInternalServerErrorResponseMono();
|
||||
});
|
||||
}
|
||||
@@ -152,7 +152,7 @@ public class QrProxyController {
|
||||
.flatMap(linkStatus -> {
|
||||
String machineId = linkStatus.getMachineId();
|
||||
if (machineId == null) {
|
||||
log.warn("无法找到codeNo对应的machineId: {}", codeNo);
|
||||
log.warn("无法找到codeNo对应的machineId");
|
||||
return createNotFoundResponseMono();
|
||||
}
|
||||
|
||||
@@ -164,16 +164,16 @@ public class QrProxyController {
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=mid-reward.png")
|
||||
.body(bytes))
|
||||
.onErrorResume(WebClientResponseException.NotFound.class, ex -> {
|
||||
log.warn("图片不存在: path={}", path);
|
||||
log.warn("图片不存在");
|
||||
return createNotFoundResponseMono();
|
||||
})
|
||||
.onErrorResume(WebClientResponseException.class, ex -> {
|
||||
log.warn("获取图片失败: path={}, status={}, error={}", path, ex.getStatusCode(), ex.getMessage());
|
||||
log.warn("获取图片失败: status={}, error={}", ex.getStatusCode(), ex.getMessage());
|
||||
return Mono.just(ResponseEntity.status(ex.getStatusCode()).build());
|
||||
});
|
||||
})
|
||||
.onErrorResume(Exception.class, ex -> {
|
||||
log.error("获取链接状态失败: codeNo={}, error={}", codeNo, ex.getMessage());
|
||||
log.error("获取链接状态失败: {}", ex.getMessage());
|
||||
return createInternalServerErrorResponseMono();
|
||||
});
|
||||
}
|
||||
@@ -315,4 +315,3 @@ public class QrProxyController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.gameplatform.server.mapper.lock;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
@Mapper
|
||||
public interface LockMapper {
|
||||
|
||||
/**
|
||||
* Try to acquire a named MySQL advisory lock. Returns 1 if acquired, 0 if timeout, NULL on error.
|
||||
*/
|
||||
@Select("SELECT GET_LOCK(#{name}, #{timeoutSeconds})")
|
||||
Integer getLock(@Param("name") String name, @Param("timeoutSeconds") int timeoutSeconds);
|
||||
|
||||
/**
|
||||
* Release the named advisory lock. Returns 1 if released, 0 if not held, NULL on error.
|
||||
*/
|
||||
@Select("SELECT RELEASE_LOCK(#{name})")
|
||||
Integer releaseLock(@Param("name") String name);
|
||||
}
|
||||
|
||||
@@ -124,7 +124,12 @@ public class MachineCooldownService {
|
||||
*/
|
||||
@Transactional
|
||||
public void addMachineToCooldown(String machineId, String reason) {
|
||||
addMachineToCooldown(machineId, reason, null);
|
||||
try {
|
||||
addMachineToCooldown(machineId, reason, null);
|
||||
} catch (RuntimeException ex) {
|
||||
// 当上层已完成占用(或并发占用导致唯一键冲突)时,吞掉异常以便上层逻辑继续
|
||||
log.warn("添加冷却记录失败或已存在,machineId={},原因={}(忽略)", machineId, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,10 +149,10 @@ public class MachineCooldownService {
|
||||
LocalDateTime cooldownEndTime = now.plusMinutes(COOLDOWN_MINUTES);
|
||||
|
||||
try {
|
||||
// 先移除该设备现有的活跃冷却记录
|
||||
// 先移除该设备现有的活跃冷却记录(若存在非并发场景下的残留)
|
||||
machineCooldownMapper.removeMachineCooldown(machineId);
|
||||
|
||||
// 创建新的冷却记录
|
||||
// 创建新的冷却记录(依赖数据库唯一约束防止并发重复占用)
|
||||
MachineCooldown cooldown = new MachineCooldown(
|
||||
machineId, now, cooldownEndTime, reason, linkTaskId);
|
||||
machineCooldownMapper.insert(cooldown);
|
||||
@@ -160,8 +165,8 @@ public class MachineCooldownService {
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("将机器{}加入冷却队列失败:{}", machineId, e.getMessage(), e);
|
||||
// 即使数据库操作失败,也要更新缓存作为备用
|
||||
machineCooldownCache.put(machineId, now);
|
||||
// 抛出异常,交由上层流程回滚/重试,避免同一设备被并发占用
|
||||
throw new RuntimeException("设备正忙或分配冲突,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
-- Add a unique constraint to ensure a device has at most one ACTIVE cooldown record at a time.
|
||||
-- This helps prevent concurrent assignments of the same machine to multiple links.
|
||||
|
||||
ALTER TABLE machine_cooldown
|
||||
ADD UNIQUE KEY ux_machine_cooldown_active (machine_id, status);
|
||||
|
||||
Reference in New Issue
Block a user