Spring MVC中如何对URL中的字段实体进行加密编码?
解决Spring MVC表单GET提交参数暴露的问题
首先得明确核心:GET请求的参数本身就会被放在URL里,这是HTTP协议的特性。要解决参数明文暴露的问题,有两种核心方案,你可以根据业务需求来选:
一、最省心的方案:改用POST请求
如果不需要生成可分享的URL,直接把请求方式改成POST是最简单有效的——POST请求的参数会放在请求体里,不会出现在URL中。
具体修改步骤:
- 修改main.jsp的表单:把
method="get"改成method="post"
<form action="successA" method="post">
- 修改Controller的请求映射:把
RequestMethod.GET换成RequestMethod.POST
@RequestMapping(value = "/successA", method = RequestMethod.POST) public ModelAndView method(@Valid @ModelAttribute("bean") Bean bean, BindingResult result ) { // 原有逻辑完全不用改,正常处理表单提交即可 }
这个方案几乎零成本,也是最推荐的做法。
二、必须用GET?那就加密参数
如果因为业务需求(比如要生成可分享的链接)必须用GET,那只能对参数进行加密,让URL里的内容变成密文,后端再解密处理。这里要注意:你提到的URIEditor只是做URI标准编码(比如把空格转成%20),并不是加密,还是能看到明文,完全不适合你的场景。
实现步骤:
1. 前端提交前加密参数
我们可以用JavaScript在表单提交前把所有参数加密成一个字符串,再作为单个参数传递。这里以AES加密为例,需要引入crypto-js库:
在main.jsp里添加这段脚本:
<script src="https://cdn.jsdelivr.net/npm/crypto-js@4.1.1/crypto-js.min.js"></script> <script> // 监听表单提交事件 document.querySelector('form').addEventListener('submit', function(e) { e.preventDefault(); // 先阻止默认提交行为 // 密钥和IV要和后端保持一致,建议用16位长度 const secretKey = CryptoJS.enc.Utf8.parse('your16bitSecretKey'); const iv = CryptoJS.enc.Utf8.parse('your16bitIV'); // 收集所有表单参数 const formData = new FormData(this); const paramObj = {}; formData.forEach((val, key) => paramObj[key] = val); // 把参数转成JSON字符串再加密 const encryptedStr = CryptoJS.AES.encrypt( JSON.stringify(paramObj), secretKey, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 } ).toString(); // 跳转到successA,把加密后的字符串作为data参数传递 window.location.href = `successA?data=${encodeURIComponent(encryptedStr)}`; }); </script>
2. 后端解密参数
修改Controller的方法,接收加密后的data参数,解密后转成你的Bean对象:
import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.util.StringUtils; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; import java.util.Set; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; @RequestMapping(value = "/successA", method = RequestMethod.GET) public ModelAndView method(@RequestParam("data") String encryptedData, BindingResult result ) throws Exception { // 先判断参数是否为空 if (!StringUtils.hasText(encryptedData)) { return new ModelAndView("main"); } // 密钥和IV要和前端完全一致 String key = "your16bitSecretKey"; String ivStr = "your16bitIV"; // 初始化解密工具 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES"); IvParameterSpec iv = new IvParameterSpec(ivStr.getBytes()); cipher.init(Cipher.DECRYPT_MODE, secretKey, iv); // 解密并转成JSON字符串 byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedData)); String decryptedJson = new String(decryptedBytes); // 把JSON转成Bean对象(需要引入Jackson依赖) ObjectMapper objectMapper = new ObjectMapper(); Bean bean = objectMapper.readValue(decryptedJson, Bean.class); // 保持原有参数校验逻辑 ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); Validator validator = factory.getValidator(); Set<ConstraintViolation<Bean>> violations = validator.validate(bean); if (!violations.isEmpty()) { for (ConstraintViolation<Bean> violation : violations) { result.addError(new FieldError("bean", violation.getPropertyPath().toString(), violation.getMessage())); } return new ModelAndView("main"); } ModelAndView view = new ModelAndView("successAnother"); view.addObject("bean", bean); return view; }
别忘了在pom.xml里添加Jackson依赖(如果还没加的话):
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency>
关于URIEditor的说明
你提到的org.springframework.beans.propertyeditors.URIEditor其实是Spring用来处理URI类型属性的编辑器,它的作用是把字符串格式的URI转成URI对象,或者反过来把URI转成字符串——只是做URI的标准编码/解码(处理空格、特殊字符),根本不是加密,完全满足不了你隐藏参数内容的需求。举个简单的使用例子,但确实帮不到你:
@InitBinder public void initBinder(WebDataBinder binder) { // 注册URIEditor,处理URI类型的属性 binder.registerCustomEditor(URI.class, new URIEditor()); }
内容的提问来源于stack exchange,提问作者Ayush
相关产品推荐
相关产品推荐

