Realex是海外常用的支付处理网关,在集成其支付接口时,SHA1哈希签名是请求校验的核心环节,一旦哈希计算出错,网关会直接返回校验失败的错误响应,导致支付流程无法推进。

Realex SHA1哈希的计算规则
Realex要求的SHA1哈希生成有固定的参数拼接逻辑,开发者需要严格按照官方规范处理,核心步骤如下:
- 确定参与签名的参数集合,通常包括商户ID、订单ID、金额、货币类型、时间戳等必填字段
- 按照指定的固定顺序拼接所有参数,每个参数之间用点号分隔
- 在拼接完成的字符串末尾追加商户私钥,同样用点号分隔
- 对最终拼接得到的字符串进行UTF-8编码处理,再执行SHA1哈希计算
- 将哈希结果转换为小写十六进制字符串,作为最终的签名值
常见SHA1哈希计算错误场景
1. 参数拼接顺序错误
Realex对签名参数的顺序有严格要求,不同接口的参数顺序可能存在差异,如果开发者自行调整了参数顺序,就会导致拼接后的字符串和网关预期的不一致,最终哈希值错误。
2. 字符编码不一致
如果拼接字符串时没有统一使用UTF-8编码,或者某些特殊字符的编码方式不符合规范,哈希计算的结果就会出现偏差,尤其是订单描述中包含中文、 emoji等字符时更容易出现这类问题。
3. 密钥格式错误
商户私钥如果包含多余的空格、换行符,或者没有正确从商户后台复制完整,就会导致拼接后的字符串末尾的密钥不正确,生成的哈希自然无法通过校验。
4. 哈希算法实现偏差
部分开发者自定义的SHA1实现逻辑不符合标准,或者没有正确处理哈希结果的十六进制转换,比如没有转小写、转换时丢失字符等,也会导致签名错误。
错误排查与解决方案
排查步骤
- 首先核对官方文档中对应接口的参数顺序,确认自己拼接的参数顺序完全一致
- 打印出拼接完成、添加密钥之前的原始字符串,和网关侧接收的原始字符串做对比,确认参数内容、分隔符完全一致
- 检查商户私钥是否完整,是否包含多余的空格或换行符,建议直接复制商户后台的密钥,不要手动输入
- 使用标准的SHA1工具类生成哈希,对比自己实现的哈希结果是否一致
代码示例(Java实现)
以下是符合Realex规范的SHA1哈希计算的Java实现示例:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;
public class RealexSha1Util {
/**
* 生成Realex要求的SHA1签名
* @param params 参与签名的参数数组,需要按照官方要求的顺序传入
* @param secret 商户私钥
* @return 小写十六进制SHA1哈希字符串
*/
public static String generateSha1Sign(String[] params, String secret) {
// 拼接参数,用点号分隔
StringBuilder sb = new StringBuilder();
for (int i = 0; i < params.length; i++) {
if (i > 0) {
sb.append(".");
}
sb.append(params[i]);
}
// 追加商户私钥
sb.append(".").append(secret);
String signStr = sb.toString();
System.out.println("待哈希的原始字符串:" + signStr);
try {
// 使用UTF-8编码
byte[] bytes = signStr.getBytes(StandardCharsets.UTF_8);
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(bytes);
// 转换为小写十六进制字符串
StringBuilder hexStr = new StringBuilder();
for (byte b : digest) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexStr.append("0");
}
hexStr.append(hex);
}
return hexStr.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("SHA1算法不存在", e);
}
}
public static void main(String[] args) {
// 示例参数,实际使用时需要替换为接口要求的真实参数和顺序
String[] params = new String[]{"merchantId", "orderId", "100", "EUR", "20240520"};
String secret = "your_merchant_secret";
String sign = generateSha1Sign(params, secret);
System.out.println("生成的SHA1签名:" + sign);
}
}Python实现示例
如果使用Python语言集成,可参考以下实现:
import hashlib
def generate_realex_sha1(params, secret):
"""
生成Realex要求的SHA1签名
:param params: 参与签名的参数列表,按官方要求顺序传入
:param secret: 商户私钥
:return: 小写十六进制SHA1哈希字符串
"""
# 拼接参数,用点号分隔
sign_str = ".".join(params) + "." + secret
print("待哈希的原始字符串:", sign_str)
# UTF-8编码后计算SHA1
sha1 = hashlib.sha1(sign_str.encode("utf-8")).hexdigest()
return sha1
if __name__ == "__main__":
# 示例参数,实际使用时替换为真实参数
params = ["merchantId", "orderId", "100", "EUR", "20240520"]
secret = "your_merchant_secret"
sign = generate_realex_sha1(params, secret)
print("生成的SHA1签名:", sign)注意事项
在调试过程中,建议先使用官方提供的签名校验工具验证自己的拼接字符串和哈希结果是否正确,避免反复提交请求浪费调试时间。如果对接的是Realex的不同接口,一定要确认对应接口的参数顺序和参与签名的字段列表,不要默认所有接口的签名规则完全一致。另外,生产环境和测试环境的商户私钥是不同的,切换环境时不要忘记替换对应的密钥,这也是常见的错误原因之一。