初始提交
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Alipay.AopSdk.Core.Util
|
||||
{
|
||||
internal class AlipayEncrypt
|
||||
{
|
||||
/// <summary>
|
||||
/// 128位0向量
|
||||
/// </summary>
|
||||
private static readonly byte[] AES_IV = initIv(16);
|
||||
|
||||
/// <summary>
|
||||
/// AES 加密
|
||||
/// </summary>
|
||||
/// <param name="encryptKey"></param>
|
||||
/// <param name="bizContent"></param>
|
||||
/// <param name="charset"></param>
|
||||
/// <returns></returns>
|
||||
public static string AesEncrypt(string encryptKey, string bizContent, string charset)
|
||||
{
|
||||
var keyArray = Convert.FromBase64String(encryptKey);
|
||||
byte[] toEncryptArray = null;
|
||||
|
||||
if (string.IsNullOrEmpty(charset))
|
||||
toEncryptArray = Encoding.UTF8.GetBytes(bizContent);
|
||||
else
|
||||
toEncryptArray = Encoding.GetEncoding(charset).GetBytes(bizContent);
|
||||
|
||||
var rDel = new RijndaelManaged();
|
||||
rDel.Key = keyArray;
|
||||
rDel.Mode = CipherMode.CBC;
|
||||
rDel.Padding = PaddingMode.PKCS7;
|
||||
rDel.IV = AES_IV;
|
||||
|
||||
var cTransform = rDel.CreateEncryptor(rDel.Key, rDel.IV);
|
||||
var resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
|
||||
|
||||
|
||||
return Convert.ToBase64String(resultArray);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AES解密
|
||||
/// </summary>
|
||||
/// <param name="encryptKey"></param>
|
||||
/// <param name="bizContent"></param>
|
||||
/// <param name="charset"></param>
|
||||
/// <returns></returns>
|
||||
public static string AesDencrypt(string encryptKey, string bizContent, string charset)
|
||||
{
|
||||
var keyArray = Convert.FromBase64String(encryptKey);
|
||||
var toEncryptArray = Convert.FromBase64String(bizContent);
|
||||
|
||||
var rDel = new RijndaelManaged();
|
||||
rDel.Key = keyArray;
|
||||
rDel.Mode = CipherMode.CBC;
|
||||
rDel.Padding = PaddingMode.PKCS7;
|
||||
rDel.IV = AES_IV;
|
||||
|
||||
var cTransform = rDel.CreateDecryptor(rDel.Key, rDel.IV);
|
||||
var resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(charset))
|
||||
return Encoding.UTF8.GetString(resultArray);
|
||||
return Encoding.GetEncoding(charset).GetString(resultArray);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化向量
|
||||
/// </summary>
|
||||
/// <param name="blockSize"></param>
|
||||
/// <returns></returns>
|
||||
private static byte[] initIv(int blockSize)
|
||||
{
|
||||
var iv = new byte[blockSize];
|
||||
for (var i = 0; i < blockSize; i++)
|
||||
iv[i] = 0x0;
|
||||
return iv;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,807 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Alipay.AopSdk.Core.Util
|
||||
{
|
||||
public class AlipaySignature
|
||||
{
|
||||
/** 默认编码字符集 */
|
||||
private static readonly string DEFAULT_CHARSET = "utf-8";
|
||||
|
||||
public static string GetSignContent(IDictionary<string, string> parameters)
|
||||
{
|
||||
// 第一步:把字典按Key的字母顺序排序
|
||||
IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
|
||||
var dem = sortedParams.GetEnumerator();
|
||||
|
||||
// 第二步:把所有参数名和参数值串在一起
|
||||
var query = new StringBuilder("");
|
||||
while (dem.MoveNext())
|
||||
{
|
||||
var key = dem.Current.Key;
|
||||
var value = dem.Current.Value;
|
||||
if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
|
||||
query.Append(key).Append("=").Append(value).Append("&");
|
||||
}
|
||||
var content = query.ToString().Substring(0, query.Length - 1);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
public static string RSASign(IDictionary<string, string> parameters, string privateKeyPem, string charset,
|
||||
string signType)
|
||||
{
|
||||
var signContent = GetSignContent(parameters);
|
||||
|
||||
return RSASignCharSet(signContent, privateKeyPem, charset, signType);
|
||||
}
|
||||
|
||||
public static string RSASign(string data, string privateKeyPem, string charset, string signType)
|
||||
{
|
||||
return RSASignCharSet(data, privateKeyPem, charset, signType);
|
||||
}
|
||||
|
||||
///*
|
||||
public static string RSASign(IDictionary<string, string> parameters, string privateKeyPem, string charset,
|
||||
bool keyFromFile, string signType)
|
||||
{
|
||||
var signContent = GetSignContent(parameters);
|
||||
|
||||
return RSASignCharSet(signContent, privateKeyPem, charset, keyFromFile, signType);
|
||||
}
|
||||
|
||||
public static string RSASign(string data, string privateKeyPem, string charset, string signType, bool keyFromFile)
|
||||
{
|
||||
return RSASignCharSet(data, privateKeyPem, charset, keyFromFile, signType);
|
||||
}
|
||||
|
||||
//*/
|
||||
public static string RSASignCharSet(string data, string privateKeyPem, string charset, string signType)
|
||||
{
|
||||
RSA rsaCsp = LoadCertificateFile(privateKeyPem, signType);
|
||||
byte[] dataBytes = null;
|
||||
if (string.IsNullOrEmpty(charset))
|
||||
dataBytes = Encoding.UTF8.GetBytes(data);
|
||||
else
|
||||
dataBytes = Encoding.GetEncoding(charset).GetBytes(data);
|
||||
|
||||
var signatureBytes = rsaCsp.SignData(dataBytes, "RSA2".Equals(signType) ? HashAlgorithmName.SHA256 : HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
|
||||
|
||||
return Convert.ToBase64String(signatureBytes);
|
||||
}
|
||||
|
||||
|
||||
public static string RSASignCharSet(string data, string privateKeyPem, string charset, bool keyFromFile,
|
||||
string signType)
|
||||
{
|
||||
byte[] signatureBytes = null;
|
||||
try
|
||||
{
|
||||
RSA rsaCsp = null;
|
||||
rsaCsp = keyFromFile ? LoadCertificateFile(privateKeyPem, signType) : LoadCertificateString(privateKeyPem, signType);
|
||||
|
||||
byte[] dataBytes = null;
|
||||
if (string.IsNullOrEmpty(charset))
|
||||
dataBytes = Encoding.UTF8.GetBytes(data);
|
||||
else
|
||||
dataBytes = Encoding.GetEncoding(charset).GetBytes(data);
|
||||
if (null == rsaCsp)
|
||||
throw new AopException("您使用的私钥格式错误,请检查RSA私钥配置" + ",charset = " + charset);
|
||||
signatureBytes = rsaCsp.SignData(dataBytes, "RSA2".Equals(signType) ? HashAlgorithmName.SHA256 : HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new AopException($"您使用的私钥格式错误,请检查RSA私钥配置,charset = {charset},异常信息:{ex.Message}", ex);
|
||||
}
|
||||
return Convert.ToBase64String(signatureBytes);
|
||||
}
|
||||
|
||||
|
||||
public static bool RSACheckV1(IDictionary<string, string> parameters, string publicKeyPem, string charset)
|
||||
{
|
||||
var sign = parameters["sign"];
|
||||
|
||||
parameters.Remove("sign");
|
||||
parameters.Remove("sign_type");
|
||||
var signContent = GetSignContent(parameters);
|
||||
return RSACheckContent(signContent, sign, publicKeyPem, charset, "RSA");
|
||||
}
|
||||
|
||||
public static bool RSACheckV1(IDictionary<string, string> parameters, string publicKeyPem)
|
||||
{
|
||||
var sign = parameters["sign"];
|
||||
|
||||
parameters.Remove("sign");
|
||||
parameters.Remove("sign_type");
|
||||
var signContent = GetSignContent(parameters);
|
||||
|
||||
return RSACheckContent(signContent, sign, publicKeyPem, DEFAULT_CHARSET, "RSA");
|
||||
}
|
||||
|
||||
public static bool RSA2Check(IDictionary<string, string> parameters, string publicKeyPem)
|
||||
{
|
||||
var sign = parameters["sign"];
|
||||
|
||||
parameters.Remove("sign");
|
||||
parameters.Remove("sign_type");
|
||||
var signContent = GetSignContent(parameters);
|
||||
|
||||
return RSACheckContent(signContent, sign, publicKeyPem, DEFAULT_CHARSET, "RSA2");
|
||||
}
|
||||
|
||||
public static bool RSACheckV1(IDictionary<string, string> parameters, string publicKeyPem, string charset,
|
||||
string signType, bool keyFromFile)
|
||||
{
|
||||
var sign = parameters["sign"];
|
||||
|
||||
parameters.Remove("sign");
|
||||
parameters.Remove("sign_type");
|
||||
var signContent = GetSignContent(parameters);
|
||||
return RSACheckContent(signContent, sign, publicKeyPem, charset, signType, keyFromFile);
|
||||
}
|
||||
|
||||
public static bool RSACheckV2(IDictionary<string, string> parameters, string publicKeyPem, string charset)
|
||||
{
|
||||
var sign = parameters["sign"];
|
||||
|
||||
parameters.Remove("sign");
|
||||
parameters.Remove("sign_type");
|
||||
var signContent = GetSignContent(parameters);
|
||||
|
||||
return RSACheckContent(signContent, sign, publicKeyPem, charset, "RSA");
|
||||
}
|
||||
|
||||
public static bool RSACheckV2(IDictionary<string, string> parameters, string publicKeyPem, string charset,
|
||||
string signType, bool keyFromFile)
|
||||
{
|
||||
var sign = parameters["sign"];
|
||||
parameters.Remove("sign");
|
||||
parameters.Remove("sign_type");
|
||||
var signContent = GetSignContent(parameters);
|
||||
|
||||
return RSACheckContent(signContent, sign, publicKeyPem, charset, signType, keyFromFile);
|
||||
}
|
||||
|
||||
public static RSA CreateRsaProviderFromPublicKey(string publicKeyString,string signType)
|
||||
{
|
||||
// encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
|
||||
byte[] seqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
|
||||
byte[] seq = new byte[15];
|
||||
|
||||
var x509Key = Convert.FromBase64String(publicKeyString);
|
||||
|
||||
// --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------
|
||||
using (MemoryStream mem = new MemoryStream(x509Key))
|
||||
{
|
||||
using (BinaryReader binr = new BinaryReader(mem)) //wrap Memory Stream with BinaryReader for easy reading
|
||||
{
|
||||
byte bt = 0;
|
||||
ushort twobytes = 0;
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
|
||||
binr.ReadByte(); //advance 1 byte
|
||||
else if (twobytes == 0x8230)
|
||||
binr.ReadInt16(); //advance 2 bytes
|
||||
else
|
||||
return null;
|
||||
|
||||
seq = binr.ReadBytes(15); //read the Sequence OID
|
||||
if (!CompareBytearrays(seq, seqOid)) //make sure Sequence for OID is correct
|
||||
return null;
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
|
||||
binr.ReadByte(); //advance 1 byte
|
||||
else if (twobytes == 0x8203)
|
||||
binr.ReadInt16(); //advance 2 bytes
|
||||
else
|
||||
return null;
|
||||
|
||||
bt = binr.ReadByte();
|
||||
if (bt != 0x00) //expect null byte next
|
||||
return null;
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
|
||||
binr.ReadByte(); //advance 1 byte
|
||||
else if (twobytes == 0x8230)
|
||||
binr.ReadInt16(); //advance 2 bytes
|
||||
else
|
||||
return null;
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
byte lowbyte = 0x00;
|
||||
byte highbyte = 0x00;
|
||||
|
||||
if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
|
||||
lowbyte = binr.ReadByte(); // read next bytes which is bytes in modulus
|
||||
else if (twobytes == 0x8202)
|
||||
{
|
||||
highbyte = binr.ReadByte(); //advance 2 bytes
|
||||
lowbyte = binr.ReadByte();
|
||||
}
|
||||
else
|
||||
return null;
|
||||
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; //reverse byte order since asn.1 key uses big endian order
|
||||
int modsize = BitConverter.ToInt32(modint, 0);
|
||||
|
||||
int firstbyte = binr.PeekChar();
|
||||
if (firstbyte == 0x00)
|
||||
{ //if first byte (highest order) of modulus is zero, don't include it
|
||||
binr.ReadByte(); //skip this null byte
|
||||
modsize -= 1; //reduce modulus buffer size by 1
|
||||
}
|
||||
|
||||
byte[] modulus = binr.ReadBytes(modsize); //read the modulus bytes
|
||||
|
||||
if (binr.ReadByte() != 0x02) //expect an Integer for the exponent data
|
||||
return null;
|
||||
int expbytes = (int)binr.ReadByte(); // should only need one byte for actual exponent data (for all useful values)
|
||||
byte[] exponent = binr.ReadBytes(expbytes);
|
||||
|
||||
// ------- create RSACryptoServiceProvider instance and initialize with public key -----
|
||||
var rsa = RSA.Create();
|
||||
rsa.KeySize = signType == "RSA" ? 1024 : 2048;
|
||||
RSAParameters rsaKeyInfo = new RSAParameters();
|
||||
rsaKeyInfo.Modulus = modulus;
|
||||
rsaKeyInfo.Exponent = exponent;
|
||||
rsa.ImportParameters(rsaKeyInfo);
|
||||
|
||||
return rsa;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CompareBytearrays(byte[] a, byte[] b)
|
||||
{
|
||||
if (a.Length != b.Length)
|
||||
return false;
|
||||
int i = 0;
|
||||
foreach (byte c in a)
|
||||
{
|
||||
if (c != b[i])
|
||||
return false;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool RSACheckContent(string signContent, string sign, string publicKeyPem, string charset,
|
||||
string signType)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(charset))
|
||||
charset = DEFAULT_CHARSET;
|
||||
|
||||
var sPublicKeyPem = File.ReadAllText(publicKeyPem);
|
||||
|
||||
var rsa = CreateRsaProviderFromPublicKey(sPublicKeyPem, signType);
|
||||
|
||||
if ("RSA2".Equals(signType))
|
||||
{
|
||||
|
||||
|
||||
var bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent),
|
||||
Convert.FromBase64String(sign),HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
return bVerifyResultOriginal;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
var bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent),
|
||||
Convert.FromBase64String(sign), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
|
||||
return bVerifyResultOriginal;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool RSACheckContent(string signContent, string sign, string publicKeyPem, string charset,
|
||||
string signType, bool keyFromFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(charset))
|
||||
charset = DEFAULT_CHARSET;
|
||||
|
||||
string sPublicKeyPem= publicKeyPem;
|
||||
|
||||
if (keyFromFile)
|
||||
{
|
||||
sPublicKeyPem = File.ReadAllText(publicKeyPem);
|
||||
}
|
||||
var rsa = CreateRsaProviderFromPublicKey(sPublicKeyPem, signType);
|
||||
|
||||
if ("RSA2".Equals(signType))
|
||||
{
|
||||
|
||||
|
||||
var bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent),
|
||||
Convert.FromBase64String(sign), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
return bVerifyResultOriginal;
|
||||
}
|
||||
else
|
||||
{
|
||||
var bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent),
|
||||
Convert.FromBase64String(sign), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
|
||||
return bVerifyResultOriginal;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool RSACheckContent(string signContent, string sign, string publicKeyPem, string charset,
|
||||
bool keyFromFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
string sPublicKeyPem= publicKeyPem;
|
||||
if (keyFromFile)
|
||||
{
|
||||
sPublicKeyPem = File.ReadAllText(publicKeyPem);
|
||||
}
|
||||
var rsa = CreateRsaProviderFromPublicKey(sPublicKeyPem, "RSA");
|
||||
var sha1 = new SHA1CryptoServiceProvider();
|
||||
if (string.IsNullOrEmpty(charset))
|
||||
charset = DEFAULT_CHARSET;
|
||||
var bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent),
|
||||
Convert.FromBase64String(sign),HashAlgorithmName.SHA1,RSASignaturePadding.Pkcs1);
|
||||
return bVerifyResultOriginal;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var s = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static string CheckSignAndDecrypt(IDictionary<string, string> parameters, string alipayPublicKey,
|
||||
string cusPrivateKey, bool isCheckSign,
|
||||
bool isDecrypt)
|
||||
{
|
||||
var charset = parameters["charset"];
|
||||
var bizContent = parameters["biz_content"];
|
||||
if (isCheckSign)
|
||||
if (!RSACheckV2(parameters, alipayPublicKey, charset))
|
||||
throw new AopException("rsaCheck failure:rsaParams=" + parameters);
|
||||
|
||||
if (isDecrypt)
|
||||
return RSADecrypt(bizContent, cusPrivateKey, charset, "RSA");
|
||||
|
||||
return bizContent;
|
||||
}
|
||||
|
||||
public static string CheckSignAndDecrypt(IDictionary<string, string> parameters, string alipayPublicKey,
|
||||
string cusPrivateKey, bool isCheckSign,
|
||||
bool isDecrypt, string signType, bool keyFromFile)
|
||||
{
|
||||
var charset = parameters["charset"];
|
||||
var bizContent = parameters["biz_content"];
|
||||
if (isCheckSign)
|
||||
if (!RSACheckV2(parameters, alipayPublicKey, charset, signType, keyFromFile))
|
||||
throw new AopException("rsaCheck failure:rsaParams=" + parameters);
|
||||
|
||||
if (isDecrypt)
|
||||
return RSADecrypt(bizContent, cusPrivateKey, charset, signType, keyFromFile);
|
||||
|
||||
return bizContent;
|
||||
}
|
||||
|
||||
public static string encryptAndSign(string bizContent, string alipayPublicKey,
|
||||
string cusPrivateKey, string charset, bool isEncrypt,
|
||||
bool isSign, string signType, bool keyFromFile)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
if (string.IsNullOrEmpty(charset))
|
||||
charset = DEFAULT_CHARSET;
|
||||
sb.Append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>");
|
||||
if (isEncrypt)
|
||||
{
|
||||
// 加密
|
||||
sb.Append("<alipay>");
|
||||
var encrypted = RSAEncrypt(bizContent, alipayPublicKey, charset, keyFromFile);
|
||||
sb.Append("<response>" + encrypted + "</response>");
|
||||
sb.Append("<encryption_type>" + signType + "</encryption_type>");
|
||||
if (isSign)
|
||||
{
|
||||
var sign = RSASign(encrypted, cusPrivateKey, charset, signType, keyFromFile);
|
||||
sb.Append("<sign>" + sign + "</sign>");
|
||||
sb.Append("<sign_type>" + signType + "</sign_type>");
|
||||
}
|
||||
sb.Append("</alipay>");
|
||||
}
|
||||
else if (isSign)
|
||||
{
|
||||
// 不加密,但需要签名
|
||||
sb.Append("<alipay>");
|
||||
sb.Append("<response>" + bizContent + "</response>");
|
||||
var sign = RSASign(bizContent, cusPrivateKey, charset, signType, keyFromFile);
|
||||
sb.Append("<sign>" + sign + "</sign>");
|
||||
sb.Append("<sign_type>" + signType + "</sign_type>");
|
||||
sb.Append("</alipay>");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 不加密,不加签
|
||||
sb.Append(bizContent);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string encryptAndSign(string bizContent, string alipayPublicKey,
|
||||
string cusPrivateKey, string charset, bool isEncrypt,
|
||||
bool isSign)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
if (string.IsNullOrEmpty(charset))
|
||||
charset = DEFAULT_CHARSET;
|
||||
sb.Append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>");
|
||||
if (isEncrypt)
|
||||
{
|
||||
// 加密
|
||||
sb.Append("<alipay>");
|
||||
var encrypted = RSAEncrypt(bizContent, alipayPublicKey, charset);
|
||||
sb.Append("<response>" + encrypted + "</response>");
|
||||
sb.Append("<encryption_type>RSA</encryption_type>");
|
||||
if (isSign)
|
||||
{
|
||||
var sign = RSASign(encrypted, cusPrivateKey, charset, "RSA");
|
||||
sb.Append("<sign>" + sign + "</sign>");
|
||||
sb.Append("<sign_type>RSA</sign_type>");
|
||||
}
|
||||
sb.Append("</alipay>");
|
||||
}
|
||||
else if (isSign)
|
||||
{
|
||||
// 不加密,但需要签名
|
||||
sb.Append("<alipay>");
|
||||
sb.Append("<response>" + bizContent + "</response>");
|
||||
var sign = RSASign(bizContent, cusPrivateKey, charset, "RSA");
|
||||
sb.Append("<sign>" + sign + "</sign>");
|
||||
sb.Append("<sign_type>RSA</sign_type>");
|
||||
sb.Append("</alipay>");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 不加密,不加签
|
||||
sb.Append(bizContent);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string RSAEncrypt(string content, string publicKeyPem, string charset)
|
||||
{
|
||||
try
|
||||
{
|
||||
var sPublicKeyPEM = File.ReadAllText(publicKeyPem);
|
||||
var rsa = CreateRsaProviderFromPublicKey(sPublicKeyPEM, "RSA");
|
||||
if (string.IsNullOrEmpty(charset))
|
||||
charset = DEFAULT_CHARSET;
|
||||
var data = Encoding.GetEncoding(charset).GetBytes(content);
|
||||
var maxBlockSize = rsa.KeySize / 8 - 11; //加密块最大长度限制
|
||||
if (data.Length <= maxBlockSize)
|
||||
{
|
||||
var cipherbytes = rsa.Encrypt(data, RSAEncryptionPadding.Pkcs1);
|
||||
return Convert.ToBase64String(cipherbytes);
|
||||
}
|
||||
var plaiStream = new MemoryStream(data);
|
||||
var crypStream = new MemoryStream();
|
||||
var buffer = new byte[maxBlockSize];
|
||||
var blockSize = plaiStream.Read(buffer, 0, maxBlockSize);
|
||||
while (blockSize > 0)
|
||||
{
|
||||
var toEncrypt = new byte[blockSize];
|
||||
Array.Copy(buffer, 0, toEncrypt, 0, blockSize);
|
||||
var cryptograph = rsa.Encrypt(toEncrypt, RSAEncryptionPadding.Pkcs1);
|
||||
crypStream.Write(cryptograph, 0, cryptograph.Length);
|
||||
blockSize = plaiStream.Read(buffer, 0, maxBlockSize);
|
||||
}
|
||||
|
||||
return Convert.ToBase64String(crypStream.ToArray(), Base64FormattingOptions.None);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new AopException("EncryptContent = " + content + ",charset = " + charset, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static string RSAEncrypt(string content, string publicKeyPem, string charset, bool keyFromFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
string sPublicKeyPEM= publicKeyPem;
|
||||
if (keyFromFile)
|
||||
{
|
||||
sPublicKeyPEM = File.ReadAllText(publicKeyPem);
|
||||
}
|
||||
var rsa = CreateRsaProviderFromPublicKey(publicKeyPem, "RSA");
|
||||
if (string.IsNullOrEmpty(charset))
|
||||
charset = DEFAULT_CHARSET;
|
||||
var data = Encoding.GetEncoding(charset).GetBytes(content);
|
||||
var maxBlockSize = rsa.KeySize / 8 - 11; //加密块最大长度限制
|
||||
if (data.Length <= maxBlockSize)
|
||||
{
|
||||
var cipherbytes = rsa.Encrypt(data, RSAEncryptionPadding.Pkcs1);
|
||||
return Convert.ToBase64String(cipherbytes);
|
||||
}
|
||||
var plaiStream = new MemoryStream(data);
|
||||
var crypStream = new MemoryStream();
|
||||
var buffer = new byte[maxBlockSize];
|
||||
var blockSize = plaiStream.Read(buffer, 0, maxBlockSize);
|
||||
while (blockSize > 0)
|
||||
{
|
||||
var toEncrypt = new byte[blockSize];
|
||||
Array.Copy(buffer, 0, toEncrypt, 0, blockSize);
|
||||
var cryptograph = rsa.Encrypt(toEncrypt, RSAEncryptionPadding.Pkcs1);
|
||||
crypStream.Write(cryptograph, 0, cryptograph.Length);
|
||||
blockSize = plaiStream.Read(buffer, 0, maxBlockSize);
|
||||
}
|
||||
|
||||
return Convert.ToBase64String(crypStream.ToArray(), Base64FormattingOptions.None);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new AopException("EncryptContent = " + content + ",charset = " + charset, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static string RSADecrypt(string content, string privateKeyPem, string charset, string signType)
|
||||
{
|
||||
try
|
||||
{
|
||||
var rsaCsp = LoadCertificateFile(privateKeyPem, signType);
|
||||
if (string.IsNullOrEmpty(charset))
|
||||
charset = DEFAULT_CHARSET;
|
||||
var data = Convert.FromBase64String(content);
|
||||
var maxBlockSize = rsaCsp.KeySize / 8; //解密块最大长度限制
|
||||
if (data.Length <= maxBlockSize)
|
||||
{
|
||||
var cipherbytes = rsaCsp.Decrypt(data, RSAEncryptionPadding.Pkcs1);
|
||||
return Encoding.GetEncoding(charset).GetString(cipherbytes);
|
||||
}
|
||||
var crypStream = new MemoryStream(data);
|
||||
var plaiStream = new MemoryStream();
|
||||
var buffer = new byte[maxBlockSize];
|
||||
var blockSize = crypStream.Read(buffer, 0, maxBlockSize);
|
||||
while (blockSize > 0)
|
||||
{
|
||||
var toDecrypt = new byte[blockSize];
|
||||
Array.Copy(buffer, 0, toDecrypt, 0, blockSize);
|
||||
var cryptograph = rsaCsp.Decrypt(toDecrypt, RSAEncryptionPadding.Pkcs1);
|
||||
plaiStream.Write(cryptograph, 0, cryptograph.Length);
|
||||
blockSize = crypStream.Read(buffer, 0, maxBlockSize);
|
||||
}
|
||||
|
||||
return Encoding.GetEncoding(charset).GetString(plaiStream.ToArray());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new AopException("DecryptContent = " + content + ",charset = " + charset, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static string RSADecrypt(string content, string privateKeyPem, string charset, string signType,
|
||||
bool keyFromFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
RSA rsaCsp = null;
|
||||
if (keyFromFile)
|
||||
rsaCsp = LoadCertificateFile(privateKeyPem, signType);
|
||||
else
|
||||
rsaCsp = LoadCertificateString(privateKeyPem, signType);
|
||||
if (string.IsNullOrEmpty(charset))
|
||||
charset = DEFAULT_CHARSET;
|
||||
var data = Convert.FromBase64String(content);
|
||||
var maxBlockSize = rsaCsp.KeySize / 8; //解密块最大长度限制
|
||||
if (data.Length <= maxBlockSize)
|
||||
{
|
||||
var cipherbytes = rsaCsp.Decrypt(data, RSAEncryptionPadding.Pkcs1);
|
||||
return Encoding.GetEncoding(charset).GetString(cipherbytes);
|
||||
}
|
||||
var crypStream = new MemoryStream(data);
|
||||
var plaiStream = new MemoryStream();
|
||||
var buffer = new byte[maxBlockSize];
|
||||
var blockSize = crypStream.Read(buffer, 0, maxBlockSize);
|
||||
while (blockSize > 0)
|
||||
{
|
||||
var toDecrypt = new byte[blockSize];
|
||||
Array.Copy(buffer, 0, toDecrypt, 0, blockSize);
|
||||
var cryptograph = rsaCsp.Decrypt(toDecrypt, RSAEncryptionPadding.Pkcs1);
|
||||
plaiStream.Write(cryptograph, 0, cryptograph.Length);
|
||||
blockSize = crypStream.Read(buffer, 0, maxBlockSize);
|
||||
}
|
||||
|
||||
return Encoding.GetEncoding(charset).GetString(plaiStream.ToArray());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new AopException("DecryptContent = " + content + ",charset = " + charset, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] GetPem(string type, byte[] data)
|
||||
{
|
||||
var pem = Encoding.UTF8.GetString(data);
|
||||
var header = string.Format("-----BEGIN {0}-----\\n", type);
|
||||
var footer = string.Format("-----END {0}-----", type);
|
||||
var start = pem.IndexOf(header) + header.Length;
|
||||
var end = pem.IndexOf(footer, start);
|
||||
var base64 = pem.Substring(start, end - start);
|
||||
|
||||
return Convert.FromBase64String(base64);
|
||||
}
|
||||
|
||||
private static RSA LoadCertificateFile(string filename, string signType)
|
||||
{
|
||||
using (var fs = File.OpenRead(filename))
|
||||
{
|
||||
var data = new byte[fs.Length];
|
||||
byte[] res = null;
|
||||
fs.Read(data, 0, data.Length);
|
||||
if (data[0] != 0x30)
|
||||
res = GetPem("RSA PRIVATE KEY", data);
|
||||
try
|
||||
{
|
||||
var rsa = DecodeRSAPrivateKey(res, signType);
|
||||
return rsa;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static RSA LoadCertificateString(string strKey, string signType)
|
||||
{
|
||||
byte[] data = null;
|
||||
//读取带
|
||||
//ata = Encoding.Default.GetBytes(strKey);
|
||||
data = Convert.FromBase64String(strKey);
|
||||
//data = GetPem("RSA PRIVATE KEY", data);
|
||||
try
|
||||
{
|
||||
var rsa = DecodeRSAPrivateKey(data, signType);
|
||||
return rsa;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new AopException("Alipay.AopSdk.Core.Util.AlipaySignature LoadCertificateString DecodeRSAPrivateKey Error", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static RSA DecodeRSAPrivateKey(byte[] privkey, string signType)
|
||||
{
|
||||
byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
|
||||
|
||||
// --------- Set up stream to decode the asn.1 encoded RSA private key ------
|
||||
var mem = new MemoryStream(privkey);
|
||||
var binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading
|
||||
byte bt = 0;
|
||||
ushort twobytes = 0;
|
||||
var elems = 0;
|
||||
try
|
||||
{
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
|
||||
binr.ReadByte(); //advance 1 byte
|
||||
else if (twobytes == 0x8230)
|
||||
binr.ReadInt16(); //advance 2 bytes
|
||||
else
|
||||
return null;
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes != 0x0102) //version number
|
||||
return null;
|
||||
bt = binr.ReadByte();
|
||||
if (bt != 0x00)
|
||||
return null;
|
||||
|
||||
|
||||
//------ all private key components are Integer sequences ----
|
||||
elems = GetIntegerSize(binr);
|
||||
MODULUS = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
E = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
D = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
P = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
Q = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
DP = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
DQ = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
IQ = binr.ReadBytes(elems);
|
||||
|
||||
|
||||
// ------- create RSACryptoServiceProvider instance and initialize with public key -----
|
||||
var CspParameters = new CspParameters();
|
||||
CspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
|
||||
|
||||
var bitLen = 1024;
|
||||
if ("RSA2".Equals(signType))
|
||||
bitLen = 2048;
|
||||
|
||||
var rsa = RSA.Create();
|
||||
rsa.KeySize = bitLen;
|
||||
var rsAparams = new RSAParameters();
|
||||
rsAparams.Modulus = MODULUS;
|
||||
rsAparams.Exponent = E;
|
||||
rsAparams.D = D;
|
||||
rsAparams.P = P;
|
||||
rsAparams.Q = Q;
|
||||
rsAparams.DP = DP;
|
||||
rsAparams.DQ = DQ;
|
||||
rsAparams.InverseQ = IQ;
|
||||
rsa.ImportParameters(rsAparams);
|
||||
return rsa;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
binr.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetIntegerSize(BinaryReader binr)
|
||||
{
|
||||
byte bt = 0;
|
||||
byte lowbyte = 0x00;
|
||||
byte highbyte = 0x00;
|
||||
var count = 0;
|
||||
bt = binr.ReadByte();
|
||||
if (bt != 0x02) //expect integer
|
||||
return 0;
|
||||
bt = binr.ReadByte();
|
||||
|
||||
if (bt == 0x81)
|
||||
{
|
||||
count = binr.ReadByte(); // data size in next byte
|
||||
}
|
||||
else if (bt == 0x82)
|
||||
{
|
||||
highbyte = binr.ReadByte(); // data size in next 2 bytes
|
||||
lowbyte = binr.ReadByte();
|
||||
byte[] modint = {lowbyte, highbyte, 0x00, 0x00};
|
||||
count = BitConverter.ToInt32(modint, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = bt; // we already have the data size
|
||||
}
|
||||
|
||||
while (binr.ReadByte() == 0x00)
|
||||
//remove high order zeros in data
|
||||
count -= 1;
|
||||
binr.BaseStream.Seek(-1, SeekOrigin.Current); //last ReadByte wasn't a removed zero, so back up a byte
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
162
Infrastructure/ServiceClient/Alipay.AopSdk.Core/Util/AopUtils.cs
Normal file
162
Infrastructure/ServiceClient/Alipay.AopSdk.Core/Util/AopUtils.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Alipay.AopSdk.Core.Util
|
||||
{
|
||||
/// <summary>
|
||||
/// AOP系统工具类。
|
||||
/// </summary>
|
||||
public abstract class AopUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// AES加密
|
||||
/// </summary>
|
||||
/// <param name="bizContent"></param>
|
||||
/// <param name="charset"></param>
|
||||
/// <param name="encryptKey"></param>
|
||||
/// <returns></returns>
|
||||
public static string AesEncrypt(string encryptKey, string bizContent, string charset)
|
||||
{
|
||||
return AlipayEncrypt.AesEncrypt(encryptKey, bizContent, charset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 给AOP请求签名。
|
||||
/// <remarks>建议使用<code>AlipaySignature.RSASign(parameters, privateKeyPem)</code>></remarks>
|
||||
/// </summary>
|
||||
/// <param name="parameters">所有字符型的AOP请求参数</param>
|
||||
/// <param name="privateKeyPem">签名密钥</param>
|
||||
/// <returns>签名</returns>
|
||||
public static string SignAopRequest(IDictionary<string, string> parameters, string privateKeyPem, string charset,
|
||||
string signType)
|
||||
{
|
||||
return AlipaySignature.RSASign(parameters, privateKeyPem, charset, signType);
|
||||
}
|
||||
|
||||
public static string SignAopRequest(IDictionary<string, string> parameters, string privateKeyPem, string charset,
|
||||
bool keyFromFile, string signType)
|
||||
{
|
||||
return AlipaySignature.RSASign(parameters, privateKeyPem, charset, keyFromFile, signType);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 清除字典中值为空的项。
|
||||
/// </summary>
|
||||
/// <param name="dict">待清除的字典</param>
|
||||
/// <returns>清除后的字典</returns>
|
||||
public static IDictionary<string, T> CleanupDictionary<T>(IDictionary<string, T> dict)
|
||||
{
|
||||
IDictionary<string, T> newDict = new Dictionary<string, T>(dict.Count);
|
||||
var dem = dict.GetEnumerator();
|
||||
|
||||
while (dem.MoveNext())
|
||||
{
|
||||
var name = dem.Current.Key;
|
||||
var value = dem.Current.Value;
|
||||
if (value != null)
|
||||
newDict.Add(name, value);
|
||||
}
|
||||
|
||||
return newDict;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件的真实后缀名。目前只支持JPG, GIF, PNG, BMP四种图片文件。
|
||||
/// </summary>
|
||||
/// <param name="fileData">文件字节流</param>
|
||||
/// <returns>JPG, GIF, PNG or null</returns>
|
||||
public static string GetFileSuffix(byte[] fileData)
|
||||
{
|
||||
if (fileData == null || fileData.Length < 10)
|
||||
return null;
|
||||
|
||||
if (fileData[0] == 'G' && fileData[1] == 'I' && fileData[2] == 'F')
|
||||
return "GIF";
|
||||
if (fileData[1] == 'P' && fileData[2] == 'N' && fileData[3] == 'G')
|
||||
return "PNG";
|
||||
if (fileData[6] == 'J' && fileData[7] == 'F' && fileData[8] == 'I' && fileData[9] == 'F')
|
||||
return "JPG";
|
||||
if (fileData[0] == 'B' && fileData[1] == 'M')
|
||||
return "BMP";
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件的真实媒体类型。目前只支持JPG, GIF, PNG, BMP四种图片文件。
|
||||
/// </summary>
|
||||
/// <param name="fileData">文件字节流</param>
|
||||
/// <returns>媒体类型</returns>
|
||||
public static string GetMimeType(byte[] fileData)
|
||||
{
|
||||
var suffix = GetFileSuffix(fileData);
|
||||
string mimeType;
|
||||
|
||||
switch (suffix)
|
||||
{
|
||||
case "JPG":
|
||||
mimeType = "image/jpeg";
|
||||
break;
|
||||
case "GIF":
|
||||
mimeType = "image/gif";
|
||||
break;
|
||||
case "PNG":
|
||||
mimeType = "image/png";
|
||||
break;
|
||||
case "BMP":
|
||||
mimeType = "image/bmp";
|
||||
break;
|
||||
default:
|
||||
mimeType = "application/octet-stream";
|
||||
break;
|
||||
}
|
||||
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据文件后缀名获取文件的媒体类型。
|
||||
/// </summary>
|
||||
/// <param name="fileName">带后缀的文件名或文件全名</param>
|
||||
/// <returns>媒体类型</returns>
|
||||
public static string GetMimeType(string fileName)
|
||||
{
|
||||
string mimeType;
|
||||
fileName = fileName.ToLower();
|
||||
|
||||
if (fileName.EndsWith(".bmp", StringComparison.CurrentCulture))
|
||||
mimeType = "image/bmp";
|
||||
else if (fileName.EndsWith(".gif", StringComparison.CurrentCulture))
|
||||
mimeType = "image/gif";
|
||||
else if (fileName.EndsWith(".jpg", StringComparison.CurrentCulture) ||
|
||||
fileName.EndsWith(".jpeg", StringComparison.CurrentCulture))
|
||||
mimeType = "image/jpeg";
|
||||
else if (fileName.EndsWith(".png", StringComparison.CurrentCulture))
|
||||
mimeType = "image/png";
|
||||
else
|
||||
mimeType = "application/octet-stream";
|
||||
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据API名称获取响应根节点名称。
|
||||
/// </summary>
|
||||
/// <param name="api">API名称</param>
|
||||
/// <returns></returns>
|
||||
public static string GetRootElement(string api)
|
||||
{
|
||||
var pos = api.IndexOf(".");
|
||||
if (pos != -1 && api.Length > pos)
|
||||
api = api.Substring(pos + 1).Replace('.', '_');
|
||||
return api + "_response";
|
||||
}
|
||||
|
||||
public static IDictionary ParseJson(string body)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<IDictionary>(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Nito.AsyncEx;
|
||||
|
||||
namespace Alipay.AopSdk.Core.Util
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides some helper methods to work with async methods.
|
||||
/// </summary>
|
||||
public static class AsyncHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if given method is an async method.
|
||||
/// </summary>
|
||||
/// <param name="method">A method to check</param>
|
||||
public static bool IsAsync(this MethodInfo method)
|
||||
{
|
||||
return (
|
||||
method.ReturnType == typeof(Task) ||
|
||||
(method.ReturnType.GetTypeInfo().IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
|
||||
);
|
||||
}
|
||||
/// <summary>
|
||||
/// Runs a async method synchronously.
|
||||
/// </summary>
|
||||
/// <param name="func">A function that returns a result</param>
|
||||
/// <typeparam name="TResult">Result type</typeparam>
|
||||
/// <returns>Result of the async operation</returns>
|
||||
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
|
||||
{
|
||||
return AsyncContext.Run(func);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs a async method synchronously.
|
||||
/// </summary>
|
||||
/// <param name="action">An async action</param>
|
||||
public static void RunSync(Func<Task> action)
|
||||
{
|
||||
AsyncContext.Run(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Alipay.AopSdk.Core.Util
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件元数据。
|
||||
/// 可以使用以下几种构造方法:
|
||||
/// 本地路径:new FileItem("C:/temp.jpg");
|
||||
/// 本地文件:new FileItem(new FileInfo("C:/temp.jpg"));
|
||||
/// 字节流:new FileItem("abc.jpg", bytes);
|
||||
/// </summary>
|
||||
public class FileItem
|
||||
{
|
||||
private byte[] content;
|
||||
private readonly FileInfo fileInfo;
|
||||
private string fileName;
|
||||
private string mimeType;
|
||||
|
||||
/// <summary>
|
||||
/// 基于本地文件的构造器。
|
||||
/// </summary>
|
||||
/// <param name="fileInfo">本地文件</param>
|
||||
public FileItem(FileInfo fileInfo)
|
||||
{
|
||||
if (fileInfo == null || !fileInfo.Exists)
|
||||
throw new ArgumentException("fileInfo is null or not exists!");
|
||||
this.fileInfo = fileInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 基于本地文件全路径的构造器。
|
||||
/// </summary>
|
||||
/// <param name="filePath">本地文件全路径</param>
|
||||
public FileItem(string filePath)
|
||||
: this(new FileInfo(filePath))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 基于文件名和字节流的构造器。
|
||||
/// </summary>
|
||||
/// <param name="fileName">文件名称(服务端持久化字节流到磁盘时的文件名)</param>
|
||||
/// <param name="content">文件字节流</param>
|
||||
public FileItem(string fileName, byte[] content)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName)) throw new ArgumentNullException("fileName");
|
||||
if (content == null || content.Length == 0) throw new ArgumentNullException("content");
|
||||
|
||||
this.fileName = fileName;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 基于文件名、字节流和媒体类型的构造器。
|
||||
/// </summary>
|
||||
/// <param name="fileName">文件名(服务端持久化字节流到磁盘时的文件名)</param>
|
||||
/// <param name="content">文件字节流</param>
|
||||
/// <param name="mimeType">媒体类型</param>
|
||||
public FileItem(string fileName, byte[] content, string mimeType)
|
||||
: this(fileName, content)
|
||||
{
|
||||
if (string.IsNullOrEmpty(mimeType)) throw new ArgumentNullException("mimeType");
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
public string GetFileName()
|
||||
{
|
||||
if (fileName == null && fileInfo != null && fileInfo.Exists)
|
||||
fileName = fileInfo.FullName;
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public string GetMimeType()
|
||||
{
|
||||
if (mimeType == null)
|
||||
mimeType = AopUtils.GetMimeType(GetContent());
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
public byte[] GetContent()
|
||||
{
|
||||
if (content == null && fileInfo != null && fileInfo.Exists)
|
||||
using (Stream fileStream = fileInfo.OpenRead())
|
||||
{
|
||||
content = new byte[fileStream.Length];
|
||||
fileStream.Read(content, 0, content.Length);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace RSATest
|
||||
{
|
||||
/// <summary>
|
||||
/// RSA加解密 使用OpenSSL的公钥加密/私钥解密
|
||||
///
|
||||
/// 公私钥请使用openssl生成 ssh-keygen -t rsa 命令生成的公钥私钥是不行的
|
||||
///
|
||||
/// 作者:李志强
|
||||
/// 时间:2017年10月30日15:50:14
|
||||
/// QQ:501232752
|
||||
/// </summary>
|
||||
public class RSAHelper
|
||||
{
|
||||
private readonly RSA _privateKeyRsaProvider;
|
||||
private readonly RSA _publicKeyRsaProvider;
|
||||
private readonly HashAlgorithmName _hashAlgorithmName;
|
||||
private readonly Encoding _encoding;
|
||||
|
||||
/// <summary>
|
||||
/// 实例化RSAHelper
|
||||
/// </summary>
|
||||
/// <param name="rsaType">加密算法类型 RSA SHA1;RSA2 SHA256 密钥长度至少为2048</param>
|
||||
/// <param name="encoding">编码类型</param>
|
||||
/// <param name="privateKey">私钥</param>
|
||||
/// <param name="publicKey">公钥</param>
|
||||
public RSAHelper(RSAType rsaType, Encoding encoding, string privateKey, string publicKey = null)
|
||||
{
|
||||
_encoding = encoding;
|
||||
if (!string.IsNullOrEmpty(privateKey))
|
||||
{
|
||||
_privateKeyRsaProvider = CreateRsaProviderFromPrivateKey(privateKey);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(publicKey))
|
||||
{
|
||||
_publicKeyRsaProvider = CreateRsaProviderFromPublicKey(publicKey);
|
||||
}
|
||||
|
||||
_hashAlgorithmName = rsaType == RSAType.RSA ? HashAlgorithmName.SHA1 : HashAlgorithmName.SHA256;
|
||||
}
|
||||
|
||||
#region 使用私钥签名
|
||||
|
||||
/// <summary>
|
||||
/// 使用私钥签名
|
||||
/// </summary>
|
||||
/// <param name="data">原始数据</param>
|
||||
/// <returns></returns>
|
||||
public string Sign(string data)
|
||||
{
|
||||
byte[] dataBytes = _encoding.GetBytes(data);
|
||||
|
||||
var signatureBytes = _privateKeyRsaProvider.SignData(dataBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1);
|
||||
|
||||
return Convert.ToBase64String(signatureBytes);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 使用公钥验证签名
|
||||
|
||||
/// <summary>
|
||||
/// 使用公钥验证签名
|
||||
/// </summary>
|
||||
/// <param name="data">原始数据</param>
|
||||
/// <param name="sign">签名</param>
|
||||
/// <returns></returns>
|
||||
public bool Verify(string data,string sign)
|
||||
{
|
||||
byte[] dataBytes = _encoding.GetBytes(data);
|
||||
byte[] signBytes = Convert.FromBase64String(sign);
|
||||
|
||||
var verify = _publicKeyRsaProvider.VerifyData(dataBytes, signBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1);
|
||||
|
||||
return verify;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 解密
|
||||
|
||||
public string Decrypt(string cipherText)
|
||||
{
|
||||
if (_privateKeyRsaProvider == null)
|
||||
{
|
||||
throw new Exception("_privateKeyRsaProvider is null");
|
||||
}
|
||||
return Encoding.UTF8.GetString(_privateKeyRsaProvider.Decrypt(Convert.FromBase64String(cipherText), RSAEncryptionPadding.Pkcs1));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 加密
|
||||
|
||||
public string Encrypt(string text)
|
||||
{
|
||||
if (_publicKeyRsaProvider == null)
|
||||
{
|
||||
throw new Exception("_publicKeyRsaProvider is null");
|
||||
}
|
||||
return Convert.ToBase64String(_publicKeyRsaProvider.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.Pkcs1));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 使用私钥创建RSA实例
|
||||
|
||||
public RSA CreateRsaProviderFromPrivateKey(string privateKey)
|
||||
{
|
||||
var privateKeyBits = Convert.FromBase64String(privateKey);
|
||||
|
||||
var rsa = RSA.Create();
|
||||
var rsaParameters = new RSAParameters();
|
||||
|
||||
using (BinaryReader binr = new BinaryReader(new MemoryStream(privateKeyBits)))
|
||||
{
|
||||
byte bt = 0;
|
||||
ushort twobytes = 0;
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes == 0x8130)
|
||||
binr.ReadByte();
|
||||
else if (twobytes == 0x8230)
|
||||
binr.ReadInt16();
|
||||
else
|
||||
throw new Exception("Unexpected value read binr.ReadUInt16()");
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes != 0x0102)
|
||||
throw new Exception("Unexpected version");
|
||||
|
||||
bt = binr.ReadByte();
|
||||
if (bt != 0x00)
|
||||
throw new Exception("Unexpected value read binr.ReadByte()");
|
||||
|
||||
rsaParameters.Modulus = binr.ReadBytes(GetIntegerSize(binr));
|
||||
rsaParameters.Exponent = binr.ReadBytes(GetIntegerSize(binr));
|
||||
rsaParameters.D = binr.ReadBytes(GetIntegerSize(binr));
|
||||
rsaParameters.P = binr.ReadBytes(GetIntegerSize(binr));
|
||||
rsaParameters.Q = binr.ReadBytes(GetIntegerSize(binr));
|
||||
rsaParameters.DP = binr.ReadBytes(GetIntegerSize(binr));
|
||||
rsaParameters.DQ = binr.ReadBytes(GetIntegerSize(binr));
|
||||
rsaParameters.InverseQ = binr.ReadBytes(GetIntegerSize(binr));
|
||||
}
|
||||
|
||||
rsa.ImportParameters(rsaParameters);
|
||||
return rsa;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 使用公钥创建RSA实例
|
||||
|
||||
public RSA CreateRsaProviderFromPublicKey(string publicKeyString)
|
||||
{
|
||||
// encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
|
||||
byte[] seqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
|
||||
byte[] seq = new byte[15];
|
||||
|
||||
var x509Key = Convert.FromBase64String(publicKeyString);
|
||||
|
||||
// --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------
|
||||
using (MemoryStream mem = new MemoryStream(x509Key))
|
||||
{
|
||||
using (BinaryReader binr = new BinaryReader(mem)) //wrap Memory Stream with BinaryReader for easy reading
|
||||
{
|
||||
byte bt = 0;
|
||||
ushort twobytes = 0;
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
|
||||
binr.ReadByte(); //advance 1 byte
|
||||
else if (twobytes == 0x8230)
|
||||
binr.ReadInt16(); //advance 2 bytes
|
||||
else
|
||||
return null;
|
||||
|
||||
seq = binr.ReadBytes(15); //read the Sequence OID
|
||||
if (!CompareBytearrays(seq, seqOid)) //make sure Sequence for OID is correct
|
||||
return null;
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
|
||||
binr.ReadByte(); //advance 1 byte
|
||||
else if (twobytes == 0x8203)
|
||||
binr.ReadInt16(); //advance 2 bytes
|
||||
else
|
||||
return null;
|
||||
|
||||
bt = binr.ReadByte();
|
||||
if (bt != 0x00) //expect null byte next
|
||||
return null;
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
|
||||
binr.ReadByte(); //advance 1 byte
|
||||
else if (twobytes == 0x8230)
|
||||
binr.ReadInt16(); //advance 2 bytes
|
||||
else
|
||||
return null;
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
byte lowbyte = 0x00;
|
||||
byte highbyte = 0x00;
|
||||
|
||||
if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
|
||||
lowbyte = binr.ReadByte(); // read next bytes which is bytes in modulus
|
||||
else if (twobytes == 0x8202)
|
||||
{
|
||||
highbyte = binr.ReadByte(); //advance 2 bytes
|
||||
lowbyte = binr.ReadByte();
|
||||
}
|
||||
else
|
||||
return null;
|
||||
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; //reverse byte order since asn.1 key uses big endian order
|
||||
int modsize = BitConverter.ToInt32(modint, 0);
|
||||
|
||||
int firstbyte = binr.PeekChar();
|
||||
if (firstbyte == 0x00)
|
||||
{ //if first byte (highest order) of modulus is zero, don't include it
|
||||
binr.ReadByte(); //skip this null byte
|
||||
modsize -= 1; //reduce modulus buffer size by 1
|
||||
}
|
||||
|
||||
byte[] modulus = binr.ReadBytes(modsize); //read the modulus bytes
|
||||
|
||||
if (binr.ReadByte() != 0x02) //expect an Integer for the exponent data
|
||||
return null;
|
||||
int expbytes = (int)binr.ReadByte(); // should only need one byte for actual exponent data (for all useful values)
|
||||
byte[] exponent = binr.ReadBytes(expbytes);
|
||||
|
||||
// ------- create RSACryptoServiceProvider instance and initialize with public key -----
|
||||
var rsa = RSA.Create();
|
||||
RSAParameters rsaKeyInfo = new RSAParameters
|
||||
{
|
||||
Modulus = modulus,
|
||||
Exponent = exponent
|
||||
};
|
||||
rsa.ImportParameters(rsaKeyInfo);
|
||||
|
||||
return rsa;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 导入密钥算法
|
||||
|
||||
private int GetIntegerSize(BinaryReader binr)
|
||||
{
|
||||
byte bt = 0;
|
||||
int count = 0;
|
||||
bt = binr.ReadByte();
|
||||
if (bt != 0x02)
|
||||
return 0;
|
||||
bt = binr.ReadByte();
|
||||
|
||||
if (bt == 0x81)
|
||||
count = binr.ReadByte();
|
||||
else
|
||||
if (bt == 0x82)
|
||||
{
|
||||
var highbyte = binr.ReadByte();
|
||||
var lowbyte = binr.ReadByte();
|
||||
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
|
||||
count = BitConverter.ToInt32(modint, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = bt;
|
||||
}
|
||||
|
||||
while (binr.ReadByte() == 0x00)
|
||||
{
|
||||
count -= 1;
|
||||
}
|
||||
binr.BaseStream.Seek(-1, SeekOrigin.Current);
|
||||
return count;
|
||||
}
|
||||
|
||||
private bool CompareBytearrays(byte[] a, byte[] b)
|
||||
{
|
||||
if (a.Length != b.Length)
|
||||
return false;
|
||||
int i = 0;
|
||||
foreach (byte c in a)
|
||||
{
|
||||
if (c != b[i])
|
||||
return false;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RSA算法类型
|
||||
/// </summary>
|
||||
public enum RSAType
|
||||
{
|
||||
/// <summary>
|
||||
/// SHA1
|
||||
/// </summary>
|
||||
RSA = 0,
|
||||
/// <summary>
|
||||
/// RSA2 密钥长度至少为2048
|
||||
/// SHA256
|
||||
/// </summary>
|
||||
RSA2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace Alipay.AopSdk.Core.Util
|
||||
{
|
||||
/// <summary>
|
||||
/// RSA签名工具类。
|
||||
/// </summary>
|
||||
public class RSAUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// 建议直接使用<code>AlipaySignature.RSASign(data, privateKeyPem)</code>
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="privateKeyPem"></param>
|
||||
/// <returns></returns>
|
||||
public static string RSASign(string data, string privateKeyPem, string charset)
|
||||
{
|
||||
return AlipaySignature.RSASign(data, privateKeyPem, charset, "RSA");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Alipay.AopSdk.Core.Util
|
||||
{
|
||||
public class StringUtil
|
||||
{
|
||||
public static string ToString(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return "null";
|
||||
|
||||
var type = obj.GetType();
|
||||
if (string.Equals("System", type.Namespace))
|
||||
return "\"" + obj + "\"";
|
||||
|
||||
// class
|
||||
var result = "{";
|
||||
|
||||
var pis = type.GetProperties();
|
||||
for (var i = 0; i < pis.Length; i++)
|
||||
{
|
||||
var pi = pis[i];
|
||||
var pType = pi.PropertyType;
|
||||
|
||||
var getMethod = pi.GetGetMethod();
|
||||
var value = getMethod.Invoke(obj, null);
|
||||
if (value == null)
|
||||
continue;
|
||||
|
||||
var valueString = "";
|
||||
|
||||
if (string.Equals("System", pType.Namespace))
|
||||
valueString = "\"" + value + "\"";
|
||||
else if (string.Equals("System.Collections.Generic", pType.Namespace))
|
||||
valueString = List2String(value);
|
||||
else
|
||||
valueString = ToString(value);
|
||||
|
||||
if (i != 0)
|
||||
result += ",";
|
||||
result += "\"" + pi.Name + "\":" + valueString + "";
|
||||
}
|
||||
result += "}";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string List2String(object listObjects)
|
||||
{
|
||||
if (listObjects == null)
|
||||
return "[]";
|
||||
|
||||
var result = "[";
|
||||
|
||||
var list = (IList) listObjects;
|
||||
for (var i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
result += ",";
|
||||
result += ToString(list[i]);
|
||||
}
|
||||
result += "]";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
214
Infrastructure/ServiceClient/Alipay.AopSdk.Core/Util/WebUtils.cs
Normal file
214
Infrastructure/ServiceClient/Alipay.AopSdk.Core/Util/WebUtils.cs
Normal file
@@ -0,0 +1,214 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Alipay.AopSdk.Core.Util
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络工具类。
|
||||
/// </summary>
|
||||
public sealed class WebUtils
|
||||
{
|
||||
|
||||
internal readonly WebUtilsHttpConnectionPool ConnectionPool;
|
||||
|
||||
public WebUtils(string server,int poolSize=30)
|
||||
{
|
||||
ConnectionPool = new WebUtilsHttpConnectionPool(server, poolSize);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 执行HTTP POST请求。
|
||||
/// </summary>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <param name="parameters">请求参数</param>
|
||||
/// <param name="charset">编码字符集</param>
|
||||
/// <returns>HTTP响应</returns>
|
||||
public string DoPost(string url, IDictionary<string, string> parameters, string charset)
|
||||
{
|
||||
return AsyncHelper.RunSync(async () => await DoPostAsync(url,parameters,charset));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行HTTP POST请求。
|
||||
/// </summary>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <param name="parameters">请求参数</param>
|
||||
/// <param name="charset">编码字符集</param>
|
||||
/// <returns>HTTP响应</returns>
|
||||
public async Task<string> DoPostAsync(string url, IDictionary<string, string> parameters, string charset)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var encoding = Encoding.GetEncoding(charset);
|
||||
var client = ConnectionPool.GetClient();
|
||||
var query = new Uri(url).Query;
|
||||
var content = new StringContent(BuildQuery(parameters, charset), encoding, "application/x-www-form-urlencoded");
|
||||
|
||||
var resp = await client.PostAsync(query, content);
|
||||
var result = await resp.Content.ReadAsStringAsync();
|
||||
|
||||
ConnectionPool.ReturnClient(client);
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.ToString());
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public string DoGet(string url, IDictionary<string, string> parameters, string charset)
|
||||
{
|
||||
return AsyncHelper.RunSync(async () => await DoGetAsync(url, parameters, charset));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行HTTP GET请求。
|
||||
/// </summary>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <param name="parameters">请求参数</param>
|
||||
/// <param name="charset">编码字符集</param>
|
||||
/// <returns>HTTP响应</returns>
|
||||
public async Task<string> DoGetAsync(string url, IDictionary<string, string> parameters, string charset)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
if (parameters != null && parameters.Count > 0)
|
||||
if (url.Contains("?"))
|
||||
url = url + "&" + BuildQuery(parameters, charset);
|
||||
else
|
||||
url = url + "?" + BuildQuery(parameters, charset);
|
||||
|
||||
var query = new Uri(url).Query;
|
||||
var client = ConnectionPool.GetClient();
|
||||
var result = await client.GetStringAsync(query);
|
||||
ConnectionPool.ReturnClient(client);
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行带文件上传的HTTP POST请求。
|
||||
/// </summary>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <param name="textParams">请求文本参数</param>
|
||||
/// <param name="fileParams">请求文件参数</param>
|
||||
/// <param name="charset">编码字符集</param>
|
||||
/// <returns>HTTP响应</returns>
|
||||
public string DoPost(string url, IDictionary<string, string> textParams,
|
||||
IDictionary<string, FileItem> fileParams,
|
||||
string charset)
|
||||
{
|
||||
return AsyncHelper.RunSync(async () => await DoPostAsync(url, textParams, fileParams, charset));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行带文件上传的HTTP POST请求。
|
||||
/// </summary>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <param name="textParams">请求文本参数</param>
|
||||
/// <param name="fileParams">请求文件参数</param>
|
||||
/// <param name="charset">编码字符集</param>
|
||||
/// <returns>HTTP响应</returns>
|
||||
public async Task<string> DoPostAsync(string url, IDictionary<string, string> textParams, IDictionary<string, FileItem> fileParams,
|
||||
string charset)
|
||||
{
|
||||
// 如果没有文件参数,则走普通POST请求
|
||||
if (fileParams == null || fileParams.Count == 0)
|
||||
return await DoPostAsync(url, textParams, charset);
|
||||
|
||||
var encoding = Encoding.GetEncoding(charset);
|
||||
|
||||
var client = ConnectionPool.GetClient();
|
||||
var query = new Uri(url).Query;
|
||||
|
||||
using (var content = new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
|
||||
{
|
||||
// 组装文本请求参数
|
||||
using (var textEnum = textParams.GetEnumerator())
|
||||
{
|
||||
while (textEnum.MoveNext())
|
||||
{
|
||||
var streamContent = new StreamContent(new MemoryStream(encoding.GetBytes(textEnum.Current.Value)));
|
||||
streamContent.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
|
||||
// streamContent.Headers.ContentDisposition=new ContentDispositionHeaderValue($"form-data;name=\"logo.jpg\"");
|
||||
// streamContent.Headers.ContentDisposition=new ContentDispositionHeaderValue($"form-data;name=\"{textEnum.Current.Key}\"");
|
||||
content.Add(streamContent, textEnum.Current.Key);
|
||||
}
|
||||
}
|
||||
// 组装文件请求参数
|
||||
using (var fileEnum = fileParams.GetEnumerator())
|
||||
{
|
||||
while (fileEnum.MoveNext())
|
||||
{
|
||||
var key = fileEnum.Current.Key;
|
||||
var fileItem = fileEnum.Current.Value;
|
||||
var streamContent = new StreamContent(new MemoryStream(fileItem.GetContent()));
|
||||
streamContent.Headers.ContentType = new MediaTypeHeaderValue(fileItem.GetMimeType());
|
||||
// streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue($"form-data;name=\"{key}\";filename=\"{fileItem.GetFileName()}\"");
|
||||
content.Add(streamContent,key,fileItem.GetFileName());
|
||||
}
|
||||
}
|
||||
|
||||
var resp = await client.PostAsync(query, content);
|
||||
var result = await resp.Content.ReadAsStringAsync();
|
||||
ConnectionPool.ReturnClient(client);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 组装普通文本请求参数。
|
||||
/// </summary>
|
||||
/// <param name="parameters">Key-Value形式请求参数字典</param>
|
||||
/// <param name="charset">编码</param>
|
||||
/// <returns>URL编码后的请求数据</returns>
|
||||
public static string BuildQuery(IDictionary<string, string> parameters, string charset)
|
||||
{
|
||||
var postData = new StringBuilder();
|
||||
var hasParam = false;
|
||||
|
||||
using (var dem = parameters.GetEnumerator())
|
||||
{
|
||||
while (dem.MoveNext())
|
||||
{
|
||||
var name = dem.Current.Key;
|
||||
var value = dem.Current.Value;
|
||||
// 忽略参数名或参数值为空的参数
|
||||
if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value))
|
||||
{
|
||||
if (hasParam)
|
||||
postData.Append("&");
|
||||
|
||||
postData.Append(name);
|
||||
postData.Append("=");
|
||||
|
||||
var encodedValue = HttpUtility.UrlEncode(value, Encoding.GetEncoding(charset));
|
||||
|
||||
postData.Append(encodedValue);
|
||||
hasParam = true;
|
||||
}
|
||||
}
|
||||
|
||||
return postData.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace Alipay.AopSdk.Core.Util
|
||||
{
|
||||
internal class WebUtilsHttpConnectionPool
|
||||
{
|
||||
private readonly ConcurrentStack<HttpClient> _clients = new ConcurrentStack<HttpClient>();
|
||||
private string _url = string.Empty;
|
||||
private int _size = 1;
|
||||
private readonly object _lockObject = new object();
|
||||
private double _timeout = 60000;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 HttpClient 池
|
||||
/// </summary>
|
||||
/// <param name="url">目标域名,不带路径 比如 http://www.baidu.com </param>
|
||||
/// <param name="num">池里Client数量</param>
|
||||
public WebUtilsHttpConnectionPool(string url, int num)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
throw new ArgumentException(nameof(url));
|
||||
}
|
||||
|
||||
if (num <= 0)
|
||||
{
|
||||
throw new ArgumentException(nameof(num));
|
||||
}
|
||||
_clients.Clear();
|
||||
_url = url;
|
||||
_size = num;
|
||||
|
||||
}
|
||||
|
||||
public HttpClient GetClient()
|
||||
{
|
||||
if (_clients.TryPop(out var client))
|
||||
{
|
||||
return client;
|
||||
}
|
||||
else
|
||||
{
|
||||
var newClient = new HttpClient()
|
||||
{ BaseAddress = new Uri(_url), Timeout = TimeSpan.FromMilliseconds(_timeout) };
|
||||
newClient.DefaultRequestHeaders.Add("User-Agent", "Aop4Net");
|
||||
newClient.DefaultRequestHeaders.Add("Connection", "keep-alive");
|
||||
return newClient;
|
||||
}
|
||||
}
|
||||
|
||||
public void ReturnClient(HttpClient client)
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
if (_clients.Count >= _size)
|
||||
{
|
||||
client.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
_clients.Push(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user