数字签名是密码学理论中的一个重要分支。它的提出是为了对电子文档进行签名,以 替代传统纸质文档上的手写签名,因此它必须具备 5 个特性。
(1)签名是可信的。
(2)签名是不可伪造的。
(3)签名是不可重用的。
(4)签名的文件是不可改变的。
(1)签名是可信的。
(2)签名是不可伪造的。
(3)签名是不可重用的。
(4)签名的文件是不可改变的。
(5)签名是不可抵赖的。
基于以上原因,我们要求请求我们的API时必须添加签名,以下分别是PHP和Java发送请求的实例:
PHP添加签名是一件so easy的事情,因为它有openssl这一强大的工具,请看示例:
//签名
public static function genSignatureForAPI($params)
{
$requestSignature = NULL;
$privateKey=null;
$rawRequestBody = json_encode($params);//POST请求之前也要对要post的数据做json_encode
$privateKey=Util::getPrivateKey();
if ($privateKey) {
$signResult = openssl_sign($rawRequestBody, $requestSignature, $privateKey, 'sha256');
if (!$signResult) {
throw new \Exception("Generate signature failed");
}
}
return base64_encode($requestSignature);
}
//API post请求示例
function testAPI()
{
$data=array(
"order_no"=> "owFW468460681780",
"app"=> array(
"id"=> "app_WTGWGw4365wgwtwerewE"
),
"metadata"=> array("metadata1"=> "VeryExcellent!"),
);
$headers=array(
'Content-type: application/json;charset=UTF-8',
'Signature: '.Util::genSignatureForAPI($data)
);
$httprequestor=new HttpRequestor();
$response=$httprequestor->curlHttpRequestForAPI($headers,"POST",$BaseUrl."/v1/tests/",$data);
}
而Java的实现就比较麻烦了,请看示例:
/**
* 将map转换为json字符串
* @param <span style="font-family: Arial, Helvetica, sans-serif;">map</span>
* @return
*/
public static String createJSONString(Map<String, Object> map) {
Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create();
return gson.toJson(map);
}
/**
* 生成请求签名
* @param privateKeyPath
* @param jsonStr
* @return
* @throws IOException
*/
public static String genSignatureForAPI(String privateKeyPath, String jsonStr) throws IOException {
String keyString="";
if (privateKeyPath == null) {
return null;
}else
{
FileInputStream inputStream = new FileInputStream(privateKeyPath);
byte[] keyBytes = new byte[inputStream.available()];
inputStream.read(keyBytes);
inputStream.close();
keyString = new String(keyBytes, CHARSET);
}
String trimmedPrivateKey = keyString
.replaceAll("(-+BEGIN (RSA )?PRIVATE KEY-+\\r?\\n|-+END (RSA )?PRIVATE KEY-+\\r?\\n?)", "");
byte[] privateKeyBytes = Base64.decodeBase64(trimmedPrivateKey);
DerInputStream derReader = new DerInputStream(privateKeyBytes);
DerValue[] seq = derReader.getSequence(0);
if (seq.length < 9) {
System.out.println("Could not parse a PKCS1 private key.");
return null;
}
// skip version seq[0];
BigInteger modulus = seq[1].getBigInteger();
BigInteger publicExp = seq[2].getBigInteger();
BigInteger privateExp = seq[3].getBigInteger();
BigInteger prime1 = seq[4].getBigInteger();
BigInteger prime2 = seq[5].getBigInteger();
BigInteger exp1 = seq[6].getBigInteger();
BigInteger exp2 = seq[7].getBigInteger();
BigInteger crtCoef = seq[8].getBigInteger();
RSAPrivateCrtKeySpec spec = new RSAPrivateCrtKeySpec(modulus, publicExp, privateExp, prime1, prime2, exp1, exp2, crtCoef);
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(spec);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(jsonStr.getBytes(CHARSET));
byte[] signBytes = signature.sign();
return Base64.encodeBase64String(signBytes).replaceAll("\n|\r", "");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (SignatureException e) {
e.printStackTrace();
}
return null;
}
具体每一个方法的含义还请你自行查阅以便于深入了解!!!
/**
* Post请求API示例
* @throws Exception
*/
@Test
public void testAPI() throws Exception {
Map<String, Object> chargeParams =APIJsonMap.createChargeMap(apiparams, category);
String jsonStr=APIUtils.createJSONString(chargeParams);
//添加签名字段
String signature=APIUtils.genSignatureForAPI(apiparams.getPrivateKeyPath(),jsonStr);
if(signature!=null)
{
headers.put("Signature",signature);
}
System.out.println(signature);
final Response res=APIUtils.doPost(headers, jsonStr, "tests/", 200);
BaseCheck.verifyCommonParamsForChargeResult(res, category, apiparams);
}
至于doPost方法,其实我是封装了rest_assured框架的一些方法来完成的,具体还请前往https://github.com/rest-assured/rest-assured学习。