Merge branch 'dev' into test
This commit is contained in:
@@ -7,6 +7,12 @@ ALTER TABLE infra_file ADD aes_iv VARCHAR(128);
|
||||
|
||||
COMMENT ON COLUMN infra_file.aes_iv IS 'AES加密时的随机IV(Base64编码)';
|
||||
|
||||
-- 3. Databus 客户端凭证新增匿名访问配置(DM8)
|
||||
ALTER TABLE databus_api_client_credential ADD allow_anonymous BIT DEFAULT '0' NOT NULL;
|
||||
ALTER TABLE databus_api_client_credential ADD anonymous_user_id BIGINT;
|
||||
COMMENT ON COLUMN databus_api_client_credential.allow_anonymous IS '是否允许匿名访问';
|
||||
COMMENT ON COLUMN databus_api_client_credential.anonymous_user_id IS '匿名访问固定用户';
|
||||
|
||||
-- 3 业务附件统一管理
|
||||
DROP TABLE IF EXISTS infra_bsn_file;
|
||||
CREATE TABLE infra_bsn_file (
|
||||
|
||||
@@ -656,6 +656,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (36, 3, '本部门数据权限', '3', 'system_data_scope', 0, '', '', '本部门数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:16', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (37, 4, '本部门及以下数据权限', '4', 'system_data_scope', 0, '', '', '本部门及以下数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:21', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (38, 5, '仅本人数据权限', '5', 'system_data_scope', 0, '', '', '仅本人数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:23', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (200010, 6, '公司及所属部门数据权限', '6', 'system_data_scope', 0, '', '', '公司及所属部门数据权限', 'admin', '2021-01-05 17:03:48', '', '2025-10-24 00:00:00', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (39, 0, '成功', '0', 'system_login_result', 0, 'success', '', '登陆结果 - 成功', '', '2021-01-18 06:17:36', '1', '2022-02-16 13:23:49', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (40, 10, '账号或密码不正确', '10', 'system_login_result', 0, 'primary', '', '登陆结果 - 账号或密码不正确', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:27', '0');
|
||||
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (41, 20, '用户被禁用', '20', 'system_login_result', 0, 'warning', '', '登陆结果 - 用户被禁用', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:23:57', '0');
|
||||
|
||||
@@ -198,7 +198,7 @@ COMMENT ON COLUMN databus_api_transform.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN databus_api_transform.deleted IS '逻辑删除标记';
|
||||
|
||||
|
||||
-- 统一外部网关 - 客户端凭证表(DM8)
|
||||
-- 统一外部网关 - 客户端凭证表(DM8)
|
||||
-- 可重复执行的建表脚本,执行前请备份历史数据
|
||||
|
||||
DROP TABLE IF EXISTS databus_api_client_credential;
|
||||
@@ -212,6 +212,8 @@ CREATE TABLE databus_api_client_credential (
|
||||
signature_type VARCHAR(32) NOT NULL,
|
||||
enabled BIT DEFAULT '1' NOT NULL,
|
||||
remark VARCHAR(255),
|
||||
allow_anonymous BIT DEFAULT '0' NOT NULL,
|
||||
anonymous_user_id BIGINT,
|
||||
creator VARCHAR(64) DEFAULT '' NOT NULL,
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updater VARCHAR(64) DEFAULT '' NOT NULL,
|
||||
@@ -231,6 +233,8 @@ COMMENT ON COLUMN databus_api_client_credential.encryption_type IS '加密算法
|
||||
COMMENT ON COLUMN databus_api_client_credential.signature_type IS '签名算法';
|
||||
COMMENT ON COLUMN databus_api_client_credential.enabled IS '是否启用';
|
||||
COMMENT ON COLUMN databus_api_client_credential.remark IS '备注';
|
||||
COMMENT ON COLUMN databus_api_client_credential.allow_anonymous IS '是否允许匿名访问';
|
||||
COMMENT ON COLUMN databus_api_client_credential.anonymous_user_id IS '匿名访问固定用户';
|
||||
COMMENT ON COLUMN databus_api_client_credential.creator IS '创建者';
|
||||
COMMENT ON COLUMN databus_api_client_credential.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN databus_api_client_credential.updater IS '更新者';
|
||||
|
||||
@@ -9,11 +9,7 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Base64;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 通用的签名、加解密工具类
|
||||
@@ -26,7 +22,7 @@ public final class CryptoSignatureUtils {
|
||||
public static final String SIGNATURE_TYPE_SHA256 = "SHA256";
|
||||
|
||||
private static final String AES_TRANSFORMATION = "AES/ECB/PKCS5Padding";
|
||||
private static final String SIGNATURE_FIELD = "signature";
|
||||
public static final String SIGNATURE_FIELD = "signature";
|
||||
|
||||
private CryptoSignatureUtils() {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.zt.plat.framework.common.validation;
|
||||
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 密码复杂度校验注解,要求至少包含大小写字母、数字、特殊字符中的三种。
|
||||
* @author chenbowen
|
||||
*/
|
||||
@Target({
|
||||
ElementType.METHOD,
|
||||
ElementType.FIELD,
|
||||
ElementType.ANNOTATION_TYPE,
|
||||
ElementType.CONSTRUCTOR,
|
||||
ElementType.PARAMETER,
|
||||
ElementType.TYPE_USE
|
||||
})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Constraint(validatedBy = PasswordValidator.class)
|
||||
public @interface Password {
|
||||
|
||||
String message() default "密码必须包含大写字母、小写字母、数字、特殊字符中的至少三种";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.zt.plat.framework.common.validation;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
|
||||
/**
|
||||
* 密码复杂度校验:至少命中以下类别中的三类:大写字母、小写字母、数字、特殊字符。
|
||||
*/
|
||||
public class PasswordValidator implements ConstraintValidator<Password, String> {
|
||||
|
||||
@Override
|
||||
public void initialize(Password constraintAnnotation) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||
if (StrUtil.isBlank(value)) {
|
||||
// 空值交由 @NotEmpty 等注解处理;在无需修改密码时视为空密码通过
|
||||
return true;
|
||||
}
|
||||
int categories = 0;
|
||||
if (value.matches(".*[A-Z].*")) {
|
||||
categories++;
|
||||
}
|
||||
if (value.matches(".*[a-z].*")) {
|
||||
categories++;
|
||||
}
|
||||
if (value.matches(".*[0-9].*")) {
|
||||
categories++;
|
||||
}
|
||||
if (value.matches(".*[^A-Za-z0-9].*")) {
|
||||
categories++;
|
||||
}
|
||||
return categories >= 3;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.zt.plat.framework.common.validation;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class PasswordValidatorTest {
|
||||
|
||||
private final PasswordValidator validator = new PasswordValidator();
|
||||
|
||||
@Test
|
||||
void shouldAcceptBlankPassword() {
|
||||
assertTrue(validator.isValid(null, null));
|
||||
assertTrue(validator.isValid("", null));
|
||||
assertTrue(validator.isValid(" ", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectInsufficientComplexity() {
|
||||
assertFalse(validator.isValid("abcdef", null));
|
||||
assertFalse(validator.isValid("ABCDEF", null));
|
||||
assertFalse(validator.isValid("ABC123", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAcceptComplexPassword() {
|
||||
assertTrue(validator.isValid("Abc123!", null));
|
||||
assertTrue(validator.isValid("1a#BCdef", null));
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import com.zt.plat.module.databus.controller.admin.gateway.vo.credential.ApiClie
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.credential.ApiClientCredentialSaveReqVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.credential.ApiClientCredentialSimpleRespVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiClientCredentialDO;
|
||||
import com.zt.plat.module.databus.service.gateway.ApiAnonymousUserService;
|
||||
import com.zt.plat.module.databus.service.gateway.ApiClientCredentialService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@@ -26,6 +27,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import java.util.List;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||
|
||||
@Tag(name = "管理后台 - API 客户端凭证")
|
||||
@RestController
|
||||
@@ -35,19 +37,24 @@ import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
public class ApiClientCredentialController {
|
||||
|
||||
private final ApiClientCredentialService credentialService;
|
||||
private final ApiAnonymousUserService anonymousUserService;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "分页查询客户端凭证")
|
||||
public CommonResult<PageResult<ApiClientCredentialRespVO>> page(ApiClientCredentialPageReqVO reqVO) {
|
||||
PageResult<ApiClientCredentialDO> page = credentialService.getPage(reqVO);
|
||||
return success(ApiClientCredentialConvert.INSTANCE.convertPage(page));
|
||||
PageResult<ApiClientCredentialRespVO> respPage = ApiClientCredentialConvert.INSTANCE.convertPage(page);
|
||||
populateAnonymousInfo(respPage.getList());
|
||||
return success(respPage);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "查询凭证详情")
|
||||
public CommonResult<ApiClientCredentialRespVO> get(@RequestParam("id") Long id) {
|
||||
ApiClientCredentialDO credential = credentialService.get(id);
|
||||
return success(ApiClientCredentialConvert.INSTANCE.convert(credential));
|
||||
ApiClientCredentialRespVO respVO = ApiClientCredentialConvert.INSTANCE.convert(credential);
|
||||
populateAnonymousInfo(List.of(respVO));
|
||||
return success(respVO);
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@@ -76,4 +83,14 @@ public class ApiClientCredentialController {
|
||||
List<ApiClientCredentialDO> list = credentialService.listEnabled();
|
||||
return success(ApiClientCredentialConvert.INSTANCE.convertSimpleList(list));
|
||||
}
|
||||
|
||||
private void populateAnonymousInfo(List<ApiClientCredentialRespVO> list) {
|
||||
if (isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
list.stream()
|
||||
.filter(item -> Boolean.TRUE.equals(item.getAllowAnonymous()) && item.getAnonymousUserId() != null)
|
||||
.forEach(item -> anonymousUserService.find(item.getAnonymousUserId())
|
||||
.ifPresent(details -> item.setAnonymousUserNickname(details.getNickname())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.zt.plat.module.databus.controller.admin.gateway.convert.ApiDefinition
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.ApiGatewayInvokeReqVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.definition.ApiDefinitionDetailRespVO;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.core.ApiGatewayExecutionService;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.core.IntegrationFlowManager;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.model.ApiGatewayResponse;
|
||||
import com.zt.plat.module.databus.service.gateway.ApiDefinitionService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -27,6 +28,7 @@ public class ApiGatewayController {
|
||||
|
||||
private final ApiGatewayExecutionService executionService;
|
||||
private final ApiDefinitionService apiDefinitionService;
|
||||
private final IntegrationFlowManager integrationFlowManager;
|
||||
|
||||
@PostMapping(value = "/invoke", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "测试调用 API 编排")
|
||||
@@ -43,4 +45,12 @@ public class ApiGatewayController {
|
||||
return success(definitions);
|
||||
}
|
||||
|
||||
@PostMapping("/cache/refresh")
|
||||
@Operation(summary = "刷新 API 缓存")
|
||||
public CommonResult<Boolean> refreshCache() {
|
||||
apiDefinitionService.refreshAllCache();
|
||||
integrationFlowManager.refreshAll();
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,6 +33,15 @@ public class ApiClientCredentialRespVO {
|
||||
@Schema(description = "备注", example = "默认应用凭证")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "允许匿名访问", example = "false")
|
||||
private Boolean allowAnonymous;
|
||||
|
||||
@Schema(description = "匿名访问固定用户 ID", example = "1024")
|
||||
private Long anonymousUserId;
|
||||
|
||||
@Schema(description = "匿名访问固定用户昵称", example = "张三")
|
||||
private String anonymousUserNickname;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user