在调用extmcloud的接口时,传送的参数需要进行加密签名。
一、kis模块接口
以默认开通轻应用接口/extmcloud/kis/openDefaultApp.action为例:
测试调用接口类
import net.sf.json.JSONObject;
public class OpenDefaultAppActionTest {
public static void main(String[] args) throws Exception {
String url = "http://do.kdweibo.com/extmcloud/kis/openDefaultApp.action";
JSONObject requestParamObj = new JSONObject();
requestParamObj.put("mID", "123456");
requestParamObj.put("appIds", new String[] { "123","456" });
KisHttpHelper.post(url, requestParamObj.toString());
}
}
使用httpclient调用前需要加密签名
import java.security.Key;
import java.security.PrivateKey;
import java.util.UUID;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import test.extmcloud.action.KeyManager;
public class KisHttpHelper {
static Key privateKey = null;
static {
try {
privateKey = KeyManager.initPrivateKey("D:/key/kis_private.key");
} catch (Exception e) {
}
}
public static String encryptPwd(String pwd) throws Exception {
byte[] bytes = pwd.getBytes("utf-8");
byte[] encryptBytes = RSAUtils.encrypt(bytes, privateKey);
String en64pwd = new String(Base64.encodeBase64(encryptBytes));
return en64pwd;
}
public static String post(String url, String data) throws Exception {
String nonce = UUID.randomUUID().toString();
Long timestamp = System.currentTimeMillis() / 1000;
//拼接顺序不能变
String signaUrl = "url=" + constructRequestURL(url) + "×tamp=" + timestamp + "&nonce=" + nonce + "&data="
+ data;
byte[] bytes = signaUrl.getBytes("utf-8");
//加密签名
byte[] signBytes = RSAUtils.sign(bytes, (PrivateKey) privateKey);
//使用base64编码
String signature = new String(Base64.encodeBase64(signBytes));
//json格式
String jsonBody = "{'data':'" + data + "','nonce':'" + nonce + "','signature':'" + signature + "','timestamp':"
+ timestamp + "}";
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("content-type", "application/json;charset=utf-8");
StringEntity entry = new StringEntity(jsonBody, "utf-8");
httpPost.setEntity(entry);
HttpResponse httpResponse = httpClient.execute(httpPost);
int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
httpPost.abort();
throw new Exception("http 状态码 :" + statusCode + " 业务请求失败");
}
byte[] resultBytes = EntityUtils.toByteArray(httpResponse.getEntity());
String ret = new String(resultBytes, "UTF-8");
return ret;
}
private static String constructRequestURL(String url) {
int index = url.indexOf("?");
if (-1 != index) {
url = url.substring(0, index);
}
int slashIndex = url.indexOf("/", 8);
String baseURL = url.substring(0, slashIndex).toLowerCase();
int colonIndex = baseURL.indexOf(":", 8);
if (-1 != colonIndex) {
if (baseURL.startsWith("http://") && baseURL.endsWith(":80")) {
baseURL = baseURL.substring(0, colonIndex);
} else if (baseURL.startsWith("https://") && baseURL.endsWith(":443")) {
baseURL = baseURL.substring(0, colonIndex);
}
}
url = baseURL + url.substring(slashIndex);
return url;
}
}
读取密钥文件
import java.io.File;
import java.security.Key;
import org.apache.commons.io.FileUtils;
//在使用前需要先初始化key
public class KeyManager {
private static Key privateKey;
private static Key publicKey;
public static Key defaultKey;
public static void setDefaultKey(Key key) {
defaultKey = key;
}
public static Key initPrivateKey(String keyPath) {
try {
byte[] keyData = FileUtils.readFileToByteArray(new File(keyPath));
privateKey = RSAUtils.restorePrivateKey(keyData);
} catch (Exception e) {
e.printStackTrace();
return privateKey;
}
return privateKey;
}
public static Key initPublicKey(String keyPath) {
try {
byte[] keyData = FileUtils.readFileToByteArray(new File(keyPath));
publicKey = RSAUtils.restorePublicKey(keyData);
} catch (Exception e) {
e.printStackTrace();
return publicKey;
}
return publicKey;
}
public static Key getPrivateKey() {
return privateKey;
}
public static Key getpublicKey() {
return publicKey;
}
}
加密、解密、签名类
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
/**
* 利用RSA进行 1)公钥/私钥的生产 2)加密/解密 3)签名/验证签名
*
*/
public class RSAUtils {
/**
* 生成非对称密钥对 通过 KeyPair.getPublic();获得公钥PublicKey 通过
* KeyPair.getPrivate();获得私钥PrivateKey 通过PublicKey(PrivateKey).getEncoded();
* 获得Key的编码后的byte内容,其中 公钥是通过X.509格式编码的, 私钥是通过PKCS#8编码的, 恢复的时候也要通过这两种编码格式恢复
*/
public static KeyPair genKeyPair() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
return kpg.genKeyPair();
}
/**
* 通过byte数组恢复一个私钥 bytes[]:私钥编码后的数组
*/
public static PrivateKey restorePrivateKey(byte[] bytes) throws Exception {
PKCS8EncodedKeySpec pkcs = new PKCS8EncodedKeySpec(bytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(pkcs);
}
/**
* 通过byte数组恢复一个公钥 bytes[]:共钥编码后的数组
*/
public static PublicKey restorePublicKey(byte[] bytes) throws Exception {
X509EncodedKeySpec pkcs = new X509EncodedKeySpec(bytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(pkcs);
}
/**
* 加密
*
* @param src
* 要加密的明文
* @param key
* 公钥/私钥
* @return
* @throws Exception
*/
public static byte[] encrypt(byte[] src, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(src);
}
/**
* 解密 dest
*
* @param dest
* 要解密的密文
* @param key
* 私钥/公钥
* @return
* @throws Exception
*/
public static byte[] deEncrypt(byte[] dest, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(dest);
}
/**
* 利用私钥签名 src:要签名的内容
*/
public static byte[] sign(byte[] src, PrivateKey prvKey) throws Exception {
Signature sig = Signature.getInstance("MD5withRSA");
sig.initSign(prvKey);
sig.update(src);
return sig.sign();
}
/**
* 利用公钥验证签名 src:签名的内容 dest:签名
*/
public static boolean verifySign(byte[] src, byte[] dest, PublicKey pubKey)
throws Exception {
Signature sig = Signature.getInstance("MD5withRSA");
sig.initVerify(pubKey);
sig.update(src);
return sig.verify(dest);
}
public static byte[] encryptLarger(byte[] data, Key key) throws Exception {
javax.crypto.Cipher rsa = javax.crypto.Cipher.getInstance("RSA");
rsa.init(javax.crypto.Cipher.ENCRYPT_MODE, key);
SecureRandom random = new SecureRandom();
final byte[] secretKey = new byte[16];
random.nextBytes(secretKey);
final javax.crypto.Cipher aes = javax.crypto.Cipher.getInstance("AES");
SecretKeySpec k = new SecretKeySpec(secretKey, "AES");
aes.init(javax.crypto.Cipher.ENCRYPT_MODE, k);
final byte[] ciphedKey = rsa.doFinal(secretKey);
final byte[] ciphedData = aes.doFinal(data);
byte[] result = new byte[128 + ciphedData.length];
System.arraycopy(ciphedKey, 0, result, 0, 128);
System.arraycopy(ciphedData, 0, result, 128, ciphedData.length);
return result;
}
public static byte[] deEncryptLarger(byte[] data, Key key) throws Exception {
javax.crypto.Cipher rsa = javax.crypto.Cipher.getInstance("RSA");
rsa.init(javax.crypto.Cipher.DECRYPT_MODE, key);
// 恢复key
byte[] secretKeyData = new byte[128];
System.arraycopy(data, 0, secretKeyData, 0, secretKeyData.length);
byte[] cipherData = new byte[data.length - secretKeyData.length];
System.arraycopy(data, secretKeyData.length, cipherData, 0,
cipherData.length);
byte[] secretKey = rsa.doFinal(secretKeyData);
final javax.crypto.Cipher aes = javax.crypto.Cipher.getInstance("AES");
SecretKeySpec k = new SecretKeySpec(secretKey, "AES");
aes.init(javax.crypto.Cipher.DECRYPT_MODE, k);
final byte[] deciphedData = aes.doFinal(cipherData);
return deciphedData;
}
public static void writeTo(byte[] keyBytes, String filePath) {
BufferedOutputStream bos = null;
FileOutputStream fos = null;
File file = null;
try {
file = new File(filePath);
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bos.write(keyBytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
public static String encrypt(String input, Key key) throws Exception {
byte[] encryptedData = RSAUtils.encryptLarger(input.getBytes("UTF-8"),
key);
String encrpyted = Base64.encodeBase64String(encryptedData);
return encrpyted;
}
public static String decrypt(String input, Key key) throws Exception {
byte[] base64Data = Base64.decodeBase64(input);
byte[] decrptedData = RSAUtils.deEncryptLarger(base64Data, key);
return new String(decrptedData, "UTF-8");
}
public static void main(String[] args) {
// KeyPair keyPair = null;
// try {
// keyPair = genKeyPair();
// } catch (Exception e) {
// e.printStackTrace();
// }
// PublicKey publicKey = keyPair.getPublic();
// PrivateKey privateKey = keyPair.getPrivate();
// byte[] publicKeyBytes = publicKey.getEncoded();
// byte[] privateKeyBytes = privateKey.getEncoded();
// writeTo(publicKeyBytes, "D:/testpublic.key");
// writeTo(privateKeyBytes, "D:/testprivate.key");
}
}
二、open模块接口
以默认开通轻应用接口/extmcloud/open/openTryApp.action为例:
测试调用接口类
import net.sf.json.JSONObject;
public class TryAppActionTest {
public static void main(String[] args) throws Exception {
String actionName = "open/openTryApp";
String url = "http://do.kdweibo.com/extmcloud/" + actionName + ".action";
JSONObject requestParamObj = new JSONObject();
requestParamObj.put("mID", "123456");
requestParamObj.put("appId", "123456");
OpenHttpPostHelper.httpRequestWithEncryptParam(actionName, url, requestParamObj);
}
}
使用httpclient调用前需要加密签名
import java.security.Key;
import java.security.PrivateKey;
import java.util.UUID;
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class OpenHttpPostHelper {
private static Key privateKey = null;
static {
privateKey = KeyManager.initPrivateKey("D:/key/app_private.key");
}
public static String encryptPassword(String password) throws Exception {
if (password == null) {
password = "";
}
try {
byte[] bytes = password.getBytes("utf-8");
byte[] encryptBytes = RSAUtils.encrypt(bytes, privateKey);
String en64pwd = new String(Base64.encodeBase64(encryptBytes));
return en64pwd;
} catch (Exception e) {
throw new Exception("密码加密失败", e);
}
}
public static String httpRequestWithEncryptParam(String actionName, String url, JSONObject requestParamObj)
throws Exception {
String nonce = UUID.randomUUID().toString();
Long timestamp = System.currentTimeMillis() / 1000;
// 1. data加密
String data = RSAUtils.encrypt(requestParamObj.toString(), privateKey);
String signaUrl = "url=" + constructRequestURL(url) + "×tamp=" + timestamp + "&nonce=" + nonce
+ "&action=" + actionName + "&data=" + data;
byte[] bytes = signaUrl.getBytes("utf-8");
byte[] signBytes = RSAUtils.sign(bytes, (PrivateKey) privateKey);
String signature = new String(Base64.encodeBase64(signBytes));
JSONObject jsonBody = new JSONObject();
jsonBody.put("action", actionName);
jsonBody.put("data", data);
jsonBody.put("nonce", nonce);
jsonBody.put("signature", signature);
jsonBody.put("timestamp", timestamp);
// 2. 发起网络请求
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("content-type", "application/json;charset=utf-8");
StringEntity entry = new StringEntity(jsonBody.toString(), "utf-8");
httpPost.setEntity(entry);
HttpResponse httpResponse = httpClient.execute(httpPost);
int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
httpPost.abort();
throw new Exception("http 状态码 :" + statusCode + " 业务请求失败");
}
byte[] resultBytes = EntityUtils.toByteArray(httpResponse.getEntity());
// 3. 消息解包
String msgContent = new String(resultBytes, "UTF-8");
System.out.println("response:" + msgContent);
return msgContent;
}
private static String constructRequestURL(String url) {
int index = url.indexOf("?");
if (-1 != index) {
url = url.substring(0, index);
}
int slashIndex = url.indexOf("/", 8);
String baseURL = url.substring(0, slashIndex).toLowerCase();
int colonIndex = baseURL.indexOf(":", 8);
if (-1 != colonIndex) {
if (baseURL.startsWith("http://") && baseURL.endsWith(":80")) {
baseURL = baseURL.substring(0, colonIndex);
} else if (baseURL.startsWith("https://") && baseURL.endsWith(":443")) {
baseURL = baseURL.substring(0, colonIndex);
}
}
url = baseURL + url.substring(slashIndex);
return url;
}
}