PAYATHON 2026

iOS PayUMoney SDK 提示“key is not valid”

支付阿杰

结论

最可能的问题是环境与凭据不匹配。代码使用了生产环境 PUMEnvironmentProduction,但传入的 key 不是当前生产商户账户的有效 Merchant Key。常见情况包括误用测试 Key、把 Merchant ID 当作 Merchant Key,或生产 Key 尚未启用。

Hash 能够正常计算,只代表 SHA-512 计算过程执行成功,不能证明该 Key 已在 PayUMoney 生产环境中注册并生效。服务端校验商户凭据时,仍可能返回 key is not valid。

排查和解决步骤

1. 确认环境与凭据匹配

当前代码使用生产环境:

self.params.environment = PUMEnvironmentProduction;

因此,以下信息必须来自同一个生产商户账户:

  • Merchant Key
  • Merchant Salt
  • Merchant ID
  • 已启用的生产账户配置

如果使用的是测试凭据,需要切换到 SDK 对应的测试环境。具体枚举名称取决于集成的 SDK 版本。例如,旧版 SDK 可能提供类似 PUMEnvironmentTest 的配置:

self.params.environment = PUMEnvironmentTest;
self.params.key = @"your_test_merchant_key";
self.params.merchantid = @"your_test_merchant_id";

测试 Key 不能用于生产环境,Merchant ID 也不能代替 Merchant Key。

如果 SDK 中没有 PUMEnvironmentTest,请查看当前版本头文件里 PUMEnvironment 的实际定义,不要直接套用其他版本的枚举名称。

2. 确保 Hash 使用同一组 Key 和 Salt

请求参数中的 key 必须与 Hash 字符串开头的 Key 完全一致:

self.params.key = merchantKey;
NSString *hashSequence = [NSString stringWithFormat:
    @"%@|%@|%@|%@|%@|%@|||||||||||%@",
    merchantKey,
    self.params.txnid,
    self.params.amount,
    self.params.productinfo,
    self.params.firstname,
    self.params.email,
    merchantSalt
];

可以用同一个变量传递 Key,避免请求参数和 Hash 使用不同的值:

- (void)setPaymentParameters {
    NSString *merchantKey = @"your_merchant_key";
    NSString *merchantSalt = @"your_merchant_salt";

    self.params = [PUMRequestParams sharedParams];
    self.params.environment = PUMEnvironmentProduction;
    self.params.key = merchantKey;
    self.params.merchantid = @"your_merchant_id";

    // 其他参数……

    self.params.hashValue = [self hashForParams:self.params
                                           key:merchantKey
                                          salt:merchantSalt];
}

3. 不要在客户端保存真实 Salt

示例代码直接在 iOS 应用中使用 Salt:

@"...|salt"

这种做法在生产环境中并不安全。iOS 应用可以被逆向分析,Salt 一旦被提取,攻击者就可能伪造请求 Hash。

生产环境应采用以下流程:

  1. iOS 客户端把订单信息发送到自己的后端。
  2. 后端生成唯一的 txnid。
  3. 后端使用 Merchant Key 和 Salt 计算 Hash。
  4. 后端把 txnid、Hash 和支付参数返回给客户端。
  5. 客户端启动 PayUMoney SDK。

生产 Salt 应只保存在服务端,不能打包进应用。

4. 检查商户账户状态

即使 Key 与环境看起来一致,生产 Key 仍可能因以下原因无法使用:

  • 商户账户尚未完成激活或审核;
  • 生产支付权限尚未开通;
  • Key 属于另一个商户账户;
  • 后台重新生成过凭据,但应用仍在使用旧 Key;
  • Key 前后带有空格、换行或其他复制错误;
  • 下载的旧 SDK 对应另一套 PayU/PayUMoney 接入配置。

请从实际商户后台重新复制生产 Merchant Key、Salt 和 Merchant ID,并确认三者属于同一个账户。不要使用文档中的演示值,也不要用 Merchant ID 代替 Merchant Key。

建议修正 Hash 的生成方式

当前代码通过 NSData 的 description 获取十六进制字符串:

NSString *rawHash = [[self createSHA512:hashSequence] description];

这种写法依赖 NSData 的描述格式,不适合正式编码。应直接把摘要字节转换成小写十六进制字符串:

#import <CommonCrypto/CommonDigest.h>

- (NSString *)sha512:(NSString *)source {
    NSData *data = [source dataUsingEncoding:NSUTF8StringEncoding];

    unsigned char digest[CC_SHA512_DIGEST_LENGTH];
    CC_SHA512(data.bytes, (CC_LONG)data.length, digest);

    NSMutableString *result =
        [NSMutableString stringWithCapacity:CC_SHA512_DIGEST_LENGTH * 2];

    for (NSInteger i = 0; i < CC_SHA512_DIGEST_LENGTH; i++) {
        [result appendFormat:@"%02x", digest[i]];
    }

    return result;
}

然后按照 PayUMoney 接口要求的字段顺序生成 Hash:

- (NSString *)hashForParams:(PUMRequestParams *)params
                        key:(NSString *)key
                       salt:(NSString *)salt {
    NSString *hashSequence = [NSString stringWithFormat:
        @"%@|%@|%@|%@|%@|%@|||||||||||%@",
        key,
        params.txnid,
        params.amount,
        params.productinfo,
        params.firstname,
        params.email,
        salt
    ];

    return [self sha512:hashSequence];
}

Hash 的字段数量、排列顺序和空字段必须严格符合所用 SDK 及接口版本的要求。上面的顺序与问题中的请求结构一致。如果当前商户后台提供了不同的集成文档,应以后台文档为准。

还需要修正的参数

当前 txnid 只有两位数字:

self.params.txnid = [self getRandomString:2];

这样的交易号很容易重复。它通常不会直接引发 key is not valid,但可能导致交易号重复或订单校验失败。建议由服务端生成足够长且唯一的交易号,例如:

self.params.txnid =
    [[[NSUUID UUID] UUIDString] stringByReplacingOccurrencesOfString:@"-"
                                                          withString:@""];

另外,phone 被设置为空字符串:

self.params.phone = @"";

如果当前接口要求手机号必填,空字符串会导致后续参数校验失败。它不是 Key 无效的主要原因,但仍应根据所用 SDK 的要求填写有效值。

推荐的排查顺序

建议按以下顺序检查:

  1. 确认 PUMEnvironmentProduction 使用的是生产 Merchant Key。
  2. 确认 self.params.key 与 Hash 字符串中的 Key 完全相同。
  3. 确认 Salt 与 Key 来自同一个商户账户和同一环境。
  4. 确认 merchantid 与 Merchant Key 没有填反。
  5. 确认生产账户已经激活,凭据也没有被重置。
  6. 核对 Hash 的字段顺序、空字段数量和字符编码是否符合当前接口文档。
  7. 使用长度合理且唯一的 txnid。
  8. 把 Hash 计算迁移到服务端。

所以,遇到这个提示时,应先检查生产环境与 Merchant Key 是否匹配,而不是只看 SHA-512 的计算结果。

备注:内容仅供参考。