新建一個 HttpServletRequestWrapper 實現類,在Filter 中使用該類包裝原request
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.net.URLDecoder; import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.asymmetric.KeyType; import cn.hutool.crypto.asymmetric.RSA; import cn.hutool.extra.spring.SpringUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.test.base.config.SecretConfig; import com.test.common.constant.CommonConstant; import com.test.common.exception.IchibanShoException; import com.test.common.servlet.CommonServletInputStream; import lombok.extern.slf4j.Slf4j; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.*; @Slf4j public class DecryptHttpServletRequest extends HttpServletRequestWrapper { private byte[] body; private static SecretConfig secretConfig; private final Map<String, String[]> parameterMap = new HashMap<>(); public DecryptHttpServletRequest (HttpServletRequest request) { super(request); if (Objects.isNull(secretConfig)) { secretConfig = SpringUtil.getBean(SecretConfig.class); } if (MapUtil.isNotEmpty(request.getParameterMap())) { parameterMap.putAll(request.getParameterMap()); } decryptSecretParam(); decryptPostBody(request); } private void decryptSecretParam() { String secretParam = getParameter("secretParam"); MapUtil.removeAny(parameterMap, "secretParam"); if (StrUtil.isNotBlank(secretParam) && Objects.nonNull(secretConfig)) { log.info(">>>>>>>>>>> 解密 secretParam 開始 <<<<<<<<<<<<<<<<<<"); log.info("原始secretParam: {}", secretParam); secretParam = URLDecoder.decode(secretParam, StandardCharsets.UTF_8); log.info("URLDecoder後secretParam: {}", secretParam); String privateKey = secretConfig.getPrivateKey(); String publicKey = secretConfig.getPublicKey(); if (CharSequenceUtil.isNotBlank(privateKey)) { RSA rsa = SecureUtil.rsa(privateKey, publicKey); rsa.setDecryptBlockSize(CommonConstant.RSA_DECRYPT_BLOCK_SIZE);//hutool RSA解密預設128 String decryptData = rsa.decryptStr(secretParam, KeyType.PrivateKey); log.info("RSA解碼後secretParam: {}", decryptData); decryptData = URLDecoder.decode(decryptData, StandardCharsets.UTF_8); log.info("URLDecoder後decryptData: {}", decryptData); if (CharSequenceUtil.isNotBlank(decryptData)) { decryptData = StrUtil.removePrefix(decryptData, "\""); decryptData = StrUtil.removeSuffix(decryptData, "\""); log.info("去除首尾雙引號後decryptData: {}", decryptData); List<String> params = StrUtil.split(decryptData, "&"); for (String param : params) { List<String> paramArr = StrUtil.splitTrim(param, "="); if (CollUtil.isNotEmpty(paramArr) && paramArr.size() == 2) { setParameter(paramArr.get(0), paramArr.get(1)); } } } } log.info(">>>>>>>>>>> 解密 secretParam 結束 <<<<<<<<<<<<<<<<<<"); } } private void decryptPostBody(HttpServletRequest request) { try { InputStream inputStream = request.getInputStream(); String bodyStr = IoUtil.read(new InputStreamReader(inputStream)); if (JSONUtil.isTypeJSON(bodyStr)) { JSONObject jsonObject = JSONUtil.parseObj(bodyStr); if (jsonObject.containsKey("secretData")) { bodyStr = jsonObject.getStr("secretData"); } } if (!JSONUtil.isTypeJSON(bodyStr) && CharSequenceUtil.isNotBlank(bodyStr) && Objects.nonNull(secretConfig)) { log.info(">>>>>>>>>>> 解密 secretData 開始 <<<<<<<<<<<<<<<<<<"); log.info("原始secretData: {}", bodyStr); String privateKey = secretConfig.getPrivateKey(); String publicKey = secretConfig.getPublicKey(); if (CharSequenceUtil.isNotBlank(privateKey)) { RSA rsa = SecureUtil.rsa(privateKey, publicKey); rsa.setDecryptBlockSize(CommonConstant.RSA_DECRYPT_BLOCK_SIZE); String decryptData = rsa.decryptStr(bodyStr, KeyType.PrivateKey); log.info("RSA解碼後secretData: {}", decryptData); decryptData = URLDecoder.decode(decryptData, StandardCharsets.UTF_8); log.info("URLDecoder後secretData: {}", decryptData); if (CharSequenceUtil.isNotBlank(decryptData)) { body = CharSequenceUtil.bytes(decryptData); } else { throw new IchibanShoException("無效的請求引數"); } } else { body = CharSequenceUtil.bytes(bodyStr); } log.info(">>>>>>>>>>> 解密 secretData 結束 <<<<<<<<<<<<<<<<<<"); } else { body = CharSequenceUtil.bytes(bodyStr); } } catch (Exception e) { log.error("解密失敗", e); } } public void setParameter(String name, String value) { parameterMap.put(name, new String[] { value }); } @Override public String getParameter(String name) { String[] values = parameterMap.get(name); if (ArrayUtil.isNotEmpty(values)) { return values[0]; } return StrUtil.EMPTY; } @Override public Map<String, String[]> getParameterMap() { return parameterMap; } @Override public Enumeration<String> getParameterNames() { Vector<String> parameterNames = new Vector<>(parameterMap.keySet()); return parameterNames.elements(); } @Override public String[] getParameterValues(String name) { return parameterMap.get(name); } @Override public ServletRequest getRequest() { return super.getRequest(); } @Override public BufferedReader getReader() { return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(body))); } @Override public ServletInputStream getInputStream() { return new CommonServletInputStream(new ByteArrayInputStream(body)); } }
import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; public class CommonServletInputStream extends ServletInputStream { private final ByteArrayInputStream inputStream; public CommonServletInputStream(ByteArrayInputStream inputStream) { this.inputStream = inputStream; } @Override public boolean isFinished() { return inputStream.available() == 0; } @Override public boolean isReady() { return true; } @Override public void setReadListener(ReadListener readListener) { } @Override public int read() { return inputStream.read(); } @Override public void close() throws IOException { inputStream.close(); } }
在filter中:filterChain.doFilter(new DecryptHttpServletRequest(request), response);