记一次对请求头为multipartform-data的post请求参数加密操作以及传参

记一次对请求头为multipart/form-data的post请求参数加密操作以及传参

背景:对接一个第三方系统,提供的接口要求对参数进行RSA加密,Base64转码。而且请求头为multipart/form-data。

1、秘钥加密代码

/**
     * <p>
     * 私钥加密
     * </p>
     *
     * @param data
     *            源数据
     * @param privateKey
     *            私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = Base64.decodeBase64(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key priKey = keyFactory.generatePrivate(pkcs8KeySpec);
        return decryptOrEncrypt(data, keyFactory, priKey, Cipher.ENCRYPT_MODE, MAX_ENCRYPT_BLOCK);
    }
/**
     * 对数据进行解密/加密过程
     *
     * @param data       已加密数据
     * @param keyFactory key工厂
     * @param key        key(pub/pri)
     * @param model      加解密模式
     * @return
     * @throws Exception
     */
    private static byte[] decryptOrEncrypt(byte[] data, KeyFactory keyFactory, Key key, int model, int block) throws Exception {
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(model, key);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > block) {
                cache = cipher.doFinal(data, offSet, block);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * block;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

2、Base64转码

使用的是org.apache.commons.codec.binary包下的Base64

public static String encodeBase64String(byte[] binaryData) {
        return StringUtils.newStringUsAscii(encodeBase64(binaryData, false));
    }

3、签名MD5加密

/**
*@param str1 加密方式
*@param str2 需加密字符串
*/
private static String digest(String str1, String str2) {
		try {
			byte[] Data = str2.getBytes();
			MessageDigest Cdigest = MessageDigest.getInstance(str1);
			Cdigest.update(Data);
			// MD5直 --dig
			byte[] dig = Cdigest.digest();
			// PrintByteArray("dig", dig);
			// byte []形式表达的MD5 转化为 16H形式String表达的MD5
			String str16hMD5 = bytesToHexString(dig);
			return str16hMD5;
		} catch (Exception e) {
			return null;
		}
	}

4、请求头为multipart/form-data,参数需要特殊处理

a.获取连接对象
/**
     * 获得连接对象
     *
     * @param urlStr
     * @param headers
     * @return
     * @throws IOException
     */
    private static HttpURLConnection getHttpURLConnection(String urlStr, Map<String, Object> headers) throws IOException {
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        //设置超时时间
        conn.setConnectTimeout(50000);
        conn.setReadTimeout(50000);
        //允许输入流
        conn.setDoInput(true);
        //允许输出流
        conn.setDoOutput(true);
        //不允许使用缓存
        conn.setUseCaches(false);
        //请求方式
        conn.setRequestMethod("POST");
        //设置编码 utf-8
        conn.setRequestProperty("Charset", "UTF-8");
        //设置为长连接
        conn.setRequestProperty("connection", "keep-alive");

        //设置其他自定义 headers
        if (headers != null && !headers.isEmpty()) {
            for (Map.Entry<String, Object> header : headers.entrySet()) {
                conn.setRequestProperty(header.getKey(), header.getValue().toString());
            }
        }

        return conn;
    }

b、写文件类型的表单参数

/**
     * 写文件类型的表单参数
     *
     * @param paramName 参数名
     * @param filePath  文件路径
     * @param boundary  分隔符
     * @param out
     * @throws IOException
     */
    private static void writeFile(String paramName, String filePath, String boundary,
                                  DataOutputStream out) {
        try (BufferedReader fileReader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)))) {
            /**
             * 写分隔符--${boundary},并回车换行
             */
            String boundaryStr = BOUNDARY_PREFIX + boundary + LINE_END;
            out.write(boundaryStr.getBytes());
            /**
             * 写描述信息(文件名设置为上传文件的文件名):
             * 写 Content-Disposition: form-data; name="参数名"; filename="文件名",并回车换行
             * 写 Content-Type: application/octet-stream,并两个回车换行
             */
            String fileName = new File(filePath).getName();
            String contentDispositionStr = String.format("Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"", paramName, fileName) + LINE_END;
            out.write(contentDispositionStr.getBytes());
            String contentType = "Content-Type: application/octet-stream" + LINE_END + LINE_END;
            out.write(contentType.getBytes());

            String line;
            while ((line = fileReader.readLine()) != null) {
                out.write(line.getBytes());
            }
            //回车换行
            out.write(LINE_END.getBytes());
        } catch (Exception e) {
            LOGGER.error("写文件类型的表单参数异常", e);
        }
    }

