Java Web

安全功能

参数检验

基于Hibernate Validator实现数据校验

集成步骤:

  1. 添加依赖: 在你的项目中添加Hibernate Validator的依赖。你可以使用Maven或者Gradle进行依赖管理。

    如果使用Maven,可以在pom.xml文件中添加如下依赖:

    1
    2
    3
    4
    5
    <dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.6.Final</version>
    </dependency>
  2. 配置Spring Boot: 如果你是在Spring Boot项目中使用Hibernate Validator,通常不需要任何显式的配置,因为Spring Boot已经默认集成了Hibernate Validator。

  3. 使用校验注解: 在需要校验的DTO类字段上使用Hibernate Validator提供的校验注解,比如@NotNull@Size@Pattern等。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import javax.validation.constraints.NotBlank;
    import javax.validation.constraints.NotNull;

    public class UserDTO {
    @NotNull
    private Long id;

    @NotBlank
    private String username;

    // Getters and setters
    }
  4. 使用@Valid注解: 在Controller中使用@Valid注解对需要校验的参数进行标记。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import org.springframework.http.ResponseEntity;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.*;

    @RestController
    @RequestMapping("/users")
    public class UserController {

    @PostMapping
    public ResponseEntity<String> createUser(@Valid @RequestBody UserDTO userDTO) {
    // 处理创建用户的逻辑
    return ResponseEntity.ok("User created successfully");
    }
    }
  5. 处理校验结果: 如果校验失败,Spring会自动返回错误信息。你可以在全局异常处理器中处理MethodArgumentNotValidException异常,以提供更友好的错误响应。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
      import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RestControllerAdvice;

    @RestControllerAdvice
    public class GlobalExceptionHandler {

    @ExceptionHandler({ MethodArgumentNotValidException.class})
    public Result validatorException(final HttpServletRequest request, final Throwable ex) {
    String errorMsg = "";
    List<FieldError> fieldErrors = new ArrayList<>();
    MethodArgumentNotValidException notValidException = (MethodArgumentNotValidException) ex;
    fieldErrors = notValidException.getBindingResult().getFieldErrors();
    if (CollUtil.isNotEmpty(fieldErrors)) {
    StrBuilder builder = StrBuilder.create();
    for (FieldError error : fieldErrors) {
    String defaultMessage = error.getDefaultMessage();
    defaultMessage = ValidatorUtil.getMessage(defaultMessage);
    builder.append(error.getField()).append("=>").append(defaultMessage).append(",");
    }
    errorMsg = StrUtil.removeSuffix(builder.toString(), ",");
    }
    // String errorMsg = notValidException.getBindingResult().getFieldError().getDefaultMessage();
    log.error("验证实体异常 => {}", ex.getMessage(), ex);
    return ResultGenerator.genFailedResult(errorMsg);
    }
    }
实现自定义注解的正则校验

思路:

基于自定义注解+配置文件。在注解上配置{文件.属性},实现基于配置文件的正则校验方式。

定义自定义注解: 首先,你需要定义一个自定义注解,用于标记需要进行正则校验的字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Documented
@Constraint(validatedBy = CustomRegexValidator.class) // 指定校验逻辑的类
@Target({ElementType.FIELD, ElementType.PARAMETER}) // 注解可以标记在字段和参数上
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomRegex {
String message() default "Invalid value";

String regex();

boolean inversion() default false;

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}

实现校验逻辑: 创建一个实现了ConstraintValidator接口的类,用于执行正则校验逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class CustomRegexValidator implements ConstraintValidator<CustomRegex, Object> {
/**
* 正则表达式
*/
private String regex;
/**
* 是否取反
*/
private boolean inversion;

@Override
public void initialize(CustomRegex customAnnotation) {
this.regex = customAnnotation.regex();
this.inversion = customAnnotation.inversion();
}


@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
boolean isValidB = true;
if (StrUtil.isNotEmpty(regex)) {
String reg = ValidatorUtil.getRegex(regex);
if (ObjectUtil.isEmpty(value)) {
isValidB = true;
} else {
isValidB = ReUtil.isMatch(reg, String.valueOf(value));
if (inversion) {
return !isValidB;
}
}
}
return isValidB;
}

}

在DTO类中使用自定义注解: 在需要进行正则校验的字段上,使用刚才定义的自定义注解。

1
2
3
4
5
6
7
8
public class UserDTO {
// ...

@CustomRegex(regex = "[A-Za-z0-9]+", message = "Invalid username format")
private String username;

// ...
}

处理校验结果: 在Controller中使用@Valid注解进行校验,如果校验失败,会触发异常。

1
2
3
4
5
6
7
8
9
10
11
@RestController
@RequestMapping("/users")
@Validated
public class UserController {

@PostMapping
public ResponseEntity<String> createUser(@Valid @RequestBody UserDTO userDTO) {
// 处理创建用户的逻辑
return ResponseEntity.ok("User created successfully");
}
}

