RSA+AES实现接口验签和参数加密( 五 )

自定义过滤器/** * @author Longer * @description 获取请求参数并处理 。签名校验,报文解密,参数过滤 。* @date 2020/8/23 */@Slf4jpublic class OutRequestFilter extends OncePerRequestFilter {@SneakyThrows@Overrideprotected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException {redisUtil redisUtil = SpringUtils.getBean(RedisUtil.class);HttpServletRequest request = (HttpServletRequest) servletRequest;String requestURL = request.getRequestURI();log.info("请求路径:" + requestURL);String method = request.getMethod();if (!"POST".equals(method)) {throw new RuntimeException("暂不支持" + method + "请求方式");}//获取请求参数RequestWrapper requestWrapper = new RequestWrapper(request);String bodyString = requestWrapper.getBodyString();if (StringUtils.isEmpty(bodyString)) {throw new RuntimeException("请求体不能为空");}log.info("请求参数:" + bodyString);JsonRequest jsonRequest = JacksonUtil.jsonToBean(bodyString, JsonRequest.class);//step0 参数合法性校验(非空判断等)parameterValidate(jsonRequest);//step1 判断请求合法性 。1.不允许重复请求(通过请求唯一id判断)2.不允许请求时间与当前时间差距过大(正负10分钟)long currentTime = System.currentTimeMillis();long subTime = currentTime - jsonRequest.getTimestamp();long tenMinuteMs = 10 * 60 * 1000;if (subTime < -tenMinuteMs || subTime > tenMinuteMs) {throw new RuntimeException("请求异常,请求时间异常");}String requestUUIDKey = MessageFormat.format(RedisConstant.REQUEST_UUID, jsonRequest.getRequestId());Object requestFlag = redisUtil.get(requestUUIDKey);if (!StringUtils.isEmpty(requestFlag)) {throw new RuntimeException("请求异常,重复的请求");}redisUtil.set(requestUUIDKey, JacksonUtil.beanToJson(jsonRequest), 15 * 60);//step2 参数解密,签名校验,参数过滤和传递Map<String, Object> paramMap = RSAUtil.bean2Map(jsonRequest);paramMap.remove("sign");//根据appkey获取rsa密钥String appIdKey = MessageFormat.format(RedisConstant.REQUEST_APPID, jsonRequest.getAppId());Object ob = redisUtil.get(appIdKey);if (StringUtils.isEmpty(ob)) {throw new RuntimeException("找不到指定的appid");}String jsonString = (String) ob;JSONObject jsonObject = JSONObject.parseobject(jsonString);//rsa公钥String publicKey = jsonObject.getString("publicKey");//rsa私钥String privateKey = jsonObject.getString("privateKey");//参数排序Map<String, Object> sortedMap = RSAUtil.sort(paramMap);//拼接参数:key1Value1key2Value2String urlParams = RSAUtil.groupStringParam(sortedMap);//签名验证boolean verify = RSAUtil.verify(HexUtils.hexStringToBytes(urlParams), publicKey, jsonRequest.getSign());if (!verify) {throw new RuntimeException("签名验证失败");}//私钥解密,获取aseKeyString aseKey = RSAUtil.decryptByPrivateKey(HexUtils.hexStringToBytes(jsonRequest.getAseKey()), privateKey);if (!StringUtils.isEmpty(jsonRequest.getBody())) {// 解密请求报文String body = "";try {body = AESUtil.decrypt(jsonRequest.getBody(), aseKey, jsonRequest.getAppId().substring(16));} catch (Exception e) {log.error("请求参数解密异常:",e);throw new RuntimeException("请求参数解密异常");}//报文传递至controller层requestWrapper.setBodyString(body.getBytes(Charset.forName("UTF-8")));}//将request传递下去filterChain.doFilter(requestWrapper, servletResponse);}private void parameterValidate(JsonRequest jsonRequest) {if (StringUtils.isEmpty(jsonRequest.getAppId())) {throw new RuntimeException("参数异常,appId不能为空");}if (StringUtils.isEmpty(jsonRequest.getAseKey())) {throw new RuntimeException("参数异常,aseKey不能为空");}if (StringUtils.isEmpty(jsonRequest.getRequestId())) {throw new RuntimeException("参数异常,requestId不能为空");}if (StringUtils.isEmpty(jsonRequest.getSign())) {throw new RuntimeException("参数异常,sign不能为空");}if (jsonRequest.getTimestamp() == 0l) {throw new RuntimeException("参数异常,timestamp不能为空");}}}完整流程演示调用方HttpClientUtils类/** * @author: Longer * @description: */public class HttpClientUtils {private static Logger logger = Logger.getLogger(HttpClientUtils.class.getName());public static String doPostJson(String url, String json) {// 创建Httpclient对象CloseableHttpClient httpClient = HttpClients.createDefault();CloseableHttpResponse response = null;String resultString = "";try {// 创建Http Post请求HttpPost httpPost = new HttpPost(url);// 创建请求内容StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);httpPost.setEntity(entity);// 执行http请求response = httpClient.execute(httpPost);resultString = EntityUtils.toString(response.getEntity(), "utf-8");} catch (Exception e) {resultString = e.getMessage();logger.info("http访问失败:" + e);} finally {try {response.close();} catch (IOException e) {logger.info("response关闭失败:" + e);}}return resultString;}/*** post请求,签名和报文加密** @param url请求地址* @param json请求json参数* @param appId商户id* @param publicKeyrsa公钥* @param privateKey rsa私钥* @return*/public static String doPostJsonForSign(String url, String json, String appId, String publicKey, String privateKey) {String aseKey = appId.substring(0, 16);JsonRequest jsonRequest = new JsonRequest();jsonRequest.setRequestId(getUUID32());jsonRequest.setAppId(appId);jsonRequest.setTimestamp(System.currentTimeMillis());//aseKey 加密logger.info("开始aseKey加密....");byte[] enStr = RSAUtil.encryptByPublicKey(aseKey, publicKey);String aseKeyStr = HexUtils.bytesToHexString(enStr);jsonRequest.setAseKey(aseKeyStr);//请求参数进行加密String body = "";try {logger.info("开始请求参数加密....");body = AESUtil.encrypt(json, aseKey, appId.substring(16));} catch (Exception e) {logger.info("报文加密异常:" + e);throw new UncheckedException("报文加密异常", e);}jsonRequest.setBody(body);Map<String, Object> paramMap = RSAUtil.bean2Map(jsonRequest);paramMap.remove("sign");// 参数排序Map<String, Object> sortedMap = RSAUtil.sort(paramMap);// 拼接参数:key1Value1key2Value2String urlParams = RSAUtil.groupStringParam(sortedMap);//私钥签名logger.info("开始参数签名....");String sign = RSAUtil.sign(HexUtils.hexStringToBytes(urlParams), privateKey);jsonRequest.setSign(sign);String requestParams = JacksonUtil.beanToJson(jsonRequest);logger.info("发起请求....");String result = doPostJson(url, requestParams);return result;}public static String getUUID32() {String uuid = UUID.randomUUID().toString();uuid = uuid.replace("-", "");return uuid;}}


推荐阅读