java - 加密 Spring Boot Rest Api 查询参数
问题描述
我知道这个问题已被多次询问,但没有人回答我的问题,所以请不要将其标记为重复。
我需要使用 AES 加密我在 rest API 中的参数。我创建了 2 个 API,用于加密和解密。
import AesTest;
import com.google.zxing.BarcodeFormat;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.net.URLDecoder;
import java.net.URLEncoder;
@RestController
@SpringBootApplication
public class BarcodeApplication {
public static void main(String[] args) {
SpringApplication.run(BarcodeApplication.class, args);
}
@GetMapping(value = "encrypt")
public String encrypt(@RequestParam BarcodeFormat barcodeFormat, @RequestParam(defaultValue = "this is test") String text, @RequestParam(defaultValue = "200") String width, @RequestParam(defaultValue = "200") String height, HttpServletResponse response) throws Exception {
System.out.println("barcodeFormat = " + barcodeFormat);
System.out.println("text = " + text);
System.out.println("width = " + width);
System.out.println("height = " + height);
response.setContentType("image/png");
String encryptQuery = AesTest.encrypt(barcodeFormat.toString() + "&" + text + "&" + width + "&" + height);
String urlEncodedData = URLEncoder.encode(encryptQuery, "UTF-8");
return urlEncodedData;
}
@RequestMapping(path = "barcode/{query}")
public String getMessage(@PathVariable("query") String query, HttpServletResponse response) throws Exception {
String decryptQuery = AesTest.decrypt(query);
String urlEncodedData = URLDecoder.decode(decryptQuery, "UTF-8");
String[] queryArr = urlEncodedData.split("&");
BarcodeFormat barcodeFormat = BarcodeFormat.valueOf(queryArr[0]);
String text = queryArr[1];
String width = queryArr[2];
String height = queryArr[3];
System.out.println("barcodeFormat = " + barcodeFormat);
System.out.println("text = " + text);
System.out.println("width = " + width);
System.out.println("height = " + height);
return null;
}
}`
下面是我的 AesTest 文件
import org.apache.tomcat.util.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
public class AesTest {
private static final String secretKey = "aesEncryptionKeyasdfghjk";
private static final String initVector = "encryptionIntVec";
public static String decrypt(String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes(StandardCharsets.UTF_8));
SecretKeySpec skeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String encrypt(String value) {
try {
IvParameterSpec ivParameterSpec = new IvParameterSpec(initVector.getBytes(StandardCharsets.UTF_8));
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(value.getBytes());
return Base64.encodeBase64String(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
如果我使用http://localhost:8080/encrypt?text= test &height=50&barcodeFormat=CODE_128&width=200
它返回给我 9mXpav2uRPRsNufSRpj1aXiD5sBVgmjFoyst8cQp%2Bms%3D。
在第二个 API http://localhost:8080/barcode/9mXpav2uRPRsNufSRpj1aXiD5sBVgmjFoyst8cQp%2Bms%3D中传递这个值工作得很好。
但是如果我更改第一个 API 的值,即http://localhost:8080/encrypt?text= testshri &height=50&barcodeFormat=CODE_128&width=200
它返回 Js%2Butdm9mS9jxSNBbvHeCJaKv7TqrtImTU%2FqcDWaSo8%3D。
在第二个 API 中传递此值会返回 HTTP 状态 400 – 错误请求。
更改查询参数中的文本会产生不同的结果。我究竟做错了什么???
解决方案
我认为问题出在您传递的参数上,因为它包含%
可能损坏请求 url 的 ** ** 字符。因此,有必要在将数据用于 URL 之前对其进行编码,然后在检索期间对其进行解码。
这是您可以遵循的示例:
=== 编码:
private String encodeValue(String value) {
return URLEncoder.encode(value, StandardCharsets.UTF_8.toString());
}
@Test
public void givenRequestParam_whenUTF8Scheme_thenEncode() throws Exception {
Map<String, String> requestParams = new HashMap<>();
requestParams.put("key1", "value 1");
requestParams.put("key2", "value@!$2");
requestParams.put("key3", "value%3");
String encodedURL = requestParams.keySet().stream()
.map(key -> key + "=" + encodeValue(requestParams.get(key)))
.collect(joining("&", "http://www.baeldung.com?", ""));
assertThat(testUrl, is(encodedURL));
}
=== 解码:
private String decode(String value) {
return URLDecoder.decode(value, StandardCharsets.UTF_8.toString());
}
@Test
public void givenRequestParam_whenUTF8Scheme_thenDecodeRequestParams() {
URI uri = new URI(testUrl);
String scheme = uri.getScheme();
String host = uri.getHost();
String query = uri.getRawQuery();
String decodedQuery = Arrays.stream(query.split("&"))
.map(param -> param.split("=")[0] + "=" + decode(param.split("=")[1]))
.collect(Collectors.joining("&"));
assertEquals("http://www.baeldung.com?key1=value 1&key2=value@!$2&key3=value%3",
scheme + "://" + host + "?" + decodedQuery);
}
你可以查看Baeldung,它更详细地解释了这个概念。
推荐阅读
- java - 如何从对象中检索 qrcode 数据?
- neural-network - 辍学正则化的目的是什么?
- mysql - MySql 选择并更新并返回更新后的 ids(以原子方式)
- c - 必须打印一个数字序列 15, 12, 24, 21, 42, 39, 78, 75, 150, 147
- reactjs - 具有扩展的可区分联合的 React 组件的 TypeScript 错误“不可分配给类型‘IntrinsicAttributes’”
- excel - INDEX 和 MATCH :值不在第一列,公式返回 #N/A
- reactjs - 在带有钩子的函数处理程序中使用 useRef
- jenkins - Jenkins 的 findbugs Gradle 构建
- php - Node js socket.io 仅针对特定事件订阅广播
- python-3.x - 自动化 pdfminer.six LAParams 配置