当请求到达Controller时,Spring会自动根据自定义注解中的正则表达式进行校验。如果校验失败,会根据自定义注解中的错误消息返回相应的错误信息。

使用工具类获取参数配置文件
在resource里新增文件xx.properties,xxRegex.properties文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class ValidatorUtil {
private final static Props messageProps = new Props("xx.properties");
private final static Props regexProps = new Props("xxRegex.properties");

/**
* @param key
* @return
* @Title: getMessageKey
* @Description: 获取对应的消息
*/
public static String getMessage(String key) {
if (StrUtil.startWith(key, "{") && StrUtil.endWith(key, "}")) {
key = StrUtil.removePrefix(key, "{");
key = StrUtil.removeSuffix(key, "}");
return String.valueOf(messageProps.get(key));
} else {
return key;
}
}

/**
* @param key
* @return
* @Title: getRegexp
* @Description: 获取正则表达式
*/
public static String getRegex(String key) {
if (StrUtil.startWith(key, "{") && StrUtil.endWith(key, "}")) {
key = StrUtil.removePrefix(key, "{");
key = StrUtil.removeSuffix(key, "}");
return String.valueOf(regexProps.get(key));
} else {
return key;
}
}
}
参数校验常用注解

常用的参数校验注解:

  1. @NotNull:字段不允许为null。
  2. @NotEmpty:字段不允许为空(可以是空字符串)。
  3. @NotBlank:字段不允许为空白字符(空格等)。
  4. @Size(min, max):字段的长度必须在指定范围内。
  5. @Min(value):字段必须大于等于指定值。
  6. @Max(value):字段必须小于等于指定值。
  7. @Email:字段必须是合法的电子邮件地址。
  8. @Pattern(regexp):字段必须匹配指定的正则表达式。

常用的正则表达式匹配规则:

  1. 数字:\d+
  2. 字母:[A-Za-z]+
  3. 数字和字母:[A-Za-z0-9]+
  4. 整数:-?\d+
  5. 正整数:\d+
  6. 非负整数:\d+0
  7. 浮点数:-?\d+(\.\d+)?
  8. 手机号:^1[0-9]{10}$
  9. 邮箱地址:^[A-Za-z0-9+_.-]+@(.+)$
  10. URL:^(http|https)://.+
  11. 身份证号(简化校验,可能不够准确):\d{17}[\dX]|\d{15}
  12. 密码(必须由字母、数字和(_*#@-)这些符号组成且要大于8位):^[a-zA-Z0-9_*#@-]{8,}$
  13. 非法字符:[`~!$^&*"()=|{}’:;’\[\].<>/?~!¥……&*()——|{}【】#\\‘;:”“’。’,、?%\-+]|(^(n|N)(u|U)(l|L)(l|L)$)
  14. 中文、英文、数字包括下划线:^\\s*$|^[\\u4E00-\\u9FA5A-Za-z0-9_]+$

配置文件加密

Jasypt 的自定义加解密

创建自定义加解密器: 首先,你需要创建一个自定义的加解密器,实现 org.jasypt.encryption.StringEncryptor 接口。在这个类中,你可以实现你自己的加密和解密逻辑。以下是一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
javaCopy codeimport org.jasypt.encryption.StringEncryptor;

public class CustomEncryptor implements StringEncryptor {

@Override
public String encrypt(String message) {
// Implement your custom encryption logic here
// Return the encrypted value
return message;
}

@Override
public String decrypt(String encryptedMessage) {
// Implement your custom decryption logic here
// Return the decrypted value
return encryptedMessage;
}
}

配置自定义加解密器:application.propertiesapplication.yml 中,配置 Spring Boot 使用你的自定义加解密器。例如:

1
2
3
jasypt:
encryptor:
bean: customEncryptor

注册自定义加解密器为 Spring Bean: 在你的 Spring Boot 应用程序中,创建一个配置类,将你的自定义加解密器注册为 Spring Bean。以下是一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
javaCopy codeimport org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.jasypt.encryption.StringEncryptor;

@Configuration
public class JasyptConfig {

@Bean(name = "customEncryptor")
public StringEncryptor customEncryptor() {
return new CustomEncryptor();
}
}

使用自定义加解密器: 在你的代码中,你可以使用 @Value 注解来注入加密的属性值,Spring Boot 会使用你的自定义加解密器来解密属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
javaCopy codeimport org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class MyComponent {

@Value("${my.encrypted.property}")
private String encryptedProperty;

public void doSomething() {
System.out.println("Decrypted Property: " + encryptedProperty);
}
}

确保在配置文件中使用加密格式 ENC(encryptedValue) 来配置加密的属性。

数据加解密

禁用nacos

bootstrap.yml
spring:
cloud:
nacos:
#注册中心
discovery:
enabled: false
instance-enabled: false
server-addr: 127.0.0.1:8848
#配置中心
config:
enabled: false
refresh-enabled: false
server-addr: ${nacos.config.addr:127.0.0.1:8848}
file-extension: yaml
group: ${nacos.config.group:DEFAULT_GROUP}
prefix: