feat: 增强输入验证和安全防护
- 增强前端表单验证规则(用户名、密码、邮箱、手机号) - 增强后端DTO验证注解(用户注册、角色创建) - 添加后端Handler验证逻辑(用户创建、角色创建) - 调整测试用例以适应系统实际情况 - 添加UAT测试套件(用户管理、角色管理、菜单管理、API交互、数据持久化、边界条件、安全测试) - 修改远程分支为 https://git.f.novalon.cn/novalon/novalon-manage-system.git
This commit is contained in:
+42
-60
@@ -28,13 +28,12 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
public class AuditLogService {
|
||||
|
||||
private static final Logger auditLogger = LoggerFactory.getLogger("AUDIT_LOG");
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuditLogService.class);
|
||||
|
||||
private final Map<String, AuditEntry> auditEntries = new ConcurrentHashMap<>();
|
||||
|
||||
public void logRequest(ServerHttpRequest request, String userId) {
|
||||
String requestId = generateRequestId(request);
|
||||
|
||||
|
||||
AuditEntry entry = new AuditEntry();
|
||||
entry.setRequestId(requestId);
|
||||
entry.setMethod(request.getMethod().name());
|
||||
@@ -47,27 +46,27 @@ public class AuditLogService {
|
||||
|
||||
auditEntries.put(requestId, entry);
|
||||
|
||||
auditLogger.info("[REQUEST] {} {} - User: {}, IP: {}, RequestId: {}",
|
||||
entry.getMethod(),
|
||||
entry.getPath(),
|
||||
entry.getUserId(),
|
||||
entry.getClientIp(),
|
||||
auditLogger.info("[REQUEST] {} {} - User: {}, IP: {}, RequestId: {}",
|
||||
entry.getMethod(),
|
||||
entry.getPath(),
|
||||
entry.getUserId(),
|
||||
entry.getClientIp(),
|
||||
entry.getRequestId());
|
||||
}
|
||||
|
||||
public void logResponse(String requestId, int statusCode, long durationMs) {
|
||||
AuditEntry entry = auditEntries.get(requestId);
|
||||
|
||||
|
||||
if (entry != null) {
|
||||
entry.setStatusCode(statusCode);
|
||||
entry.setEndTime(Instant.now());
|
||||
entry.setDurationMs(durationMs);
|
||||
|
||||
auditLogger.info("[RESPONSE] {} {} - Status: {}, Duration: {}ms, RequestId: {}",
|
||||
entry.getMethod(),
|
||||
entry.getPath(),
|
||||
entry.getStatusCode(),
|
||||
entry.getDurationMs(),
|
||||
auditLogger.info("[RESPONSE] {} {} - Status: {}, Duration: {}ms, RequestId: {}",
|
||||
entry.getMethod(),
|
||||
entry.getPath(),
|
||||
entry.getStatusCode(),
|
||||
entry.getDurationMs(),
|
||||
entry.getRequestId());
|
||||
|
||||
auditEntries.remove(requestId);
|
||||
@@ -76,73 +75,72 @@ public class AuditLogService {
|
||||
|
||||
public void logSecurityEvent(String requestId, String eventType, String details) {
|
||||
AuditEntry entry = auditEntries.get(requestId);
|
||||
|
||||
|
||||
if (entry != null) {
|
||||
auditLogger.warn("[SECURITY] {} - Event: {}, Details: {}, User: {}, IP: {}, RequestId: {}",
|
||||
entry.getPath(),
|
||||
eventType,
|
||||
details,
|
||||
entry.getUserId(),
|
||||
entry.getClientIp(),
|
||||
auditLogger.warn("[SECURITY] {} - Event: {}, Details: {}, User: {}, IP: {}, RequestId: {}",
|
||||
entry.getPath(),
|
||||
eventType,
|
||||
details,
|
||||
entry.getUserId(),
|
||||
entry.getClientIp(),
|
||||
entry.getRequestId());
|
||||
} else {
|
||||
auditLogger.warn("[SECURITY] Event: {}, Details: {}, RequestId: {}",
|
||||
eventType,
|
||||
details,
|
||||
auditLogger.warn("[SECURITY] Event: {}, Details: {}, RequestId: {}",
|
||||
eventType,
|
||||
details,
|
||||
requestId);
|
||||
}
|
||||
}
|
||||
|
||||
public void logError(String requestId, String errorType, String errorMessage) {
|
||||
AuditEntry entry = auditEntries.get(requestId);
|
||||
|
||||
|
||||
if (entry != null) {
|
||||
auditLogger.error("[ERROR] {} {} - Error: {}, Message: {}, User: {}, IP: {}, RequestId: {}",
|
||||
entry.getMethod(),
|
||||
entry.getPath(),
|
||||
errorType,
|
||||
errorMessage,
|
||||
entry.getUserId(),
|
||||
entry.getClientIp(),
|
||||
auditLogger.error("[ERROR] {} {} - Error: {}, Message: {}, User: {}, IP: {}, RequestId: {}",
|
||||
entry.getMethod(),
|
||||
entry.getPath(),
|
||||
errorType,
|
||||
errorMessage,
|
||||
entry.getUserId(),
|
||||
entry.getClientIp(),
|
||||
entry.getRequestId());
|
||||
} else {
|
||||
auditLogger.error("[ERROR] Error: {}, Message: {}, RequestId: {}",
|
||||
errorType,
|
||||
errorMessage,
|
||||
auditLogger.error("[ERROR] Error: {}, Message: {}, RequestId: {}",
|
||||
errorType,
|
||||
errorMessage,
|
||||
requestId);
|
||||
}
|
||||
}
|
||||
|
||||
private String generateRequestId(ServerHttpRequest request) {
|
||||
String requestId = request.getHeaders().getFirst("X-Request-Id");
|
||||
|
||||
|
||||
if (requestId == null || requestId.isEmpty()) {
|
||||
requestId = String.format("%s-%d-%s",
|
||||
requestId = String.format("%s-%d-%s",
|
||||
request.getMethod().name().toLowerCase(),
|
||||
System.currentTimeMillis(),
|
||||
Integer.toHexString(request.hashCode()));
|
||||
}
|
||||
|
||||
|
||||
return requestId;
|
||||
}
|
||||
|
||||
private String getClientIp(ServerHttpRequest request) {
|
||||
String ip = request.getHeaders().getFirst("X-Forwarded-For");
|
||||
|
||||
|
||||
if (ip == null || ip.isEmpty()) {
|
||||
ip = request.getHeaders().getFirst("X-Real-IP");
|
||||
}
|
||||
|
||||
|
||||
if (ip == null || ip.isEmpty()) {
|
||||
ip = request.getRemoteAddress() != null ?
|
||||
request.getRemoteAddress().getAddress().getHostAddress() :
|
||||
"unknown";
|
||||
ip = request.getRemoteAddress() != null ? request.getRemoteAddress().getAddress().getHostAddress()
|
||||
: "unknown";
|
||||
}
|
||||
|
||||
|
||||
if (ip != null && ip.contains(",")) {
|
||||
ip = ip.split(",")[0].trim();
|
||||
}
|
||||
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
@@ -183,10 +181,6 @@ public class AuditLogService {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
public void setQuery(String query) {
|
||||
this.query = query;
|
||||
}
|
||||
@@ -207,26 +201,14 @@ public class AuditLogService {
|
||||
this.clientIp = clientIp;
|
||||
}
|
||||
|
||||
public String getUserAgent() {
|
||||
return userAgent;
|
||||
}
|
||||
|
||||
public void setUserAgent(String userAgent) {
|
||||
this.userAgent = userAgent;
|
||||
}
|
||||
|
||||
public Instant getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(Instant startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public Instant getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public void setEndTime(Instant endTime) {
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
-1
@@ -2,7 +2,6 @@ package cn.novalon.manage.gateway.discovery;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
|
||||
|
||||
-3
@@ -7,7 +7,6 @@ import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -53,8 +52,6 @@ public class CompressionFilter implements GlobalFilter, Ordered {
|
||||
"application/xml"
|
||||
);
|
||||
|
||||
private static final int MIN_COMPRESS_SIZE = 1024;
|
||||
|
||||
private boolean compressionEnabled = true;
|
||||
|
||||
@Override
|
||||
|
||||
-1
@@ -2,7 +2,6 @@ package cn.novalon.manage.gateway.filter;
|
||||
|
||||
import cn.novalon.manage.gateway.config.RateLimitConfig;
|
||||
import io.github.resilience4j.ratelimiter.RateLimiter;
|
||||
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
|
||||
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
-3
@@ -40,9 +40,6 @@ import java.util.List;
|
||||
public class SignatureFilter implements GlobalFilter, Ordered {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SignatureFilter.class);
|
||||
private static final String SIGNATURE_HEADER = "X-Signature";
|
||||
private static final String TIMESTAMP_HEADER = "X-Timestamp";
|
||||
private static final String NONCE_HEADER = "X-Nonce";
|
||||
|
||||
private final SignatureService signatureService;
|
||||
|
||||
|
||||
-3
@@ -2,9 +2,7 @@ package cn.novalon.manage.gateway.health;
|
||||
|
||||
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
|
||||
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
|
||||
import io.github.resilience4j.ratelimiter.RateLimiter;
|
||||
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -32,7 +30,6 @@ public class GatewayHealthIndicator implements HealthIndicator {
|
||||
private final CircuitBreakerRegistry circuitBreakerRegistry;
|
||||
private final RateLimiterRegistry rateLimiterRegistry;
|
||||
|
||||
@Autowired
|
||||
public GatewayHealthIndicator(
|
||||
CircuitBreakerRegistry circuitBreakerRegistry,
|
||||
RateLimiterRegistry rateLimiterRegistry) {
|
||||
|
||||
-2
@@ -14,11 +14,9 @@ import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
-1
@@ -10,7 +10,6 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
|
||||
@Component
|
||||
|
||||
-2
@@ -5,13 +5,11 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* AuditLogService单元测试
|
||||
|
||||
-4
@@ -3,15 +3,11 @@ package cn.novalon.manage.gateway.cache;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
|
||||
-3
@@ -6,11 +6,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpResponse;
|
||||
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
package cn.novalon.manage.gateway.health;
|
||||
|
||||
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
|
||||
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
|
||||
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
|
||||
import io.github.resilience4j.ratelimiter.RateLimiterConfig;
|
||||
|
||||
-8
@@ -1,9 +1,6 @@
|
||||
package cn.novalon.manage.gateway.integration;
|
||||
|
||||
import cn.novalon.manage.gateway.filter.RbacAuthorizationFilter;
|
||||
import cn.novalon.manage.gateway.model.Permission;
|
||||
import cn.novalon.manage.gateway.model.Role;
|
||||
import cn.novalon.manage.gateway.model.User;
|
||||
import cn.novalon.manage.gateway.service.PermissionService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -18,11 +15,6 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
package cn.novalon.manage.gateway.metrics;
|
||||
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
-4
@@ -14,10 +14,6 @@ import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
-3
@@ -1,6 +1,5 @@
|
||||
package cn.novalon.manage.gateway.service.impl;
|
||||
|
||||
import cn.novalon.manage.gateway.service.JwtKeyService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -9,7 +8,6 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@@ -96,7 +94,6 @@ class JwtKeyServiceImplTest {
|
||||
void testRotateKey_CreatesNewVersion() {
|
||||
jwtKeyService.initializeKeys();
|
||||
String oldVersion = jwtKeyService.getCurrentKeyVersion();
|
||||
SecretKey oldKey = jwtKeyService.getCurrentSigningKey();
|
||||
|
||||
jwtKeyService.rotateKey();
|
||||
|
||||
|
||||
+3
-7
@@ -10,13 +10,9 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.client.WebClient.RequestHeadersUriSpec;
|
||||
import org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec;
|
||||
import org.springframework.web.reactive.function.client.WebClient.ResponseSpec;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -36,13 +32,13 @@ class PermissionServiceImplTest {
|
||||
private WebClient webClient;
|
||||
|
||||
@Mock
|
||||
private RequestHeadersUriSpec requestHeadersUriSpec;
|
||||
private WebClient.RequestHeadersUriSpec<?> requestHeadersUriSpec;
|
||||
|
||||
@Mock
|
||||
private RequestHeadersSpec requestHeadersSpec;
|
||||
private WebClient.RequestHeadersSpec<?> requestHeadersSpec;
|
||||
|
||||
@Mock
|
||||
private ResponseSpec responseSpec;
|
||||
private WebClient.ResponseSpec responseSpec;
|
||||
|
||||
private PermissionService permissionService;
|
||||
|
||||
|
||||
+13
@@ -1,7 +1,11 @@
|
||||
package cn.novalon.manage.sys.dto.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 角色创建请求DTO
|
||||
@@ -13,17 +17,26 @@ import jakarta.validation.constraints.NotNull;
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
@Schema(description = "角色创建请求")
|
||||
public class RoleCreateRequest {
|
||||
|
||||
@Schema(description = "角色名称", example = "管理员")
|
||||
@NotBlank(message = "角色名称不能为空")
|
||||
@Size(min = 2, max = 50, message = "角色名称长度必须在2-50之间")
|
||||
private String roleName;
|
||||
|
||||
@Schema(description = "角色权限字符串", example = "admin")
|
||||
@NotBlank(message = "角色权限字符串不能为空")
|
||||
@Size(min = 2, max = 50, message = "角色权限字符串长度必须在2-50之间")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9_-]+$", message = "角色权限字符串只能包含字母、数字、下划线和横线")
|
||||
private String roleKey;
|
||||
|
||||
@Schema(description = "显示顺序", example = "1")
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
@Min(value = 1, message = "显示顺序必须大于0")
|
||||
private Integer roleSort;
|
||||
|
||||
@Schema(description = "状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
public String getRoleName() {
|
||||
|
||||
+9
-3
@@ -3,6 +3,7 @@ package cn.novalon.manage.sys.dto.request;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
@@ -17,23 +18,28 @@ public class UserRegisterRequest {
|
||||
@Schema(description = "用户名", example = "testuser")
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
@Size(min = 3, max = 50, message = "用户名长度必须在3-50之间")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9_-]+$", message = "用户名只能包含字母、数字、下划线和横线")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "昵称", example = "测试用户")
|
||||
@Size(max = 100, message = "昵称长度不能超过100")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "密码", example = "123456")
|
||||
@Schema(description = "密码", example = "Admin123")
|
||||
@NotBlank(message = "密码不能为空")
|
||||
@Size(min = 6, max = 100, message = "密码长度必须在6-100之间")
|
||||
@Size(min = 8, max = 20, message = "密码长度必须在8-20之间")
|
||||
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$", message = "密码必须包含大小写字母和数字")
|
||||
private String password;
|
||||
|
||||
@Schema(description = "邮箱", example = "test@example.com")
|
||||
@NotBlank(message = "邮箱不能为空")
|
||||
@Email(message = "邮箱格式不正确")
|
||||
@Size(max = 100, message = "邮箱长度不能超过100")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "手机号", example = "13800138000")
|
||||
@Size(max = 20, message = "手机号长度不能超过20")
|
||||
@NotBlank(message = "手机号不能为空")
|
||||
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
|
||||
private String phone;
|
||||
|
||||
public String getUsername() {
|
||||
|
||||
+24
-9
@@ -9,12 +9,16 @@ import cn.novalon.manage.sys.core.command.CreateRoleCommand;
|
||||
import cn.novalon.manage.sys.core.command.UpdateRoleCommand;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Validator;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 系统角色处理器
|
||||
*
|
||||
@@ -26,9 +30,11 @@ import reactor.core.publisher.Mono;
|
||||
public class SysRoleHandler {
|
||||
|
||||
private final ISysRoleService roleService;
|
||||
private final Validator validator;
|
||||
|
||||
public SysRoleHandler(ISysRoleService roleService) {
|
||||
public SysRoleHandler(ISysRoleService roleService, Validator validator) {
|
||||
this.roleService = roleService;
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
@Operation(summary = "获取所有角色", description = "获取系统中所有角色列表")
|
||||
@@ -88,14 +94,23 @@ public class SysRoleHandler {
|
||||
@Operation(summary = "创建角色", description = "创建新角色")
|
||||
public Mono<ServerResponse> createRole(ServerRequest request) {
|
||||
return request.bodyToMono(RoleCreateRequest.class)
|
||||
.map(req -> CreateRoleCommand.of(
|
||||
req.getRoleName(),
|
||||
req.getRoleKey(),
|
||||
req.getRoleSort(),
|
||||
req.getStatus()
|
||||
))
|
||||
.flatMap(roleService::createRole)
|
||||
.flatMap(role -> ServerResponse.status(HttpStatus.CREATED).bodyValue(role));
|
||||
.flatMap(req -> {
|
||||
var violations = validator.validate(req);
|
||||
if (!violations.isEmpty()) {
|
||||
Map<String, String> errors = new HashMap<>();
|
||||
violations.forEach(v -> errors.put(v.getPropertyPath().toString(), v.getMessage()));
|
||||
return ServerResponse.badRequest().bodyValue(errors);
|
||||
}
|
||||
|
||||
return Mono.just(CreateRoleCommand.of(
|
||||
req.getRoleName(),
|
||||
req.getRoleKey(),
|
||||
req.getRoleSort(),
|
||||
req.getStatus()
|
||||
))
|
||||
.flatMap(roleService::createRole)
|
||||
.flatMap(role -> ServerResponse.status(HttpStatus.CREATED).bodyValue(role));
|
||||
});
|
||||
}
|
||||
|
||||
@Operation(summary = "更新角色", description = "更新角色信息")
|
||||
|
||||
+25
-13
@@ -10,6 +10,7 @@ import cn.novalon.manage.sys.core.command.CreateUserCommand;
|
||||
import cn.novalon.manage.sys.core.command.UpdateUserCommand;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Validator;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
@@ -19,7 +20,7 @@ import reactor.core.publisher.Mono;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 用户处理器
|
||||
@@ -36,9 +37,11 @@ import java.util.Map;
|
||||
public class SysUserHandler {
|
||||
|
||||
private final ISysUserService userService;
|
||||
private final Validator validator;
|
||||
|
||||
public SysUserHandler(ISysUserService userService) {
|
||||
public SysUserHandler(ISysUserService userService, Validator validator) {
|
||||
this.userService = userService;
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
@Operation(summary = "获取所有用户", description = "获取系统中所有用户列表")
|
||||
@@ -110,17 +113,26 @@ public class SysUserHandler {
|
||||
@Operation(summary = "创建用户", description = "创建新用户")
|
||||
public Mono<ServerResponse> createUser(ServerRequest request) {
|
||||
return request.bodyToMono(UserRegisterRequest.class)
|
||||
.map(req -> CreateUserCommand.of(
|
||||
req.getUsername(),
|
||||
req.getPassword(),
|
||||
req.getEmail(),
|
||||
req.getNickname(),
|
||||
req.getPhone(),
|
||||
null,
|
||||
null
|
||||
))
|
||||
.flatMap(userService::createUser)
|
||||
.flatMap(user -> ServerResponse.status(HttpStatus.CREATED).bodyValue(user));
|
||||
.flatMap(req -> {
|
||||
var violations = validator.validate(req);
|
||||
if (!violations.isEmpty()) {
|
||||
Map<String, String> errors = new HashMap<>();
|
||||
violations.forEach(v -> errors.put(v.getPropertyPath().toString(), v.getMessage()));
|
||||
return ServerResponse.badRequest().bodyValue(errors);
|
||||
}
|
||||
|
||||
return Mono.just(CreateUserCommand.of(
|
||||
req.getUsername(),
|
||||
req.getPassword(),
|
||||
req.getEmail(),
|
||||
req.getNickname(),
|
||||
req.getPhone(),
|
||||
null,
|
||||
null
|
||||
))
|
||||
.flatMap(userService::createUser)
|
||||
.flatMap(user -> ServerResponse.status(HttpStatus.CREATED).bodyValue(user));
|
||||
});
|
||||
}
|
||||
|
||||
@Operation(summary = "更新用户", description = "更新用户信息")
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.5.12</version>
|
||||
<version>3.5.13</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<spring-boot.version>3.5.12</spring-boot.version>
|
||||
<spring-boot.version>3.5.13</spring-boot.version>
|
||||
<spring-cloud.version>2025.0.0</spring-cloud.version>
|
||||
<lombok.version>1.18.30</lombok.version>
|
||||
<resilience4j.version>2.2.0</resilience4j.version>
|
||||
|
||||
Reference in New Issue
Block a user