import base64
import hmac
import json
import requests
from datetime import datetime
from typing import Dict, Any, List, Union, Type
# 签名
class SignatureUtility:
def generate_signature(self, secret_key: str, message: str) -> str:
"""Generate the HMAC SHA256 signature for a given message."""
signature = hmac.new(
secret_key.encode(), message.encode(), digestmod="sha256"
).digest()
return base64.b64encode(signature).decode()
def verify_signature(
self, secret_key: str, message: str, received_signature: str
) -> bool:
"""Verify the received signature against the computed one."""
computed_signature = self.generate_signature(secret_key, message)
return hmac.compare_digest(computed_signature, received_signature)
def clean_and_sort_dict(
self, data: Union[Dict[Any, Union[Dict, Any]], List[Union[Dict, Any]]]
) -> Union[Dict[Any, Union[Dict, Any]], List[Union[Dict, Any]]]:
if isinstance(data, dict):
sorted_dict = {}
for key, value in sorted(data.items()):
if isinstance(value, (dict, list)):
value = self.clean_and_sort_dict(value)
# Checking for non-empty values, including non-empty lists and non-empty dictionaries
if value or value == 0:
sorted_dict[key] = value
return (
sorted_dict if sorted_dict else None
) # Return None if the dictionary is empty
elif isinstance(data, list):
int_list = sorted([item for item in data if isinstance(item, int)])
float_list = sorted([item for item in data if isinstance(item, float)])
str_list = sorted([item for item in data if isinstance(item, str)])
complex_data_types = [
item for item in data if isinstance(item, (dict, list))
]
sorted_complex_data = [
self.clean_and_sort_dict(item) for item in complex_data_types
]
sorted_complex_data = [
item for item in sorted_complex_data if item
] # Filter out None values
result = int_list + float_list + str_list + sorted_complex_data
return result if result else None # Return None if the list is empty
#
def post_request(URL: str, body: Type):
sign_utility = SignatureUtility()
query_string = ""
method = "POST"
#
# 请求签名
body_str = ""
timestamp = str(int(datetime.utcnow().timestamp() * 1000))
req_cleaned_body = sign_utility.clean_and_sort_dict(body)
if req_cleaned_body is not None:
body_str = json.dumps(
req_cleaned_body,
sort_keys=True,
separators=(",", ":"),
ensure_ascii=False,
)
message = f"{timestamp}{method}{URL}{query_string}{body_str}"
print(message)
sign = sign_utility.generate_signature(secret_key=SECRET_KEY, message=message)
print(sign)
# POST REQUEST
headers = {
"ach-access-key": API_KEY,
"ach-access-sign": sign,
"ach-access-timestamp": timestamp,
}
response = requests.post(url=HOST + URL, headers=headers, json=body)
return response.text
API_KEY = "service000-local-apikey"
SECRET_KEY = "service000-local-secretkey"
HOST = "http://127.0.0.1:8072"
#
if __name__ == "__main__":
url = "/open/api/card/create"
body = {
"callbackUrl": "http://baidu.com",
"cardHolder": {
"address": {
"city": "string",
"country": "string",
"state": "string",
"street": "string",
"zipCode": "string"
},
"firstName": "string",
"lastName": "string"
},
"customerId": "user_id_123",
"deposit": "100",
"orderNo": "12165456165441",
"tagNameList": [
"string"
],
"vid": "vab_069af8a792ad"
}
response = post_request(url, body)
print(f"response: {response}")
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections4.list.TreeList;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
public class AchVccSignUtils {
public static String apiSign(String timestamp, String method, String requestUrl, String body, String secretkey) throws NoSuchAlgorithmException, InvalidKeyException {
String signVal = "";
if("POST".equalsIgnoreCase(method)) {
String content = timestamp + method.toUpperCase() + getPath(requestUrl) + getJsonBody(body);
System.out.println("POST signString:" + content);
Base64.Encoder base = Base64.getEncoder();
signVal = base.encodeToString(sha256(content.getBytes(StandardCharsets.UTF_8), secretkey.getBytes(StandardCharsets.UTF_8)));
}else {
String content = "";
if(!StringUtils.isEmpty(body) && !"null".equalsIgnoreCase(body) && !"{}".equals(body)) {
content = timestamp + method.toUpperCase() + getPath(requestUrl) + orderGetSignStr((Map) JSONObject.parseObject(body));
}else {
content = timestamp + method.toUpperCase() + getPath(requestUrl);
}
System.out.println("GET signString:" + content);
Base64.Encoder base = Base64.getEncoder();
signVal = base.encodeToString(sha256(content.getBytes(StandardCharsets.UTF_8), secretkey.getBytes(StandardCharsets.UTF_8)));
}
return signVal;
}
public static byte[] sha256(byte[] message, byte[] secret) throws NoSuchAlgorithmException, InvalidKeyException {
Mac sha256_HMAC = Mac.getInstance("HmacSha256");
SecretKeySpec secretKey = new SecretKeySpec(secret, "HmacSha256");
sha256_HMAC.init(secretKey);
return sha256_HMAC.doFinal(message);
}
private static String getPath(String requestUrl) {
String path = getURI(requestUrl).getPath();
Map map = parsePath(requestUrl);
map = removeEmptyKeys(map);
if (map.isEmpty()) {
return path;
}
map = (Map) sortObject(map);
if (map.isEmpty()) {
return path;
} else {
StringBuffer httpUlr = new StringBuffer();
StringBuffer sb = new StringBuffer("?");
Iterator<Map.Entry> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Object> entry = iterator.next();
sb.append(entry.getKey() + "=" + entry.getValue() + "&");
}
return httpUlr.append(path).append(sb.substring(0, sb.length() - 1)).toString();
}
}
private static String getJsonBody(String body) {
Map map = null;
if (isJson(body)) {
map = JSONObject.parseObject(body, Map.class);
} else {
map = new HashMap();
}
if (map == null || map.isEmpty()) {
return "";
}
map = removeEmptyKeys(map);
map = (Map) sortObject(map);
return JSON.toJSONString(map);
}
private static URI getURI(String requestUrl) {
URL url = null;
URI uri = null;
try {
url = new URL(requestUrl);
uri = url.toURI();
} catch (Exception e) {
throw new RuntimeException(e);
}
return uri;
}
private static String orderGetSignStr(Map<String, String> params) {
String signStr = "?";
if (params != null) {
params = removeEmptyKeys(params);
params = (Map) sortObject(params);
for(String k:params.keySet()){
signStr += k+"="+params.get(k)+"&";
}
}
return signStr.substring(0,signStr.length()-1);
}
private static Map<String, String> parsePath(String requestUrl) {
URI uri = getURI(requestUrl);
String path = uri.getPath();
// 获取请求参数
String query = uri.getQuery();
if (query != null) {
Map<String, String> params = new HashMap<>();
String[] keyValuePairs = query.split("&");
for (String pair : keyValuePairs) {
String[] keyValuePair = pair.split("=");
String key = keyValuePair[0];
String value = keyValuePair.length > 1 ? keyValuePair[1] : null;
params.put(key, value);
}
System.out.println("Parameters: " + params);
return params;
} else {
System.out.println("No parameters found.");
return new HashMap<>();
}
}
private static boolean isJson(String jsonString) {
if (jsonString == null || jsonString.equals("")) {
return false;
}
try {
JSON.parse(jsonString);
return true;
} catch (JSONException e) {
return false;
}
}
private static Map removeEmptyKeys(Map map) {
if (map.isEmpty()) {
return map;
}
Map retMap = new HashMap();
Iterator<Map.Entry> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Object> entry = iterator.next();
if (entry.getValue() != null && !entry.getValue().equals("")) {
retMap.put(entry.getKey(), entry.getValue());
}
}
return retMap;
}
private static Object sortObject(Object obj) {
if (obj instanceof Map) {
return sortMap((Map) obj);
} else if (obj instanceof List) {
sortList((List) obj);
return obj;
}
return null;
}
private static Map sortMap(Map map) {
if (map.isEmpty()) {
return null;
}
SortedMap<String, Object> sortedMap = new TreeMap<>(removeEmptyKeys(map));
for (String sortKey : sortedMap.keySet()) {
if (sortedMap.get(sortKey) instanceof Map) {
sortedMap.put(sortKey, sortMap((Map) sortedMap.get(sortKey)));
} else if (sortedMap.get(sortKey) instanceof List) {
sortedMap.put(sortKey, sortList((List) sortedMap.get(sortKey)));
}
}
return sortedMap;
}
private static List sortList(List list) {
if (list.isEmpty()) {
return null;
}
List objectList = new ArrayList();
List intList = new ArrayList();
List floatList = new ArrayList();
List stringList = new ArrayList();
List jsonArray = new ArrayList();
for (Object obj : list) {
if (obj instanceof Map || obj instanceof List) {
jsonArray.add(obj);
} else if (obj instanceof Integer) {
intList.add(obj);
} else if (obj instanceof BigDecimal) {
floatList.add(obj);
} else if (obj instanceof String) {
stringList.add(obj);
} else {
intList.add(obj);
}
}
Collections.sort(intList);
Collections.sort(floatList);
Collections.sort(stringList);
objectList.addAll(intList);
objectList.addAll(floatList);
objectList.addAll(stringList);
objectList.addAll(jsonArray);
list.clear();
list.addAll(objectList);
List retList = new TreeList();
for (Object obj : list) {
if (obj instanceof Map) {
retList.add(sortMap((Map) obj));
} else if (obj instanceof List) {
retList.add(sortList((List) obj));
} else {
retList.add(obj);
}
}
return retList;
}
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
String timestamp = String.valueOf(System.currentTimeMillis());
String sign = apiSign(timestamp, "POST", "XXXXXXXX", "JSONbody", "secretKey");
System.out.println("ach-access-sign:"+ sign);
}
}