该帖子主要目标是:想开发自己SDK的研发人员
支付宝请求流程
- 首先根据支付宝的要求,生成签名,组装参数
- 然后向支付宝发起支付
- 支付宝会根据你组装好的参数验证签名
- 签名验证成功,则开始验证参数
- 验证成功,支付宝会返回成功的响应结果,code 为 10000
- 响应后,拿到一个支付宝的签名,需要你在本地验签
- 若验签成功,流程结束
支付宝提供了各个语言的SDK,用户可以自行下载,或如果你考虑自己开发SDK,下面我遇到的坑给大家分享一下:
密钥和签名类型是否匹配
支付宝分为两种密钥类型,RSA和RSA2,RSA 是 SHA1 算法 ,RSA2 是 SHA256算法,一旦两者弄混了,自然验签会不通过。
支付宝的密钥是JAVA算法生成的
我用的是C#语言,两者RSA算法是不一样的,我没试过其他语言。在C#中不能直接使用RSAServiceProvider 类型来生成签名,因为算法不同。在最底部我会贴一段代码,可以CV走使用。该代码是在支付宝提供的源码里,非自己原创。
发送请求之前要转码
我忘了是在哪里看到这个要求的了,反正没在支付宝文档里看到。要把所有的参数根据charset参数进行url的转码操作(encode),否则总说你参数无效。
本地验签
其实这一步你可以考虑不做,因为你已经拿到结果了(无论成功还是失败),为了安全起见当然还是做一下比较好。支付宝的响应是一个动态对象,名称格式大致为:xxxxxxx_response
,这个对象虽然是json的,但在验签前,一定要清楚所有的空格和换行符(\r\n),保留成一行的字符串,不然总提示我验签失败。
证书类型
JAVA用的好像是pk8类型的,提示上说的C#用pk12就可以,但是然并卵。
好像就这些了吧?
这是那段代码,我太菜,太底层的读不懂
static class AlipayRsaServiceHelper
{
#region Methods
/// <summary>
/// 获取指定签名类型对应的RSA加密算法类型。
/// </summary>
/// <param name="signType">签名类型。</param>
/// <returns>算法类型的字符串。</returns>
public static string GetHashlgType(string signType)
{
switch (signType.ToUpper())
{
case "RSA":return "SHA1";
case "RSA2":return "SHA256";
default:throw new ArgumentOutOfRangeException("仅支持 RSA/RSA2 两种类型");
}
}
/// <summary>
/// 加载 DER 类型的公钥。
/// </summary>
/// <param name="provider"><see cref="RSACryptoServiceProvider"/> 实例。</param>
/// <param name="DERData">一个符合 DER 格式的二进制数据。</param>
public static void LoadPublicKeyDER(RSACryptoServiceProvider provider, byte[] DERData)
{
byte[] RSAData = GetRSAFromDER(DERData);
byte[] publicKeyBlob = GetPublicKeyBlobFromRSA(RSAData);
provider.ImportCspBlob(publicKeyBlob);
}
/// <summary>
/// 加载指定 PEM 格式的公钥。
/// </summary>
/// <param name="provider"><see cref="RSACryptoServiceProvider"/> 实例。</param>
/// <param name="pem">一个符合 DER 格式的二进制数据。</param>
public static void LoadPublicKeyPEM(RSACryptoServiceProvider provider, string pem)
{
byte[] DERData = GetDERFromPEM(pem);
LoadPublicKeyDER(provider, DERData);
}
/// <summary>
/// 获取指定RSA数据的公钥二进制数据。
/// </summary>
public static byte[] GetPublicKeyBlobFromRSA(byte[] RSAData)
{
byte[] data = null;
UInt32 dwCertPublicKeyBlobSize = 0;
if (CryptDecodeObject(CRYPT_ENCODING_FLAGS.X509_ASN_ENCODING | CRYPT_ENCODING_FLAGS.PKCS_7_ASN_ENCODING,
new IntPtr((int)CRYPT_OUTPUT_TYPES.RSA_CSP_PUBLICKEYBLOB), RSAData, (UInt32)RSAData.Length, CRYPT_DECODE_FLAGS.NONE,
data, ref