今天做支付寶接口回調這塊,不得不說,弄的我焦頭爛額,翻了很多陳年舊帖,試了無數種解決坑的方案,在我成功解決的一瞬間,覺得非常有必要記錄一下這些坑。
簽名驗證錯誤的檢查順序(這里是基於使用官方給的demo,自己封裝的請繞道):
1:檢查一下你使用的驗證簽名的方法是否正確?
bool signVerified = AlipaySignature.RSACheckV1(dic, alipay_public_key, config.charset);
2:檢查一下你傳入的參數是否正確?
參數1:dic,把回調的參數保存到key,value集合中
Dictionary<string, string> dic = new Dictionary<string, string>(); var form = HttpContext.Current.Request.Form; string str = "異步通知:\r\n"; foreach (var key in form) { dic[key.ToString()] = HttpContext.Current.Request.Form[key.ToString()]; var value = HttpContext.Current.Request.Form[key.ToString()]; //記錄日志使用 str += $"{key.ToString()}:{value}\r\n"; }
參數2:alipay_public_key
這個參數是 支付寶公鑰!! 很多小伙伴都寫成了應用公鑰,瞎幾把寫。
參數3:編碼格式,UTF-8,這個一般沒人會錯。
3:檢查一下你的環境,沙盒環境還是線上環境,沙盒環境會出錯,具體為什么我不知道,百度來的。要在支付寶中給你的回調域名授權,不授權人家懶得回調給你。
4:檢查一下你的加密解密類型,我從官網下載下來的demo里面的解密類型默認是RSA,但是官方文檔已經明確說明現在都要用RSA2了,所以記得檢查demo的源碼
public static bool RSACheckV1(IDictionary<string, string> parameters, string publicKeyPem, string charset) { string sign = parameters["sign"]; string sign_type = parameters["sign_type"]; parameters.Remove("sign"); parameters.Remove("sign_type"); string signContent = GetSignContent(parameters); return RSACheckContent(signContent, sign, publicKeyPem, charset, sign_type); }
sign_type,這個就是解碼類型,demo寫的好像“RSA”,我這里改成動態獲取了,我們在前期配置的地方也會配置加密類型,從哪獲取都可以,別弄錯了就行。
5:這里不檢查了,回憶一下你的支付寶公鑰,是直接存在文本中的,還是寫在代碼里的(區別:公鑰.txt,string 公鑰 = “巴拉巴拉巴拉一大堆”),一個是文件,一個是直接代碼(我就是代碼,所以我一直到最后才解決)(下面的解決方案只針對代碼保存支付寶公鑰的騷年)
string alipay_public_key = "-----BEGIN PUBLIC KEY-----\r\n" + config.alipay_public_key + "-----END PUBLIC KEY-----\r\n\r\n"; bool signVerified = AlipaySignature.RSACheckV1(dic, alipay_public_key, config.charset);
如果是直接寫在代碼中的,要給支付寶公鑰的頭跟尾加上標識,具體標識看我貼出來的代碼,如果是文件,請自動忽略
還沒結束,官方給的demo也是默認找的文件,可是我用的代碼存的,哪有文件,所以找不到文件是會報錯的,報錯直接返回false了,在修改一下源碼(自己到AlipaySignature這個類里面去找)
public static bool RSACheckContent(string signContent, string sign, string publicKeyPem, string charset, string signType) { try { if (string.IsNullOrEmpty(charset)) { charset = DEFAULT_CHARSET; } if ("RSA2".Equals(signType)) { //這里就是要改的地方 //從參數獲取 string sPublicKeyPEM = publicKeyPem; //從文件獲取 //string sPublicKeyPEM = File.ReadAllText(publicKeyPem); RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.PersistKeyInCsp = false; RSACryptoServiceProviderExtension.LoadPublicKeyPEM(rsa, sPublicKeyPEM); bool bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent), "SHA256", Convert.FromBase64String(sign)); return bVerifyResultOriginal; } else { //這里就是要改的地方 //從參數獲取 string sPublicKeyPEM = publicKeyPem; //從文件獲取 //string sPublicKeyPEM = File.ReadAllText(publicKeyPem); RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.PersistKeyInCsp = false; RSACryptoServiceProviderExtension.LoadPublicKeyPEM(rsa, sPublicKeyPEM); SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); bool bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent), sha1, Convert.FromBase64String(sign)); return bVerifyResultOriginal; } } catch (Exception e) { NLogGetter.NLog.ErrorLog(e); return false; } }
好了,差不多就總結了這么多,基本上可以讓你簽名驗證成功了。
