摘要签名认证(AppKey & AppSecret)
获取授权密钥
WARNING
请勿把AppKey和AppSecret存到前端本地,导致数据被抓包、资源被盗用
公共参数
对接口签名时,公共参数需要统一放到请求头部Header中, 如下
参数名称 | 类型 | 必选 | 描述 |
---|---|---|---|
X-CS-Authorization | String | 是 | 签名校验方式,目前只支持HMAC-SHA256 |
X-CS-Key | String | 是 | 授权应用AppKey |
X-CS-Nonce | String | 是 | 自行生成的随机唯一UUID,36个字符以内 |
X-CS-Timestamp | String | 是 | 当前UNIX时间戳(10位),精确到秒,注意:如果和服务器时间相差超过10分钟,签名失败 |
X-CS-Version | String | 是 | 当前接口版本号 |
拼接签名字符串
1、 对公共参数名按字母升序排序, 得到:
- X-CS-Authorization: "HMAC-SHA256"
- X-CS-Key: "5673AEFC6D24351826B5"
- X-CS-Nonce: "080537a0-8266-4053-a82c-404b7909afeb"
- X-CS-Timestamp: "1559831475"
- X-CS-Version: "v2"
将上一步排序好的请求参数格式化成“参数名”=“参数值”的形式,然后将格式化后的各个参数用|
拼接在一起,注意:末尾不需要|
。
2、 在字符串前面加上接口【大写】Method和分隔符,得到如下字符串
POST|X-CS-Authorization=HMAC-SHA256|X-CS-Key=5673AEFC6D24351826B5|X-CS-Nonce=080537a0-8266-4053-a82c-404b7909afeb|X-CS-Timestamp=1559831475|X-CS-Version=v2
计算签名
通过HMAC-SHA256
,用应用密钥AppSecrect对上一步拼接的字符串进行计算,返回格式为Base64
crypto
.createHmac("sha256", appSecret)
.update('signString')
.digest("base64");
得到ABNBrbrj2awewbTzDeZvsPJKiXv5ftYXaCIBbQPFhqM=
使用签名
将计算的签名结果放到请求的 Header 中,Key为:X-CS-Signature
POST /v2/invoice/query HTTP/1.1
Host: open.cs.zbj.com
Content-Type: application/json;charset=utf-8
X-CS-Authorization: HMAC-SHA256
X-CS-Key: 5673AEFC6D24351826B5
X-CS-Nonce: 080537a0-8266-4053-a82c-404b7909afeb
X-CS-Timestamp: 1559831475
X-CS-Version: v2
X-CS-Signature: ABNBrbrj2awewbTzDeZvsPJKiXv5ftYXaCIBbQPFhqM=
// Payload data
{"key1":"val1","key2":"val2"}
示例代码
提供了部分语言的示例实现,其他语言可以根据以上流程自行实现
Java
package com.zbj.cs;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import com.google.gson.Gson;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
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.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
/**
* Hello csopen
*
*/
public class App {
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException {
try {
final String host = "https://open.cs.zbj.com";
String appKey = "应用中心申请";
String appSecret = "应用中心申请";
String method = "post";
String path = "/v2/invoice/query";
String url = host + path;
HashMap<String,String> payload = new HashMap<String,String>();
payload.put("fpdm", "051001900111");
payload.put("fphm", "51096586");
payload.put("kprq", "20190608");
payload.put("checkCode", "769875");
payload.put("noTaxAmount", "110.72");
doRequest(appKey, appSecret, method, url, payload);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void doRequest(String appKey, String appSecret, String method, String url, HashMap<String,String> payload)
throws Exception {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("Content-Type", "application/json;charset=UTF-8");
List<NameValuePair> params = getParams(appKey);
final String splitor = "|";
StringBuilder builder = new StringBuilder(method.toUpperCase() + splitor);
for (int i = 0; i < params.size(); i++) {
NameValuePair pair = params.get(i);
String key = pair.getName();
String value = pair.getValue();
httpPost.addHeader(key, value);
builder.append(key + "=" + value + splitor);
}
String signString = builder.substring(0, builder.length() - 1);
System.out.println(signString);
String signature = getSignature(appSecret, signString);
System.out.println(signature);
httpPost.addHeader("X-CS-Signature", signature);
String json = new Gson().toJson(payload);
httpPost.setEntity(new StringEntity(json, "UTF-8"));
CloseableHttpResponse response = httpclient.execute(httpPost);
HttpEntity entity = response.getEntity();
System.out.println("------------------response------------------");
System.out.println(EntityUtils.toString(entity));
}
/**
* 获取公共参数
*
* @param appKey 授权应用的appKey
* @return 签名字符串
*/
private static List<NameValuePair> getParams(String appKey) {
if (appKey == null) {
throw new NullPointerException();
}
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("X-CS-Authorization", "HMAC-SHA256"));
params.add(new BasicNameValuePair("X-CS-Key", appKey));
params.add(new BasicNameValuePair("X-CS-Nonce", UUID.randomUUID().toString()));
params.add(new BasicNameValuePair("X-CS-Timestamp", "" + System.currentTimeMillis() / 1000L));
params.add(new BasicNameValuePair("X-CS-Version", "v2"));
return params;
}
/**
* 获取签名字符串 跟据公共参数的集合,按名称升序排列后用‘|’拼接
*
* @param appKey 授权应用的appKey
* @param 请求的Http方法
* @return 签名字符串
*/
public static String getSignature(final String key, final String data)
throws NoSuchAlgorithmException, InvalidKeyException {
if (key == null || data == null) {
throw new NullPointerException();
}
final String HMAC_SHA256 = "HmacSHA256";
final Mac hMacSHA256 = Mac.getInstance(HMAC_SHA256);
byte[] hmacKeyBytes = key.getBytes(StandardCharsets.UTF_8);
final SecretKeySpec secretKey = new SecretKeySpec(hmacKeyBytes, HMAC_SHA256);
hMacSHA256.init(secretKey);
byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
byte[] res = hMacSHA256.doFinal(dataBytes);
return Base64.getEncoder().encodeToString(res);
}
}
PHP
<?php
function guid(){
if (function_exists('com_create_guid')){
return com_create_guid();
}else{
mt_srand((double)microtime()*10000);
$charid = strtoupper(md5(uniqid(rand(), true)));
$hyphen = chr(45);
$uuid = substr($charid, 0, 8).$hyphen
.substr($charid, 8, 4).$hyphen
.substr($charid,12, 4).$hyphen
.substr($charid,16, 4).$hyphen
.substr($charid,20,12);
return $uuid;
}
}
function getSignaure($secret, $message) {
$s = hash_hmac('sha256', $message, $secret, true);
return base64_encode($s);
}
function getParams($appKey) {
$params = array(
"X-CS-Authorization" => "HMAC-SHA256",
"X-CS-Key" => $appKey,
"X-CS-Nonce" => guid(),
"X-CS-Timestamp" => time(),
"X-CS-Version" => "v2"
);
return $params;
}
function doRequest($appKey, $appSecret, $url, $method, $payload) {
$curl = curl_init();
$headers = array(
"content-type:application/json;charset=UTF-8"
);
$splitor = '|';
$builder = strtoupper($method).$splitor;
$params = getParams($appKey);
foreach ($params as $key => $value) {
array_push($headers, $key.":".$value);
$builder.=$key.'='.$value.$splitor;
}
$signString = substr($builder, 0 , strlen($builder) - 1);
echo $signString."\n";
$signature = getSignaure($appSecret, $signString);
echo $signature."\n";
array_push($headers, "X-CS-Signature:".$signature);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($curl, CURLOPT_TIMEOUT, 30);
$resp = curl_exec($curl);
curl_close($curl);
echo $resp;
}
try {
$baseUri = "https://open.cs.zbj.com";
$appKey = "应用中心申请";
$appSecret = "应用中心申请";
$method = "post";
// 基础查询
$path = "/v2/invoice/query";
$url = $baseUri.$path;
$payload = array(
"fpdm" => "051001900111",
"fphm" => "51096586",
"kprq" => "20190608",
"checkCode" => "769875",
"noTaxAmount" => "110.72"
);
$payloadJson = json_encode($payload);
// echo $payloadJson;
doRequest($appKey, $appSecret, $url, $method, $payloadJson);
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
Node.js
const crypto = require("crypto");
const uuid = require('uuid/v4');
const axios = require('axios');
const url = "https://open.cs.zbj.com/v2/invoice/query";
const AppKey = "应用中心申请";
const AppSecret = "应用中心申请";
const headers = {
"X-CS-Authorization": "HMAC-SHA256",
"X-CS-Key": AppKey,
"X-CS-Nonce": uuid(),
"X-CS-Timestamp": Math.ceil(Date.now() / 1000),
"X-CS-Version": "v2"
}
const signStr = "POST|" + Object.entries(headers).map(([key, val]) => `${key}=${val}`).join("|");
const signature = crypto.createHmac("sha256", AppSecret).update(signStr).digest("base64")
axios.post(url, {
kprq: "20190608",
fpdm: "051001900111",
fphm: "51096586",
checkCode: "769875"
}, {
headers: {...headers, 'X-CS-Signature': signature}
}).then(data => {
console.log(data)
}).catch(e => {
console.error(e)
})
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json;
namespace csopen_csharp
{
internal class Program
{
private static void Main(string[] args)
{
try
{
const string host = "https://open.cs.zbj.com";
const string appKey = "应用中心申请";
const string appSecret = "应用中心申请";
const string method = "post";
const string path = "/v2/invoice/query";
const string url = host + path;
var payload = new
{
fpdm= "051001900111",
fphm = "51096586",
kprq = "20190608",
checkCode= "769875",
noTaxAmount= "110.72"
};
DoRequest(appKey, appSecret, method, url, payload);
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
}
Console.ReadKey(true);
}
private static async void DoRequest(string appKey, string appSecret, string method, string url,
Object payload)
{
using (var client = new HttpClient())
{
HttpContent content = new StringContent(JsonConvert.SerializeObject(payload));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var parameters = BuildBasicParams(appKey);
const string splitor = "|";
var builder = new StringBuilder(method.ToUpper() + splitor);
foreach (var parameter in parameters)
{
content.Headers.Add(parameter.Key, parameter.Value);
builder.AppendFormat("{0}={1}{2}", parameter.Key, parameter.Value, splitor);
}
var signString = builder.ToString(0, builder.Length - 1);
Console.WriteLine(signString);
var signature = GetSignature(appSecret, signString);
Console.WriteLine(signature);
content.Headers.Add("X-CS-Signature", signature);
var response = await client.PostAsync(url, content);
var responseText = await response.Content.ReadAsStringAsync();
Console.WriteLine("------------------response------------------");
Console.WriteLine(responseText);
}
}
private static IList<KeyValuePair<string, string>> BuildBasicParams(string appKey)
{
if (string.IsNullOrEmpty(appKey))
{
throw new ArgumentNullException(nameof(appKey));
}
IList<KeyValuePair<string, string>> parameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("X-CS-Authorization", "HMAC-SHA256"),
new KeyValuePair<string, string>("X-CS-Key", appKey),
new KeyValuePair<string, string>("X-CS-Nonce", Guid.NewGuid().ToString()),
new KeyValuePair<string, string>("X-CS-Timestamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString()),
new KeyValuePair<string, string>("X-CS-Version", "v2")
};
parameters.OrderBy(x => x.Key);
return parameters;
}
private static string GetSignature(string key, string data)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentNullException(nameof(key));
}
if (string.IsNullOrEmpty(data))
{
throw new ArgumentNullException(nameof(data));
}
var encoding = new ASCIIEncoding();
var hash = new HMACSHA256(encoding.GetBytes(key));
var hashMessage = hash.ComputeHash(encoding.GetBytes(data));
return Convert.ToBase64String(hashMessage);
}
}
}
Python
#!/usr/bin/python3
import time
import uuid
import hmac
import base64
import hashlib
from urllib import request, parse, error
AppKey = "应用中心申请"
AppSecret = "应用中心申请"
url = "https://open.cs.zbj.com/v2/invoice/query"
headers = {
"X-CS-Authorization": "HMAC-SHA256",
"X-CS-Key": AppKey,
"X-CS-Nonce": str(uuid.uuid4()),
"X-CS-Timestamp": str(int(time.time())),
"X-CS-Version": "v2"
}
signList = ['POST']
for key,val in headers.items():
signList.append(key + '=' + val)
signStr = '|'.join(signList)
signature = base64.b64encode(hmac.new(bytes(AppSecret, 'utf-8'), bytes(signStr, 'utf-8'), hashlib.sha256).digest())
headers['X-CS-Signature'] = str(signature, 'utf-8')
parms = {
"kprq": "20190608",
"fpdm": "051001900111",
"fphm": "51096586",
"checkCode": "769875"
}
req = request.Request(url, parse.urlencode(parms).encode(encoding='utf8'), headers)
try:
res = request.urlopen(req)
resText = res.read()
print(resText.decode())
except error.HTTPError as err:
error_message = err.read()
print (error_message.decode())