错误码梳理
This commit is contained in:
@@ -3,9 +3,13 @@ package com.cisd.tms.common.enums;
|
|||||||
public enum ErrorCode {
|
public enum ErrorCode {
|
||||||
BAD_REQUEST(400, "bad request"),
|
BAD_REQUEST(400, "bad request"),
|
||||||
UNAUTHORIZED(4010, "unauthorized"),
|
UNAUTHORIZED(4010, "unauthorized"),
|
||||||
|
SESSION_INVALID(4011, "session invalid"),
|
||||||
|
FORBIDDEN(4030, "forbidden"),
|
||||||
VALIDATE_FAILED(4001, "parameter validation failed"),
|
VALIDATE_FAILED(4001, "parameter validation failed"),
|
||||||
|
CONFLICT(4090, "conflict"),
|
||||||
BIZ_ERROR(5001, "business exception"),
|
BIZ_ERROR(5001, "business exception"),
|
||||||
CRYPTO_CARD_ERROR(5201, "crypto card adapter error"),
|
CRYPTO_CARD_ERROR(5201, "crypto card adapter error"),
|
||||||
|
SERVICE_UNAVAILABLE(5030, "service unavailable"),
|
||||||
INTERNAL_ERROR(5000, "internal server error");
|
INTERNAL_ERROR(5000, "internal server error");
|
||||||
|
|
||||||
private final int code;
|
private final int code;
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||||||
import jakarta.validation.ConstraintViolationException;
|
import jakarta.validation.ConstraintViolationException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.validation.FieldError;
|
import org.springframework.validation.FieldError;
|
||||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
@@ -20,7 +22,7 @@ public class GlobalExceptionHandler {
|
|||||||
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
||||||
|
|
||||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
public ApiResponse<Void> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpServletRequest request) {
|
public ResponseEntity<ApiResponse<Void>> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpServletRequest request) {
|
||||||
String msg = ex.getBindingResult().getAllErrors().stream()
|
String msg = ex.getBindingResult().getAllErrors().stream()
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.map(error -> {
|
.map(error -> {
|
||||||
@@ -30,53 +32,84 @@ public class GlobalExceptionHandler {
|
|||||||
return error.getDefaultMessage();
|
return error.getDefaultMessage();
|
||||||
})
|
})
|
||||||
.orElse(ErrorCode.VALIDATE_FAILED.getMessage());
|
.orElse(ErrorCode.VALIDATE_FAILED.getMessage());
|
||||||
return ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), msg).withPath(request.getRequestURI());
|
return response(HttpStatus.BAD_REQUEST, ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), msg).withPath(request.getRequestURI()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(ConstraintViolationException.class)
|
@ExceptionHandler(ConstraintViolationException.class)
|
||||||
public ApiResponse<Void> handleConstraintViolation(ConstraintViolationException ex, HttpServletRequest request) {
|
public ResponseEntity<ApiResponse<Void>> handleConstraintViolation(ConstraintViolationException ex, HttpServletRequest request) {
|
||||||
return ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), ex.getMessage()).withPath(request.getRequestURI());
|
return response(HttpStatus.BAD_REQUEST,
|
||||||
|
ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), ex.getMessage()).withPath(request.getRequestURI()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(BizException.class)
|
@ExceptionHandler(BizException.class)
|
||||||
public ApiResponse<Void> handleBizException(BizException ex, HttpServletRequest request) {
|
public ResponseEntity<ApiResponse<Void>> handleBizException(BizException ex, HttpServletRequest request) {
|
||||||
return ApiResponse.fail(ex.getCode(), ex.getMessage()).withPath(request.getRequestURI());
|
return response(resolveHttpStatus(ex.getCode()),
|
||||||
|
ApiResponse.fail(ex.getCode(), ex.getMessage()).withPath(request.getRequestURI()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(IllegalArgumentException.class)
|
@ExceptionHandler(IllegalArgumentException.class)
|
||||||
public ApiResponse<Void> handleIllegalArgument(IllegalArgumentException ex, HttpServletRequest request) {
|
public ResponseEntity<ApiResponse<Void>> handleIllegalArgument(IllegalArgumentException ex, HttpServletRequest request) {
|
||||||
return ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), ex.getMessage()).withPath(request.getRequestURI());
|
return response(HttpStatus.BAD_REQUEST,
|
||||||
|
ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), ex.getMessage()).withPath(request.getRequestURI()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(MaxUploadSizeExceededException.class)
|
@ExceptionHandler(MaxUploadSizeExceededException.class)
|
||||||
public ApiResponse<Void> handleMaxUploadSizeExceeded(MaxUploadSizeExceededException ex, HttpServletRequest request) {
|
public ResponseEntity<ApiResponse<Void>> handleMaxUploadSizeExceeded(MaxUploadSizeExceededException ex, HttpServletRequest request) {
|
||||||
return ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), "upload file size exceeds limit")
|
return response(HttpStatus.BAD_REQUEST, ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), "upload file size exceeds limit")
|
||||||
.withPath(request.getRequestURI());
|
.withPath(request.getRequestURI()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(MultipartException.class)
|
@ExceptionHandler(MultipartException.class)
|
||||||
public ApiResponse<Void> handleMultipartException(MultipartException ex, HttpServletRequest request) {
|
public ResponseEntity<ApiResponse<Void>> handleMultipartException(MultipartException ex, HttpServletRequest request) {
|
||||||
return ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), "failed to parse multipart request")
|
return response(HttpStatus.BAD_REQUEST, ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), "failed to parse multipart request")
|
||||||
.withPath(request.getRequestURI());
|
.withPath(request.getRequestURI()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(PcieCryptoException.class)
|
@ExceptionHandler(PcieCryptoException.class)
|
||||||
public ApiResponse<Void> handleCryptoCardException(PcieCryptoException ex, HttpServletRequest request) {
|
public ResponseEntity<ApiResponse<Void>> handleCryptoCardException(PcieCryptoException ex, HttpServletRequest request) {
|
||||||
return ApiResponse.fail(ErrorCode.CRYPTO_CARD_ERROR.getCode(), ex.getMessage())
|
return response(HttpStatus.INTERNAL_SERVER_ERROR, ApiResponse.fail(ErrorCode.CRYPTO_CARD_ERROR.getCode(), ex.getMessage())
|
||||||
.withPath(request.getRequestURI());
|
.withPath(request.getRequestURI()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(ReplayProtectionException.class)
|
@ExceptionHandler(ReplayProtectionException.class)
|
||||||
public ApiResponse<Void> handleReplayProtectionException(ReplayProtectionException ex, HttpServletRequest request) {
|
public ResponseEntity<ApiResponse<Void>> handleReplayProtectionException(ReplayProtectionException ex, HttpServletRequest request) {
|
||||||
log.warn("Replay protection failed", ex);
|
log.warn("Replay protection failed", ex);
|
||||||
return ApiResponse.fail(ErrorCode.INTERNAL_ERROR.getCode(), "replay protection unavailable")
|
return response(HttpStatus.SERVICE_UNAVAILABLE,
|
||||||
.withPath(request.getRequestURI());
|
ApiResponse.fail(ErrorCode.SERVICE_UNAVAILABLE.getCode(), "replay protection unavailable")
|
||||||
|
.withPath(request.getRequestURI()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(Exception.class)
|
@ExceptionHandler(Exception.class)
|
||||||
public ApiResponse<Void> handleException(Exception ex, HttpServletRequest request) {
|
public ResponseEntity<ApiResponse<Void>> handleException(Exception ex, HttpServletRequest request) {
|
||||||
log.error("Unhandled exception", ex);
|
log.error("Unhandled exception", ex);
|
||||||
return ApiResponse.fail(ErrorCode.INTERNAL_ERROR.getCode(), ErrorCode.INTERNAL_ERROR.getMessage())
|
return response(HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
.withPath(request.getRequestURI());
|
ApiResponse.fail(ErrorCode.INTERNAL_ERROR.getCode(), ErrorCode.INTERNAL_ERROR.getMessage())
|
||||||
|
.withPath(request.getRequestURI()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseEntity<ApiResponse<Void>> response(HttpStatus status, ApiResponse<Void> body) {
|
||||||
|
return ResponseEntity.status(status).body(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpStatus resolveHttpStatus(int code) {
|
||||||
|
if (code == ErrorCode.BAD_REQUEST.getCode() || code == ErrorCode.VALIDATE_FAILED.getCode()) {
|
||||||
|
return HttpStatus.BAD_REQUEST;
|
||||||
|
}
|
||||||
|
if (code == ErrorCode.UNAUTHORIZED.getCode()) {
|
||||||
|
return HttpStatus.UNAUTHORIZED;
|
||||||
|
}
|
||||||
|
if (code == ErrorCode.SESSION_INVALID.getCode()) {
|
||||||
|
return HttpStatus.UNAUTHORIZED;
|
||||||
|
}
|
||||||
|
if (code == ErrorCode.FORBIDDEN.getCode()) {
|
||||||
|
return HttpStatus.FORBIDDEN;
|
||||||
|
}
|
||||||
|
if (code == ErrorCode.CONFLICT.getCode()) {
|
||||||
|
return HttpStatus.CONFLICT;
|
||||||
|
}
|
||||||
|
if (code == ErrorCode.SERVICE_UNAVAILABLE.getCode()) {
|
||||||
|
return HttpStatus.SERVICE_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
return HttpStatus.INTERNAL_SERVER_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -63,7 +63,7 @@ public class InternalAuthorizationInterceptor implements HandlerInterceptor {
|
|||||||
HttpResponseUtil.writeJson(
|
HttpResponseUtil.writeJson(
|
||||||
response,
|
response,
|
||||||
HttpServletResponse.SC_FORBIDDEN,
|
HttpServletResponse.SC_FORBIDDEN,
|
||||||
ApiResponse.fail(ErrorCode.UNAUTHORIZED.getCode(), message),
|
ApiResponse.fail(ErrorCode.FORBIDDEN.getCode(), message),
|
||||||
objectMapper
|
objectMapper
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -461,9 +461,9 @@ public class AuthServiceImpl implements AuthService {
|
|||||||
|
|
||||||
private AuthSessionEntity requireActiveSession(String sessionToken) {
|
private AuthSessionEntity requireActiveSession(String sessionToken) {
|
||||||
AuthSessionEntity session = authSessionRepository.findBySessionToken(sessionToken)
|
AuthSessionEntity session = authSessionRepository.findBySessionToken(sessionToken)
|
||||||
.orElseThrow(() -> new BizException(ErrorCode.UNAUTHORIZED.getCode(), "session not found"));
|
.orElseThrow(() -> new BizException(ErrorCode.SESSION_INVALID.getCode(), "session not found"));
|
||||||
if (session.getLogoutAt() != null || session.getExpiresAt() == null || !session.getExpiresAt().isAfter(now())) {
|
if (session.getLogoutAt() != null || session.getExpiresAt() == null || !session.getExpiresAt().isAfter(now())) {
|
||||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "session expired");
|
throw new BizException(ErrorCode.SESSION_INVALID.getCode(), "session expired");
|
||||||
}
|
}
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package com.cisd.tms.modules.device.controller;
|
|||||||
|
|
||||||
|
|
||||||
import com.cisd.tms.common.api.ApiResponse;
|
import com.cisd.tms.common.api.ApiResponse;
|
||||||
|
import com.cisd.tms.common.enums.ErrorCode;
|
||||||
|
import com.cisd.tms.common.exception.BizException;
|
||||||
import com.cisd.tms.modules.device.dto.network.*;
|
import com.cisd.tms.modules.device.dto.network.*;
|
||||||
import com.cisd.tms.modules.device.service.NetworkConfigService;
|
import com.cisd.tms.modules.device.service.NetworkConfigService;
|
||||||
import com.cisd.tms.modules.log.annotation.AuditedOperation;
|
import com.cisd.tms.modules.log.annotation.AuditedOperation;
|
||||||
@@ -122,7 +124,7 @@ public class NetworkConfigController {
|
|||||||
String mode = networkConfigService.getBondMode(bondName);
|
String mode = networkConfigService.getBondMode(bondName);
|
||||||
|
|
||||||
if (mode == null) {
|
if (mode == null) {
|
||||||
return ApiResponse.fail(400, "未找到该连接的 Bond 模式", null);
|
throw new BizException(ErrorCode.BAD_REQUEST.getCode(), "未找到该连接的 Bond 模式");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ApiResponse.success(mode);
|
return ApiResponse.success(mode);
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package com.cisd.tms.modules.device.filter;
|
package com.cisd.tms.modules.device.filter;
|
||||||
|
|
||||||
|
import com.cisd.tms.common.api.ApiResponse;
|
||||||
|
import com.cisd.tms.common.enums.ErrorCode;
|
||||||
|
import com.cisd.tms.common.util.HttpResponseUtil;
|
||||||
import com.cisd.tms.modules.device.service.IpWhitelistService;
|
import com.cisd.tms.modules.device.service.IpWhitelistService;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
@@ -17,6 +21,9 @@ public class IpWhitelistFilter implements Filter {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IpWhitelistService ipWhitelistService;
|
private IpWhitelistService ipWhitelistService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
|
||||||
@@ -39,9 +46,7 @@ public class IpWhitelistFilter implements Filter {
|
|||||||
try {
|
try {
|
||||||
clientIpInt = ipToInt(clientIp);
|
clientIpInt = ipToInt(clientIp);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
writeForbidden(response, "非法的客户端 IP 格式,拒绝访问");
|
||||||
response.setContentType("application/json;charset=utf-8");
|
|
||||||
response.getWriter().write("{\"code\": 403, \"msg\": \"非法的客户端 IP 格式,拒绝访问\"}");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,9 +77,7 @@ public class IpWhitelistFilter implements Filter {
|
|||||||
|
|
||||||
// 默认拒绝
|
// 默认拒绝
|
||||||
if (!isAllowed) {
|
if (!isAllowed) {
|
||||||
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
writeForbidden(response, "非法访问:您的IP不在允许的白名单内");
|
||||||
response.setContentType("application/json;charset=utf-8");
|
|
||||||
response.getWriter().write("{\"code\": 403, \"msg\": \"非法访问:您的IP不在允许的白名单内\"}");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,4 +139,13 @@ public class IpWhitelistFilter implements Filter {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeForbidden(HttpServletResponse response, String message) throws IOException {
|
||||||
|
HttpResponseUtil.writeJson(
|
||||||
|
response,
|
||||||
|
HttpServletResponse.SC_FORBIDDEN,
|
||||||
|
ApiResponse.fail(ErrorCode.FORBIDDEN.getCode(), message),
|
||||||
|
objectMapper
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package com.cisd.tms.modules.log.controller;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.cisd.tms.common.api.ApiResponse;
|
import com.cisd.tms.common.api.ApiResponse;
|
||||||
|
import com.cisd.tms.common.enums.ErrorCode;
|
||||||
|
import com.cisd.tms.common.exception.BizException;
|
||||||
import com.cisd.tms.modules.log.dto.AuditLogReviewRequest;
|
import com.cisd.tms.modules.log.dto.AuditLogReviewRequest;
|
||||||
import com.cisd.tms.modules.log.dto.OperationAuditLogPageRequest;
|
import com.cisd.tms.modules.log.dto.OperationAuditLogPageRequest;
|
||||||
import com.cisd.tms.modules.log.dto.OperationAuditLogPageResponse;
|
import com.cisd.tms.modules.log.dto.OperationAuditLogPageResponse;
|
||||||
@@ -50,7 +52,7 @@ public class OperationAuditController {
|
|||||||
|
|
||||||
// 权限校验:仅审计管理员可操作
|
// 权限校验:仅审计管理员可操作
|
||||||
if (roleObj == null || !roleObj.toString().equals("AUDIT_ADMIN")) {
|
if (roleObj == null || !roleObj.toString().equals("AUDIT_ADMIN")) {
|
||||||
return ApiResponse.fail(403, "权限不足:仅审计管理员可执行此操作");
|
throw new BizException(ErrorCode.FORBIDDEN.getCode(), "权限不足:仅审计管理员可执行此操作");
|
||||||
}
|
}
|
||||||
|
|
||||||
auditorUser = roleObj.toString();
|
auditorUser = roleObj.toString();
|
||||||
|
|||||||
@@ -51,17 +51,17 @@ public class InternalApiAuthInterceptor implements HandlerInterceptor {
|
|||||||
|
|
||||||
String sessionToken = extractSessionToken(request);
|
String sessionToken = extractSessionToken(request);
|
||||||
if (sessionToken == null || sessionToken.isBlank()) {
|
if (sessionToken == null || sessionToken.isBlank()) {
|
||||||
writeUnauthorized(response, "session token missing");
|
writeSessionInvalid(response, "session token missing");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthSessionEntity session = authSessionRepository.findBySessionToken(sessionToken).orElse(null);
|
AuthSessionEntity session = authSessionRepository.findBySessionToken(sessionToken).orElse(null);
|
||||||
if (session == null || session.getLogoutAt() != null) {
|
if (session == null || session.getLogoutAt() != null) {
|
||||||
writeUnauthorized(response, "session not found");
|
writeSessionInvalid(response, "session not found");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (session.getExpiresAt() == null || !session.getExpiresAt().isAfter(now())) {
|
if (session.getExpiresAt() == null || !session.getExpiresAt().isAfter(now())) {
|
||||||
writeUnauthorized(response, "session expired");
|
writeSessionInvalid(response, "session expired");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,4 +99,13 @@ public class InternalApiAuthInterceptor implements HandlerInterceptor {
|
|||||||
objectMapper
|
objectMapper
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeSessionInvalid(HttpServletResponse response, String message) throws IOException {
|
||||||
|
HttpResponseUtil.writeJson(
|
||||||
|
response,
|
||||||
|
HttpServletResponse.SC_UNAUTHORIZED,
|
||||||
|
ApiResponse.fail(ErrorCode.SESSION_INVALID.getCode(), message),
|
||||||
|
objectMapper
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,11 +69,11 @@ public class InternalApiReplayInterceptor implements HandlerInterceptor {
|
|||||||
try {
|
try {
|
||||||
ReplayCheckResult result = replayProtectionService.check(replayRequest);
|
ReplayCheckResult result = replayProtectionService.check(replayRequest);
|
||||||
if (result.isReplayed()) {
|
if (result.isReplayed()) {
|
||||||
writeJson(response, HttpServletResponse.SC_CONFLICT, ErrorCode.UNAUTHORIZED.getCode(), "replayed nonce");
|
writeJson(response, HttpServletResponse.SC_CONFLICT, ErrorCode.CONFLICT.getCode(), "replayed nonce");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (ReplayProtectionException ex) {
|
} catch (ReplayProtectionException ex) {
|
||||||
writeJson(response, HttpServletResponse.SC_SERVICE_UNAVAILABLE, ErrorCode.INTERNAL_ERROR.getCode(),
|
writeJson(response, HttpServletResponse.SC_SERVICE_UNAVAILABLE, ErrorCode.SERVICE_UNAVAILABLE.getCode(),
|
||||||
"replay protection unavailable");
|
"replay protection unavailable");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,11 +89,12 @@ public class OpenApiSignAuthInterceptor implements HandlerInterceptor {
|
|||||||
// 先完成签名校验,再占用 nonce,避免伪造请求提前消耗合法 nonce。
|
// 先完成签名校验,再占用 nonce,避免伪造请求提前消耗合法 nonce。
|
||||||
ReplayCheckResult result = replayProtectionService.check(buildReplayRequest(request, appId, nonce, requestEpoch));
|
ReplayCheckResult result = replayProtectionService.check(buildReplayRequest(request, appId, nonce, requestEpoch));
|
||||||
if (result.isReplayed()) {
|
if (result.isReplayed()) {
|
||||||
writeUnauthorized(response, "replayed nonce");
|
writeJson(response, HttpServletResponse.SC_CONFLICT, ErrorCode.CONFLICT.getCode(), "replayed nonce");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (ReplayProtectionException ex) {
|
} catch (ReplayProtectionException ex) {
|
||||||
writeUnauthorized(response, "replay protection unavailable");
|
writeJson(response, HttpServletResponse.SC_SERVICE_UNAVAILABLE,
|
||||||
|
ErrorCode.SERVICE_UNAVAILABLE.getCode(), "replay protection unavailable");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,10 +137,14 @@ public class OpenApiSignAuthInterceptor implements HandlerInterceptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void writeUnauthorized(HttpServletResponse response, String message) throws IOException {
|
private void writeUnauthorized(HttpServletResponse response, String message) throws IOException {
|
||||||
|
writeJson(response, HttpServletResponse.SC_UNAUTHORIZED, ErrorCode.UNAUTHORIZED.getCode(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeJson(HttpServletResponse response, int status, int code, String message) throws IOException {
|
||||||
HttpResponseUtil.writeJson(
|
HttpResponseUtil.writeJson(
|
||||||
response,
|
response,
|
||||||
HttpServletResponse.SC_UNAUTHORIZED,
|
status,
|
||||||
ApiResponse.fail(ErrorCode.UNAUTHORIZED.getCode(), message),
|
ApiResponse.fail(code, message),
|
||||||
objectMapper
|
objectMapper
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import com.cisd.tms.common.api.ApiResponse;
|
|||||||
import com.cisd.tms.common.enums.ErrorCode;
|
import com.cisd.tms.common.enums.ErrorCode;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
||||||
import org.springframework.web.multipart.MultipartException;
|
import org.springframework.web.multipart.MultipartException;
|
||||||
@@ -15,15 +17,17 @@ class GlobalExceptionHandlerTest {
|
|||||||
GlobalExceptionHandler handler = new GlobalExceptionHandler();
|
GlobalExceptionHandler handler = new GlobalExceptionHandler();
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/api/v1/upgrade-packages");
|
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/api/v1/upgrade-packages");
|
||||||
|
|
||||||
ApiResponse<Void> response = handler.handleMaxUploadSizeExceeded(
|
ResponseEntity<ApiResponse<Void>> response = handler.handleMaxUploadSizeExceeded(
|
||||||
new MaxUploadSizeExceededException(104857600),
|
new MaxUploadSizeExceededException(104857600),
|
||||||
request
|
request
|
||||||
);
|
);
|
||||||
|
|
||||||
Assertions.assertFalse(response.isSuccess());
|
Assertions.assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
|
||||||
Assertions.assertEquals(ErrorCode.VALIDATE_FAILED.getCode(), response.getCode());
|
Assertions.assertNotNull(response.getBody());
|
||||||
Assertions.assertEquals("upload file size exceeds limit", response.getMsg());
|
Assertions.assertFalse(response.getBody().isSuccess());
|
||||||
Assertions.assertEquals("/api/v1/upgrade-packages", response.getPath());
|
Assertions.assertEquals(ErrorCode.VALIDATE_FAILED.getCode(), response.getBody().getCode());
|
||||||
|
Assertions.assertEquals("upload file size exceeds limit", response.getBody().getMsg());
|
||||||
|
Assertions.assertEquals("/api/v1/upgrade-packages", response.getBody().getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -31,14 +35,16 @@ class GlobalExceptionHandlerTest {
|
|||||||
GlobalExceptionHandler handler = new GlobalExceptionHandler();
|
GlobalExceptionHandler handler = new GlobalExceptionHandler();
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/api/v1/files/upload");
|
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/api/v1/files/upload");
|
||||||
|
|
||||||
ApiResponse<Void> response = handler.handleMultipartException(
|
ResponseEntity<ApiResponse<Void>> response = handler.handleMultipartException(
|
||||||
new MultipartException("Failed to parse multipart servlet request"),
|
new MultipartException("Failed to parse multipart servlet request"),
|
||||||
request
|
request
|
||||||
);
|
);
|
||||||
|
|
||||||
Assertions.assertFalse(response.isSuccess());
|
Assertions.assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
|
||||||
Assertions.assertEquals(ErrorCode.VALIDATE_FAILED.getCode(), response.getCode());
|
Assertions.assertNotNull(response.getBody());
|
||||||
Assertions.assertEquals("failed to parse multipart request", response.getMsg());
|
Assertions.assertFalse(response.getBody().isSuccess());
|
||||||
Assertions.assertEquals("/api/v1/files/upload", response.getPath());
|
Assertions.assertEquals(ErrorCode.VALIDATE_FAILED.getCode(), response.getBody().getCode());
|
||||||
|
Assertions.assertEquals("failed to parse multipart request", response.getBody().getMsg());
|
||||||
|
Assertions.assertEquals("/api/v1/files/upload", response.getBody().getPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+79
-86
@@ -1,86 +1,79 @@
|
|||||||
//package com.cisd.tms.modules.auth.security;
|
package com.cisd.tms.modules.auth.security;
|
||||||
//
|
|
||||||
//import com.cisd.tms.modules.log.service.OperationAuditService;
|
import com.cisd.tms.common.enums.ErrorCode;
|
||||||
//import com.cisd.tms.security.internal.InternalApiAuthInterceptor;
|
import com.cisd.tms.modules.log.service.OperationAuditService;
|
||||||
//import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.cisd.tms.security.internal.InternalApiAuthInterceptor;
|
||||||
//import org.junit.jupiter.api.Assertions;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
//import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Assertions;
|
||||||
//import org.springframework.mock.web.MockHttpServletRequest;
|
import org.junit.jupiter.api.Test;
|
||||||
//import org.springframework.mock.web.MockHttpServletResponse;
|
import org.mockito.Mockito;
|
||||||
//import org.springframework.web.method.HandlerMethod;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
//
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
//import java.lang.reflect.Method;
|
import org.springframework.web.method.HandlerMethod;
|
||||||
//
|
|
||||||
//class InternalAuthorizationInterceptorTest {
|
class InternalAuthorizationInterceptorTest {
|
||||||
//
|
|
||||||
// @Test
|
@Test
|
||||||
// void shouldAllowRequestWhenHandlerHasNoAuthorizationAnnotations() throws Exception {
|
void shouldRejectWhenRoleDoesNotMatchRequiredRole() throws Exception {
|
||||||
// InternalAuthorizationInterceptor interceptor = new InternalAuthorizationInterceptor(new ObjectMapper());
|
OperationAuditService operationAuditService = Mockito.mock(OperationAuditService.class);
|
||||||
// MockHttpServletRequest request = new MockHttpServletRequest("GET", "/api/v1/public");
|
InternalAuthorizationInterceptor interceptor = new InternalAuthorizationInterceptor(new ObjectMapper(), operationAuditService);
|
||||||
// MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/api/v1/auth/roles/AUDIT_ADMIN/enable");
|
||||||
//
|
request.setAttribute(InternalApiAuthInterceptor.ATTR_ROLE_CODE, "AUDIT_ADMIN");
|
||||||
// boolean allowed = interceptor.preHandle(request, response, handler("openEndpoint"));
|
request.setAttribute(InternalApiAuthInterceptor.ATTR_AUTH_LEVEL, "FULL");
|
||||||
//
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
// Assertions.assertTrue(allowed);
|
|
||||||
// }
|
boolean allowed = interceptor.preHandle(request, response, handler("keyAdminFullEndpoint"));
|
||||||
//
|
|
||||||
// @Test
|
Assertions.assertFalse(allowed);
|
||||||
// void shouldRejectWhenRoleDoesNotMatchRequiredRole() throws Exception {
|
Assertions.assertEquals(403, response.getStatus());
|
||||||
// InternalAuthorizationInterceptor interceptor = new InternalAuthorizationInterceptor(new ObjectMapper());
|
Assertions.assertTrue(response.getContentAsString().contains("\"code\":" + ErrorCode.FORBIDDEN.getCode()));
|
||||||
// MockHttpServletRequest request = new MockHttpServletRequest("POST", "/api/v1/auth/roles/AUDIT_ADMIN/enable");
|
Assertions.assertTrue(response.getContentAsString().contains("role not allowed"));
|
||||||
// request.setAttribute(InternalApiAuthInterceptor.ATTR_ROLE_CODE, "AUDIT_ADMIN");
|
Mockito.verify(operationAuditService).recordDeniedLog(Mockito.eq(request), Mockito.any(HandlerMethod.class), Mockito.eq("role not allowed"));
|
||||||
// request.setAttribute(InternalApiAuthInterceptor.ATTR_AUTH_LEVEL, "FULL");
|
}
|
||||||
// MockHttpServletResponse response = new MockHttpServletResponse();
|
|
||||||
//
|
@Test
|
||||||
// boolean allowed = interceptor.preHandle(request, response, handler("keyAdminFullEndpoint"));
|
void shouldRejectWhenAuthLevelDoesNotMatchRequirement() throws Exception {
|
||||||
//
|
OperationAuditService operationAuditService = Mockito.mock(OperationAuditService.class);
|
||||||
// Assertions.assertFalse(allowed);
|
InternalAuthorizationInterceptor interceptor = new InternalAuthorizationInterceptor(new ObjectMapper(), operationAuditService);
|
||||||
// Assertions.assertEquals(403, response.getStatus());
|
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/api/v1/auth/roles/AUDIT_ADMIN/reset-password");
|
||||||
// Assertions.assertTrue(response.getContentAsString().contains("role not allowed"));
|
request.setAttribute(InternalApiAuthInterceptor.ATTR_ROLE_CODE, "KEY_ADMIN");
|
||||||
// }
|
request.setAttribute(InternalApiAuthInterceptor.ATTR_AUTH_LEVEL, "LIMITED");
|
||||||
//
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
// @Test
|
|
||||||
// void shouldRejectWhenAuthLevelDoesNotMatchRequirement() throws Exception {
|
boolean allowed = interceptor.preHandle(request, response, handler("keyAdminFullEndpoint"));
|
||||||
// InternalAuthorizationInterceptor interceptor = new InternalAuthorizationInterceptor(new ObjectMapper());
|
|
||||||
// MockHttpServletRequest request = new MockHttpServletRequest("POST", "/api/v1/auth/roles/AUDIT_ADMIN/reset-password");
|
Assertions.assertFalse(allowed);
|
||||||
// request.setAttribute(InternalApiAuthInterceptor.ATTR_ROLE_CODE, "KEY_ADMIN");
|
Assertions.assertEquals(403, response.getStatus());
|
||||||
// request.setAttribute(InternalApiAuthInterceptor.ATTR_AUTH_LEVEL, "LIMITED");
|
Assertions.assertTrue(response.getContentAsString().contains("\"code\":" + ErrorCode.FORBIDDEN.getCode()));
|
||||||
// MockHttpServletResponse response = new MockHttpServletResponse();
|
Assertions.assertTrue(response.getContentAsString().contains("auth level not allowed"));
|
||||||
//
|
Mockito.verify(operationAuditService).recordDeniedLog(Mockito.eq(request), Mockito.any(HandlerMethod.class), Mockito.eq("auth level not allowed"));
|
||||||
// boolean allowed = interceptor.preHandle(request, response, handler("keyAdminFullEndpoint"));
|
}
|
||||||
//
|
|
||||||
// Assertions.assertFalse(allowed);
|
@Test
|
||||||
// Assertions.assertEquals(403, response.getStatus());
|
void shouldAllowWhenRoleAndAuthLevelMatch() throws Exception {
|
||||||
// Assertions.assertTrue(response.getContentAsString().contains("auth level not allowed"));
|
OperationAuditService operationAuditService = Mockito.mock(OperationAuditService.class);
|
||||||
// }
|
InternalAuthorizationInterceptor interceptor = new InternalAuthorizationInterceptor(new ObjectMapper(), operationAuditService);
|
||||||
//
|
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/api/v1/auth/roles/AUDIT_ADMIN/reset-password");
|
||||||
// @Test
|
request.setAttribute(InternalApiAuthInterceptor.ATTR_ROLE_CODE, "KEY_ADMIN");
|
||||||
// void shouldAllowWhenRoleAndAuthLevelMatch() throws Exception {
|
request.setAttribute(InternalApiAuthInterceptor.ATTR_AUTH_LEVEL, "FULL");
|
||||||
// InternalAuthorizationInterceptor interceptor = new InternalAuthorizationInterceptor(new ObjectMapper());
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
// MockHttpServletRequest request = new MockHttpServletRequest("POST", "/api/v1/auth/roles/AUDIT_ADMIN/reset-password");
|
|
||||||
// request.setAttribute(InternalApiAuthInterceptor.ATTR_ROLE_CODE, "KEY_ADMIN");
|
boolean allowed = interceptor.preHandle(request, response, handler("keyAdminFullEndpoint"));
|
||||||
// request.setAttribute(InternalApiAuthInterceptor.ATTR_AUTH_LEVEL, "FULL");
|
|
||||||
// MockHttpServletResponse response = new MockHttpServletResponse();
|
Assertions.assertTrue(allowed);
|
||||||
//
|
Mockito.verifyNoInteractions(operationAuditService);
|
||||||
// boolean allowed = interceptor.preHandle(request, response, handler("keyAdminFullEndpoint"));
|
}
|
||||||
//
|
|
||||||
// Assertions.assertTrue(allowed);
|
private static HandlerMethod handler(String methodName) throws NoSuchMethodException {
|
||||||
// }
|
DemoController controller = new DemoController();
|
||||||
//
|
return new HandlerMethod(controller, DemoController.class.getDeclaredMethod(methodName));
|
||||||
// private HandlerMethod handler(String methodName) throws NoSuchMethodException {
|
}
|
||||||
// DemoController controller = new DemoController();
|
|
||||||
// Method method = DemoController.class.getDeclaredMethod(methodName);
|
@SuppressWarnings("unused")
|
||||||
// return new HandlerMethod(controller, method);
|
private static class DemoController {
|
||||||
// }
|
|
||||||
//
|
@RequireInternalAuth(role = com.cisd.tms.modules.auth.enums.RoleCode.KEY_ADMIN, authLevel = com.cisd.tms.modules.auth.enums.AuthLevel.FULL)
|
||||||
// @SuppressWarnings("unused")
|
public void keyAdminFullEndpoint() {
|
||||||
// private static class DemoController {
|
}
|
||||||
//
|
}
|
||||||
// public void openEndpoint() {
|
}
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @RequireInternalAuth(role = com.cisd.tms.modules.auth.enums.RoleCode.KEY_ADMIN, authLevel = com.cisd.tms.modules.auth.enums.AuthLevel.FULL)
|
|
||||||
// public void keyAdminFullEndpoint() {
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.cisd.tms.modules.auth.service;
|
package com.cisd.tms.modules.auth.service;
|
||||||
|
|
||||||
|
import com.cisd.tms.common.enums.ErrorCode;
|
||||||
import com.cisd.tms.common.exception.BizException;
|
import com.cisd.tms.common.exception.BizException;
|
||||||
import com.cisd.tms.modules.auth.dto.CaptchaResponse;
|
import com.cisd.tms.modules.auth.dto.CaptchaResponse;
|
||||||
import com.cisd.tms.modules.auth.dto.CurrentUserResponse;
|
import com.cisd.tms.modules.auth.dto.CurrentUserResponse;
|
||||||
@@ -193,6 +194,31 @@ class AuthServiceTest {
|
|||||||
Assertions.assertEquals(LocalDateTime.of(2026, 3, 23, 2, 0), changed.getLastActiveAt());
|
Assertions.assertEquals(LocalDateTime.of(2026, 3, 23, 2, 0), changed.getLastActiveAt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldThrowSessionInvalidWhenChangingPasswordWithExpiredSession() {
|
||||||
|
InMemoryRoleAccountRepository roleAccounts = new InMemoryRoleAccountRepository();
|
||||||
|
InMemoryAuthSessionRepository sessions = new InMemoryAuthSessionRepository();
|
||||||
|
roleAccounts.save(activeRole(RoleCode.KEY_ADMIN, "12345678", "ROLE-SALT-K", 0, null, true));
|
||||||
|
AuthSessionEntity expiredSession = session("token-expired-001", RoleCode.KEY_ADMIN.getCode(), AuthLevel.FULL.name());
|
||||||
|
expiredSession.setExpiresAt(LocalDateTime.of(2026, 3, 23, 1, 59));
|
||||||
|
sessions.save(expiredSession);
|
||||||
|
|
||||||
|
AuthService service = newAuthService(
|
||||||
|
roleAccounts,
|
||||||
|
new InMemoryAuthUserAccountRepository(),
|
||||||
|
sessions,
|
||||||
|
new InMemoryRoleUkeyBindingRepository(),
|
||||||
|
FIXED_CLOCK,
|
||||||
|
() -> "unused"
|
||||||
|
);
|
||||||
|
|
||||||
|
BizException exception = Assertions.assertThrows(BizException.class,
|
||||||
|
() -> service.changePassword("token-expired-001", "12345678", "87654321"));
|
||||||
|
|
||||||
|
Assertions.assertEquals(ErrorCode.SESSION_INVALID.getCode(), exception.getCode());
|
||||||
|
Assertions.assertEquals("session expired", exception.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldIssueCaptchaAndAcceptPasswordLoginWithValidCaptcha() {
|
void shouldIssueCaptchaAndAcceptPasswordLoginWithValidCaptcha() {
|
||||||
InMemoryRoleAccountRepository roleAccounts = new InMemoryRoleAccountRepository();
|
InMemoryRoleAccountRepository roleAccounts = new InMemoryRoleAccountRepository();
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.cisd.tms.modules.log.controller;
|
package com.cisd.tms.modules.log.controller;
|
||||||
|
|
||||||
|
import com.cisd.tms.common.enums.ErrorCode;
|
||||||
|
import com.cisd.tms.common.exception.GlobalExceptionHandler;
|
||||||
import com.cisd.tms.modules.log.dto.AuditLogReviewRequest;
|
import com.cisd.tms.modules.log.dto.AuditLogReviewRequest;
|
||||||
import com.cisd.tms.modules.log.enums.AuditResult;
|
import com.cisd.tms.modules.log.enums.AuditResult;
|
||||||
import com.cisd.tms.modules.log.service.OperationAuditService;
|
import com.cisd.tms.modules.log.service.OperationAuditService;
|
||||||
@@ -34,6 +36,7 @@ class OperationAuditControllerTest {
|
|||||||
|
|
||||||
mockMvc = MockMvcBuilders
|
mockMvc = MockMvcBuilders
|
||||||
.standaloneSetup(new OperationAuditController(auditService))
|
.standaloneSetup(new OperationAuditController(auditService))
|
||||||
|
.setControllerAdvice(new GlobalExceptionHandler())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,8 +67,8 @@ class OperationAuditControllerTest {
|
|||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.content(objectMapper.writeValueAsString(req))
|
.content(objectMapper.writeValueAsString(req))
|
||||||
.requestAttr(InternalApiAuthInterceptor.ATTR_ROLE_CODE, "SYS_ADMIN"))
|
.requestAttr(InternalApiAuthInterceptor.ATTR_ROLE_CODE, "SYS_ADMIN"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isForbidden())
|
||||||
.andExpect(jsonPath("$.code").value(403))
|
.andExpect(jsonPath("$.code").value(ErrorCode.FORBIDDEN.getCode()))
|
||||||
.andExpect(jsonPath("$.msg").value("权限不足:仅审计管理员可执行此操作"));
|
.andExpect(jsonPath("$.msg").value("权限不足:仅审计管理员可执行此操作"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@ import org.springframework.test.web.servlet.MockMvc;
|
|||||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
|
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
class LmkControllerTest {
|
class LmkControllerTest {
|
||||||
@@ -48,7 +49,8 @@ class LmkControllerTest {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
"""))
|
"""))
|
||||||
.andExpect(status().isOk());
|
.andExpect(status().isBadRequest())
|
||||||
|
.andExpect(jsonPath("$.code").value(4001));
|
||||||
|
|
||||||
Mockito.verifyNoInteractions(lmkService);
|
Mockito.verifyNoInteractions(lmkService);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.cisd.tms.modules.security.replay.enums.ReplayCheckStatus;
|
|||||||
import com.cisd.tms.modules.security.replay.enums.ReplayScope;
|
import com.cisd.tms.modules.security.replay.enums.ReplayScope;
|
||||||
import com.cisd.tms.modules.security.replay.exception.ReplayProtectionException;
|
import com.cisd.tms.modules.security.replay.exception.ReplayProtectionException;
|
||||||
import com.cisd.tms.modules.security.replay.service.ReplayProtectionService;
|
import com.cisd.tms.modules.security.replay.service.ReplayProtectionService;
|
||||||
|
import com.cisd.tms.common.enums.ErrorCode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
@@ -122,6 +123,7 @@ class InternalApiReplayInterceptorTest {
|
|||||||
Assertions.assertFalse(allowed);
|
Assertions.assertFalse(allowed);
|
||||||
Assertions.assertEquals(409, response.getStatus());
|
Assertions.assertEquals(409, response.getStatus());
|
||||||
Assertions.assertTrue(response.getContentAsString().contains("replayed nonce"));
|
Assertions.assertTrue(response.getContentAsString().contains("replayed nonce"));
|
||||||
|
Assertions.assertTrue(response.getContentAsString().contains("\"code\":" + ErrorCode.CONFLICT.getCode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -146,6 +148,7 @@ class InternalApiReplayInterceptorTest {
|
|||||||
Assertions.assertFalse(allowed);
|
Assertions.assertFalse(allowed);
|
||||||
Assertions.assertEquals(503, response.getStatus());
|
Assertions.assertEquals(503, response.getStatus());
|
||||||
Assertions.assertTrue(response.getContentAsString().contains("replay protection unavailable"));
|
Assertions.assertTrue(response.getContentAsString().contains("replay protection unavailable"));
|
||||||
|
Assertions.assertTrue(response.getContentAsString().contains("\"code\":" + ErrorCode.SERVICE_UNAVAILABLE.getCode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HandlerMethod protectedHandler(String methodName) throws NoSuchMethodException {
|
private static HandlerMethod protectedHandler(String methodName) throws NoSuchMethodException {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.cisd.tms.security.openapi;
|
package com.cisd.tms.security.openapi;
|
||||||
|
|
||||||
|
import com.cisd.tms.common.enums.ErrorCode;
|
||||||
import com.cisd.tms.common.config.properties.TmsSecurityProperties;
|
import com.cisd.tms.common.config.properties.TmsSecurityProperties;
|
||||||
import com.cisd.tms.common.util.HmacUtil;
|
import com.cisd.tms.common.util.HmacUtil;
|
||||||
import com.cisd.tms.modules.security.replay.dto.ReplayCheckRequest;
|
import com.cisd.tms.modules.security.replay.dto.ReplayCheckRequest;
|
||||||
@@ -115,8 +116,9 @@ class OpenApiSignAuthInterceptorTest {
|
|||||||
boolean allowed = interceptor.preHandle(request, response, new Object());
|
boolean allowed = interceptor.preHandle(request, response, new Object());
|
||||||
|
|
||||||
Assertions.assertFalse(allowed);
|
Assertions.assertFalse(allowed);
|
||||||
Assertions.assertEquals(401, response.getStatus());
|
Assertions.assertEquals(409, response.getStatus());
|
||||||
Assertions.assertTrue(response.getContentAsString().contains("replayed nonce"));
|
Assertions.assertTrue(response.getContentAsString().contains("replayed nonce"));
|
||||||
|
Assertions.assertTrue(response.getContentAsString().contains("\"code\":" + ErrorCode.CONFLICT.getCode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -144,8 +146,9 @@ class OpenApiSignAuthInterceptorTest {
|
|||||||
boolean allowed = interceptor.preHandle(request, response, new Object());
|
boolean allowed = interceptor.preHandle(request, response, new Object());
|
||||||
|
|
||||||
Assertions.assertFalse(allowed);
|
Assertions.assertFalse(allowed);
|
||||||
Assertions.assertEquals(401, response.getStatus());
|
Assertions.assertEquals(503, response.getStatus());
|
||||||
Assertions.assertTrue(response.getContentAsString().contains("replay protection unavailable"));
|
Assertions.assertTrue(response.getContentAsString().contains("replay protection unavailable"));
|
||||||
|
Assertions.assertTrue(response.getContentAsString().contains("\"code\":" + ErrorCode.SERVICE_UNAVAILABLE.getCode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TmsSecurityProperties securityProperties(String appId, String secret, long skewSeconds) {
|
private static TmsSecurityProperties securityProperties(String appId, String secret, long skewSeconds) {
|
||||||
|
|||||||
Reference in New Issue
Block a user