今天作支付寶接口回調這塊,不得不說,弄的我焦頭爛額,翻了不少陳年舊帖,試了無數種解決坑的方案,在我成功解決的一瞬間,以爲很是有必要記錄一下這些坑。異步
簽名驗證錯誤的檢查順序(這裏是基於使用官方給的demo,本身封裝的請繞道):ide
1:檢查一下你使用的驗證簽名的方法是否正確?編碼
bool signVerified = AlipaySignature.RSACheckV1(dic, alipay_public_key, config.charset);
2:檢查一下你傳入的參數是否正確?加密
參數1:dic,把回調的參數保存到key,value集合中spa
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日誌
這個參數是 支付寶公鑰!! 不少小夥伴都寫成了應用公鑰,瞎幾把寫。code
參數3:編碼格式,UTF-8,這個通常沒人會錯。orm
3:檢查一下你的環境,沙盒環境仍是線上環境,沙盒環境會出錯,具體爲何我不知道,百度來的。要在支付寶中給你的回調域名受權,不受權人家懶得回調給你。blog
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; } }
好了,差很少就總結了這麼多,基本上可讓你簽名驗證成功了。