springBoot(七) ---在application.properties中使用随机数

本文介绍在Spring Boot的application.properties文件中如何使用RandomValuePropertySource类进行随机数配置,包括整形、长整形数、UUID及特定范围内的随机数。这种配置方式适用于密钥、测试用例等需要非固定值的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在 application.properties 中配置属性时,可以使用随机数配置,例如注入某些密钥、UUID 或者测试用例,需要每次不是一个固定的值。RandomValuePropertySource 类随机提供整形、长整形数、UUID 或者字符串。

使用代码如下:

my.secret=${random.value}

my.number=${random.int}

my.bignumber=${random.long}

my.uuid=${random.uuid}

my.number.less.than.ten=${random.int(10)}

my.number.in.range=${random.int[1024,65536]}

<think>我们通常使用对称加密算法(如AES)来实现请求体和响应体的加解密。这里,我们将使用AES算法,并且使用application.properties中的appKey和appSecret。注意:在实际应用中,appKey通常用于标识应用,而appSecret作为密钥用于加解密。但是,对称加密需要一个密钥,所以这里我们将appSecret作为AES的密钥。步骤:1.application.properties配置appKey和appSecret(注意:appSecret需要满足AES密钥的长度要求,例如16,24,32字节,对应AES-128,AES-192,AES-256)2.创建一个工具类,用于AES加解密。3.使用SpringBoot的拦截器(Interceptor)或过滤器(Filter)对请求进行解密,对响应进行加密。但是,考虑到需要将请求体解密为DTO对象,以及将返回加密,我们可以使用@ControllerAdvice和RequestBodyAdviceAdapter、ResponseBodyAdvice来实现。实现方案:一、配置属性类二、AES加解密工具类三、请求解密:通过RequestBodyAdviceAdapter,在请求体被读取并转换为对象之前进行解密四、响应加密:通过ResponseBodyAdvice,在响应体写入之前进行加密注意:为了安全,我们通常使用HTTPS来传输数据。此外,加解密会增加性能开销,请根据实际情况选择。下面我们逐步实现:第一步:配置属性类在application.properties配置:app.key=你的appKey(标识)app.secret=你的appSecret(作为AES密钥,必须为16/24/32位)第二步:创建配置类读取属性第三步:创建AES加解密工具类第四步:实现请求体解密和响应体加密的增强处理但是请注意,这种全局的加解密会影响所有接口,如果某些接口不需要加解密,我们可以通过注解或其他方式排除。由于需求是全局的,我们先实现全局处理,然后可以通过注解来排除。代码实现:1.添加依赖(SpringBootWeb已经包含,但我们需要AES相关的工具,这里使用javax.crypto)2.实现属性配置类3.实现AES工具类4.实现请求体解密和响应体加密的Advice注意:请求体解密时,我们假设客户端发送的是加密后的字符串(Base64编码),我们需要将其解密,然后才能被反序列化为DTO。响应体加密时,我们将对象序列化为字符串,然后加密,再以Base64编码形式返回。我们将返回一个统一的加密响应体,例如:{"encryptedData":"base64加密字符串"},或者直接返回加密后的Base64字符串。这里我们选择直接返回加密后的Base64字符串。但是,这样前端需要知道如何解密。因此,我们需要和前端约定加解密方式。另外,为了安全,我们还可以加入时间戳和随机数(nonce)来防止重放攻击,但这不属于加解密工具类的范畴。下面开始代码:</think># Spring Boot 加解密工具类优化方案 下面是一个完整的解决方案,通过`application.properties`中的`appKey`和`appSecret`实现接口请求体解密和响应体加密功能。 ## 1. 添加依赖到 `pom.xml` ```xml <dependencies> <!-- Spring Boot Starter --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- JSON 处理 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> <!-- 加解密库 --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency> </dependencies> ``` ## 2. 配置 `application.properties` ```properties # 加解密配置 app.encrypt.enabled=true app.encrypt.appKey=${APP_KEY:default_app_key} app.encrypt.appSecret=${APP_SECRET:default_app_secret} app.encrypt.algorithm=AES/CBC/PKCS7Padding ``` ## 3. 加密配置类 ```java import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @ConfigurationProperties(prefix = "app.encrypt") public class EncryptionConfig { private boolean enabled; private String appKey; private String appSecret; private String algorithm; // Getters and setters public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public String getAppKey() { return appKey; } public void setAppKey(String appKey) { this.appKey = appKey; } public String getAppSecret() { return appSecret; } public void setAppSecret(String appSecret) { this.appSecret = appSecret; } public String getAlgorithm() { return algorithm; } public void setAlgorithm(String algorithm) { this.algorithm = algorithm; } } ``` ## 4. 加解密工具类 ```java import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.Security; import java.util.Base64; @Component public class EncryptionUtils { private final EncryptionConfig config; @Autowired public EncryptionUtils(EncryptionConfig config) { this.config = config; Security.addProvider(new BouncyCastleProvider()); } /** * 加密数据 */ public String encrypt(String data) { if (!config.isEnabled()) return data; try { SecretKeySpec key = generateKey(); IvParameterSpec iv = generateIv(); Cipher cipher = Cipher.getInstance(config.getAlgorithm(), "BC"); cipher.init(Cipher.ENCRYPT_MODE, key, iv); byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(encryptedBytes); } catch (Exception e) { throw new RuntimeException("加密失败", e); } } /** * 解密数据 */ public String decrypt(String encryptedData) { if (!config.isEnabled()) return encryptedData; try { SecretKeySpec key = generateKey(); IvParameterSpec iv = generateIv(); Cipher cipher = Cipher.getInstance(config.getAlgorithm(), "BC"); cipher.init(Cipher.DECRYPT_MODE, key, iv); byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData); byte[] decryptedBytes = cipher.doFinal(encryptedBytes); return new String(decryptedBytes, StandardCharsets.UTF_8); } catch (Exception e) { throw new RuntimeException("解密失败", e); } } /** * 生成密钥 */ private SecretKeySpec generateKey() { // 使用 appSecret 作为密钥基础 String combinedSecret = config.getAppKey() + config.getAppSecret(); byte[] keyBytes = combinedSecret.getBytes(StandardCharsets.UTF_8); return new SecretKeySpec(keyBytes, "AES"); } /** * 生成初始化向量 */ private IvParameterSpec generateIv() { // 使用 appKey 作为初始化向量基础 byte[] ivBytes = config.getAppKey().getBytes(StandardCharsets.UTF_8); return new IvParameterSpec(ivBytes); } } ``` ## 5. 请求解密处理器 ```java import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.MethodParameter; import org.springframework.http.HttpInputMessage; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter; import java.io.IOException; import java.lang.reflect.Type; @ControllerAdvice public class DecryptRequestBodyAdvice extends RequestBodyAdviceAdapter { @Autowired private EncryptionUtils encryptionUtils; @Autowired private ObjectMapper objectMapper; @Override public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { return true; // 支持所有控制器方法 } @Override public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { if (body instanceof String) { // 如果是字符串类型,直接解密 String encrypted = (String) body; String decrypted = encryptionUtils.decrypt(encrypted); try { // 将解密后的字符串转换为目标DTO对象 return objectMapper.readValue(decrypted, parameter.getParameterType()); } catch (IOException e) { throw new RuntimeException("DTO转换失败", e); } } return body; } } ``` ## 6. 响应加密处理器 ```java import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; @ControllerAdvice public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<Object> { @Autowired private EncryptionUtils encryptionUtils; @Autowired private ObjectMapper objectMapper; @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { return true; // 支持所有控制器方法 } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { try { // 将响应对象转换为JSON字符串 String json = objectMapper.writeValueAsString(body); // 加密JSON字符串 return encryptionUtils.encrypt(json); } catch (Exception e) { throw new RuntimeException("响应加密失败", e); } } } ``` ## 7. 控制器示例 ```java import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class ApiController { @PostMapping("/api/endpoint") public ApiResponse handleRequest(@RequestBody ApiRequest request) { // 处理业务逻辑 System.out.println("接收到解密后的请求: " + request); // 返回响应对象 return new ApiResponse(200, "操作成功", request.getData()); } // DTO 示例 static class ApiRequest { private String data; // Getters and setters public String getData() { return data; } public void setData(String data) { this.data = data; } } static class ApiResponse { private int code; private String message; private Object result; public ApiResponse(int code, String message, Object result) { this.code = code; this.message = message; this.result = result; } // Getters and setters public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public Object getResult() { return result; } public void setResult(Object result) { this.result = result; } } } ``` ## 使用说明 1. **配置密钥**:在 `application.properties` 中设置 `app.encrypt.appKey` 和 `app.encrypt.appSecret` 2. **启用/禁用**:通过 `app.encrypt.enabled` 控制加解密功能开关 3. **请求流程**: - 客户端发送加密的请求体(Base64编码) - 解密处理器将请求体解密并转换为DTO对象 - 控制器处理业务逻辑 - 响应处理器将响应对象加密后返回 4. **算法配置**:通过 `app.encrypt.algorithm` 可配置不同的加密算法 ## 安全性建议 1. **密钥管理**:生产环境应使用环境变量或密钥管理系统存储密钥[^3] 2. **HTTPS**:始终使用HTTPS传输加密数据 3. **密钥轮换**:定期更换`appKey`和`appSecret` 4. **算法升级**:根据需要升级到更安全的算法(如AES-256-GCM) ## 注意事项 - 此方案适用于JSON格式的请求/响应体 - 如果需要处理非JSON格式,需要调整加解密处理器 - 加解密会增加少量性能开销,建议在高并发场景下评估影响
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值