fix:审计npe

This commit is contained in:
waner
2026-04-25 11:44:47 +08:00
parent 57ebf819a3
commit 779052142b
3 changed files with 243 additions and 9 deletions
@@ -1,7 +1,12 @@
package com.cisd.tms.modules.log.aspect;
import com.cisd.tms.common.api.ApiResponse;
import com.cisd.tms.modules.auth.dto.LoginResponse;
import com.cisd.tms.modules.auth.dto.PasswordLoginRequest;
import com.cisd.tms.modules.auth.dto.UkeyLoginRequest;
import com.cisd.tms.modules.log.annotation.AuditedOperation;
import com.cisd.tms.modules.log.dto.OperationAuditCommand;
import com.cisd.tms.modules.log.enums.ActionType;
import com.cisd.tms.modules.log.enums.AuthLevel;
import com.cisd.tms.modules.log.enums.OperationResult;
import com.cisd.tms.modules.log.enums.OperatorRoleCode;
@@ -16,6 +21,8 @@ import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.stream.Collectors;
@Aspect
@Component
public class OperationAuditAspect {
@@ -33,13 +40,18 @@ public class OperationAuditAspect {
command.setActionType(auditedOperation.action());
command.setSummary(auditedOperation.summary());
//todo 后续测
// 获取上下文信息
// 获取已认证请求上下文;登录接口尚未有会话,会在下面从登录请求体补充。
getContextInfo(command);
if (ActionType.LOGIN == auditedOperation.action()) {
getLoginRequestContext(command, joinPoint.getArgs());
}
Object result = null;
try {
result = joinPoint.proceed();
if (ActionType.LOGIN == auditedOperation.action()) {
getLoginResponseContext(command, result);
}
command.setOperationResult(OperationResult.SUCCESS);
return result;
@@ -69,12 +81,98 @@ public class OperationAuditAspect {
Object roleObj = request.getAttribute(InternalApiAuthInterceptor.ATTR_ROLE_CODE);
command.setOperatorRoleCode(OperatorRoleCode.valueOf(roleObj.toString()));
setOperatorRoleCode(command, roleObj);
Object levelObj = request.getAttribute(InternalApiAuthInterceptor.ATTR_AUTH_LEVEL);
command.setOperatorAuthLevel(AuthLevel.valueOf(levelObj.toString()));
setOperatorAuthLevel(command, levelObj);
command.setRemoteIp(request.getRemoteAddr());
}
}
}
private void getLoginRequestContext(OperationAuditCommand command, Object[] args) {
if (args == null) {
return;
}
for (Object arg : args) {
if (arg instanceof PasswordLoginRequest request) {
setOperatorRoleCode(command, request.getRoleCode());
appendLoginSummary(command, request.getRoleCode(), passwordLoginAccounts(request));
return;
}
if (arg instanceof UkeyLoginRequest request) {
setOperatorRoleCode(command, request.getRoleCode());
appendLoginSummary(command, request.getRoleCode(), ukeyLoginUids(request));
return;
}
}
}
private void getLoginResponseContext(OperationAuditCommand command, Object result) {
if (result instanceof ApiResponse<?> apiResponse && apiResponse.getData() instanceof LoginResponse loginResponse) {
setOperatorRoleCode(command, loginResponse.getRoleCode());
setOperatorAuthLevel(command, loginResponse.getAuthLevel());
}
}
private void setOperatorRoleCode(OperationAuditCommand command, Object roleObj) {
if (roleObj == null || roleObj.toString().isBlank()) {
return;
}
try {
command.setOperatorRoleCode(OperatorRoleCode.valueOf(roleObj.toString()));
} catch (IllegalArgumentException ignored) {
// 保留空值,避免审计上下文解析异常反向阻断登录或业务请求。
}
}
private void setOperatorAuthLevel(OperationAuditCommand command, Object levelObj) {
if (levelObj == null || levelObj.toString().isBlank()) {
return;
}
try {
command.setOperatorAuthLevel(AuthLevel.valueOf(levelObj.toString()));
} catch (IllegalArgumentException ignored) {
// 保留空值,避免审计上下文解析异常反向阻断登录或业务请求。
}
}
private String passwordLoginAccounts(PasswordLoginRequest request) {
if (request.getAccounts() == null || request.getAccounts().isEmpty()) {
return "";
}
return request.getAccounts().stream()
.map(account -> account.getUsername() == null ? "" : account.getUsername().trim())
.filter(value -> !value.isBlank())
.collect(Collectors.joining(","));
}
private String ukeyLoginUids(UkeyLoginRequest request) {
if (request.getLoginFactors() == null || request.getLoginFactors().isEmpty()) {
return "";
}
return request.getLoginFactors().stream()
.map(factor -> factor.getUid() == null ? "" : "uid=" + factor.getUid())
.filter(value -> !value.isBlank())
.collect(Collectors.joining(","));
}
private void appendLoginSummary(OperationAuditCommand command, String roleCode, String principalText) {
StringBuilder builder = new StringBuilder(command.getSummary() == null ? "" : command.getSummary());
if ((roleCode == null || roleCode.isBlank()) && (principalText == null || principalText.isBlank())) {
return;
}
builder.append(" [");
if (roleCode != null && !roleCode.isBlank()) {
builder.append("role=").append(roleCode);
}
if (principalText != null && !principalText.isBlank()) {
if (roleCode != null && !roleCode.isBlank()) {
builder.append(", ");
}
builder.append("principal=").append(principalText);
}
builder.append("]");
command.setSummary(builder.toString());
}
}
@@ -89,11 +89,22 @@ public class OperationAuditService {
// 从上下文中获取刚才解析出的用户信息
Object roleObj = request.getAttribute(ATTR_ROLE_CODE);
// todo 是否考虑未知情况
command.setOperatorRoleCode(OperatorRoleCode.valueOf(roleObj.toString()));
if (roleObj != null && !roleObj.toString().isBlank()) {
try {
command.setOperatorRoleCode(OperatorRoleCode.valueOf(roleObj.toString()));
} catch (IllegalArgumentException ignored) {
// 保留空值,避免审计上下文解析失败影响原始越权响应。
}
}
Object levelObj = request.getAttribute(ATTR_AUTH_LEVEL);
command.setOperatorAuthLevel(AuthLevel.valueOf(levelObj.toString()));
if (levelObj != null && !levelObj.toString().isBlank()) {
try {
command.setOperatorAuthLevel(AuthLevel.valueOf(levelObj.toString()));
} catch (IllegalArgumentException ignored) {
// 保留空值,避免审计上下文解析失败影响原始越权响应。
}
}
command.setRemoteIp(request.getRemoteAddr());
command.setErrorMessage(errorMsg);
@@ -238,4 +249,4 @@ public class OperationAuditService {
private String trim(String s){
return s == null ? "" : s.trim();
}
}
}