c、写普通的表单参数

/**
 * 写普通的表单参数
 *
 * @param boundary 分隔符
 * @param out
 * @param entry    参数的键值对
 * @throws IOException
 */
private static void writeSimpleFormField(String boundary, DataOutputStream out, Map.Entry<String, Object> entry) throws IOException {
    //写分隔符--${boundary},并回车换行
    String boundaryStr = BOUNDARY_PREFIX + boundary + LINE_END;
    out.write(boundaryStr.getBytes());
    //写描述信息:Content-Disposition: form-data; name="参数名",并两个回车换行
    String contentDispositionStr = String.format("Content-Disposition: form-data; name=\"%s\"", entry.getKey()) + LINE_END + LINE_END;
    out.write(contentDispositionStr.getBytes());
    //写具体内容:参数值,并回车换行
    String valueStr = entry.getValue().toString() + LINE_END;
    out.write(valueStr.getBytes());
}

d、请求

/**
     *
     * @param url 请求路径
     * @param filePathMap 文件参数
     * @param keyValues 普通参数
     * @return 请求结果
     */
    public static String postFormData(String url,Map<String,String> filePathMap,Map<String,Object> keyValues)  {
        LOGGER.info("发起http请求的url:{}",url);
        LOGGER.info("文件请求参数filePathMap:{}",filePathMap);
        LOGGER.info("文本参数keyValues:{}",keyValues);
        StringBuffer buffer = new StringBuffer();
        HttpURLConnection con = null;
        try {
            con = getHttpURLConnection(url, null);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //分隔符,可以任意设置,这里设置为 MyBoundary+ 时间戳(尽量复杂点,避免和正文重复)
        String boundary = "MyBoundary" + System.currentTimeMillis();
        //设置 Content-Type 为 multipart/form-data; boundary=${boundary}
        con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

        //发送参数数据
        try (DataOutputStream out = new DataOutputStream(con.getOutputStream())) {
            //发送普通参数
            if (keyValues != null && !keyValues.isEmpty()) {
                for (Map.Entry<String, Object> entry : keyValues.entrySet()) {
                    writeSimpleFormField(boundary, out, entry);
                }
            }
            //发送文件类型参数
            if (filePathMap != null && !filePathMap.isEmpty()) {
                for (Map.Entry<String, String> filePath : filePathMap.entrySet()) {
                    writeFile(filePath.getKey(), filePath.getValue(), boundary, out);
                }
            }
            //写结尾的分隔符--${boundary}--,然后回车换行
            String endStr = BOUNDARY_PREFIX + boundary + BOUNDARY_PREFIX + LINE_END;
            out.write(endStr.getBytes());
            out.flush();
            out.close();
            if (con.getResponseCode() == 200) {
                InputStream in = con.getInputStream();
                BufferedReader br = new BufferedReader(new InputStreamReader(in, "utf-8"));
                String temp;
                while ((temp = br.readLine()) != null) {
                    buffer.append(temp);
                    // buffer.append("\n");
                }
                in.close();
                br.close();
            }
        } catch (Exception e) {
            LOGGER.error("HttpUtils.postFormData 请求异常!", e);
        }
        LOGGER.info("http请求相应数据:{}", buffer.toString());
        return buffer.toString();
    }

5、根据业务场景调用方法

 public String enrollAdd(EnrollAddVO vo){
        Map map = new HashMap(4);
        JSONObject requestObj = new JSONObject();
        requestObj.put("name",vo.getName());
        requestObj.put("sex",vo.getSex());
        byte[] requestString = null;
        try {
            requestString = RsaUtils.encryptByPrivateKey(requestObj.toJSONString().getBytes("UTF-8"),RAS_KEY);
        }catch (Exception e){
            log.info("RSA加密失败:{}",e.getMessage());
        }
        String base64Str = Base64.encodeBase64String(requestString);
        String sign = MD5Util.genMD5(base64Str + SECRET_KEY);
        map.put("appKey",APP_KEY);
        map.put("request",base64Str);
        map.put("sign",sign);
        return HttpClientUtil.postFormData(ENROLL_ADD_URL,null,map);
    }
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值