钉钉审批流回调
Posted lonelyxmas
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了钉钉审批流回调相关的知识,希望对你有一定的参考价值。
原文:钉钉审批流回调
先注册回调接口(只需要调用注册回调接口一次),
using Newtonsoft.Json;
1 public void DingdingTest() 2 { 3 string accessToken = dingApp.getAccessToken(); 4 5 string code = "jiangxiaobai";//@NFine.Code.OperatorProvider.Provider.GetCurrent().UserCode; 6 var userEntry = userApp.GetList().Where(t => t.F_Account == code).FirstOrDefault(); 7 List<string> list = new List<string>(); 8 list.Add("bpms_task_change");//审批任务开始,结束,转交 9 list.Add("bpms_instance_change");//审批实例开始,结束 10 list.Add("user_leave_org"); 11 IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/call_back/register_call_back"); 12 OapiCallBackRegisterCallBackRequest request = new OapiCallBackRegisterCallBackRequest(); 16 request.Url = "http://fab.retsc.com/Receive.ashx";//17 18 request.AesKey = ding.ENCODING_AES_KEY;//("45skhqweass5232345IUJKWEDL5251054DSFdsuhfW2");//随意 19 request.Token = "123456";//随意 20 21 request.CallBackTag = list; 27 OapiCallBackRegisterCallBackResponse response = client.Execute(request, accessToken); 39 }
注册后查询
public void DingdingLook(){ IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/call_back/get_call_back"); 31 OapiCallBackGetCallBackRequest request = new OapiCallBackGetCallBackRequest(); 32 request.SetHttpMethod("GET"); 33 OapiCallBackGetCallBackResponse response = client.Execute(request, accessToken); }
新建一个后缀为.ashx的文件
1 using System; 2 using System.Collections; 3 using System.Configuration; 4 using System.IO; 5 using System.Text; 6 using System.Web; 7 using System.Web.Services; 8 using Newtonsoft.Json; 9 using DDApi; 10 using DDApi.PXTSC.COM; 11 using NFine.Code; 12 using NFine.Application.FAManage; 13 using NFine.Domain.Entity.FAManage; 14 using System.Linq; 15 16 namespace PXTWMS.Web 17 { 18 /// <summary> 19 /// Receive 的摘要说明 20 /// </summary> 21 public class Receive : IHttpHandler 22 { 23 //ILog logger = LogManager.GetLogger(typeof(Receive)); 24 private NFine.Code.Log log = LogFactory.GetLogger("ReceiveError"); 25 26 private string GetPostParam(HttpContext context) 27 { 28 if ("POST" == context.Request.RequestType) 29 { 30 Stream sm = context.Request.InputStream;//获取post正文 31 int len = (int)sm.Length;//post数据长度 32 byte[] inputByts = new byte[len];//字节数据,用于存储post数据 33 sm.Read(inputByts, 0, len);//将post数据写入byte数组中 34 sm.Close();//关闭IO流 35 36 //**********下面是把字节数组类型转换成字符串********** 37 38 string data = Encoding.UTF8.GetString(inputByts);//转为String 39 data = data.Replace("{"encrypt":"", "").Replace(""}", ""); 40 return data; 41 } 42 return "get方法"; 43 } 44 45 46 47 public void ProcessRequest(HttpContext context) 48 { 49 // context.Response.ContentType = "text/plain"; 50 // context.Response.Write("Hello World"); 51 52 try 53 { 54 #region 获取套件配置参数 55 string mToken = DDApi.PXTSC.COM.ding.Token ;// ConfigurationManager.AppSettings["Token"]; 56 string mSuiteKey = DDApi.PXTSC.COM.ding.Corpid; 57 string mEncodingAesKey = DDApi.PXTSC.COM.ding.ENCODING_AES_KEY;// ConfigurationManager.AppSettings["EncodingAESKey"]; 58 //mSuiteKey = "suite4xxxxxxxxxxxxxxx"; 59 #endregion 60 61 #region 获取回调URL里面的参数 62 //url中的签名 63 string msgSignature = context.Request["signature"]; 64 //url中的时间戳 65 string timeStamp = context.Request["timestamp"]; 66 //url中的随机字符串 67 string nonce = context.Request["nonce"]; 68 //post数据包数据中的加密数据 69 string encryptStr = GetPostParam(context); 70 #endregion 71 72 string sEchoStr = ""; 73 74 #region 验证回调的url 75 76 DDApi.PXTSC.COM.DingTalkCrypt dingTalk = new DingTalkCrypt(mToken, mEncodingAesKey, mSuiteKey); 77 78 var ret = dingTalk.VerifyURL(msgSignature, timeStamp, nonce, encryptStr, ref sEchoStr); 79 80 // var ret = dingTalk.VerifyURL(mToken, mEncodingAesKey, msgSignature, timeStamp, nonce, encryptStr, ref mSuiteKey); 81 82 if (ret != 0) 83 { 84 log.Error("ERR: VerifyURL fail, ret: " + ret); 85 return; 86 } 87 #endregion 88 89 #region 90 //构造DingTalkCrypt 91 // DingTalkCrypt dingTalk = new DingTalkCrypt(mToken, mEncodingAesKey, mSuiteKey); 92 93 string plainText = ""; 94 dingTalk.DecryptMsg(msgSignature, timeStamp, nonce, encryptStr, ref plainText); 95 Hashtable tb = (Hashtable)JsonConvert.DeserializeObject(plainText, typeof(Hashtable)); 96 string eventType = tb["EventType"].ToString(); 97 string res = "success"; 98 log.Error("plainText:" + plainText); 99 log.Info("eventType:" + eventType); 100 switch (eventType) 101 { 102 case "suite_ticket"://定时推送Ticket 103 ConfigurationManager.AppSettings["SuiteTicket"] = tb["SuiteTicket"].ToString(); 104 mSuiteKey = tb["SuiteKey"].ToString(); 105 // dingTalk.SaveSuiteTicket(tb); 106 break; 107 case "tmp_auth_code"://钉钉推送过来的临时授权码 108 ConfigurationManager.AppSettings["TmpAuthCode"] = tb["AuthCode"].ToString(); 109 // dingTalk.SaveTmpAuthCode(tb); 110 break; 111 case "change_auth":// do something; 112 break; 113 case "check_update_suite_url": 114 res = tb["Random"].ToString(); 115 mSuiteKey = tb["TestSuiteKey"].ToString(); 116 break; 117 case "bpms_task_change"://审批任务开始,结束,转交 118 119 break; 120 case "bpms_instance_change"://审批实例开始,结束 121 string processCode = tb["processCode"].ToString(); 122 if (processCode== "PROC-13AFD99D-97F7-4893-8C5D-E612B960BBBC") 123 { 124 string processInstanceId = tb["processInstanceId"].ToString();//审批实例ID 125 var a = ding.getProcessInstance(processInstanceId); 126 var b = a.ProcessInstance; 127 if (b.Status== "COMPLETED") 128 { 129 foreach (var item in b.FormComponentValues) 130 { 131 if (item.Name=="调拨单号") 132 { 133 string sheetno = item.Value; 134 TransMasterApp tApp = new TransMasterApp(); 135 var bill = tApp.GetList().Where(t => t.F_SHEETNO == sheetno).FirstOrDefault(); 136 bill.F_STATUS = 10; 137 tApp.UpdateForm(bill); 138 } 139 } 140 } 141 else if(b.Status == "TERMINATED") 142 { 143 foreach (var item in b.FormComponentValues) 144 { 145 if (item.Name == "调拨单号") 146 { 147 string sheetno = item.Value; 148 TransMasterApp tApp = new TransMasterApp(); 149 var bill = tApp.GetList().Where(t => t.F_SHEETNO == sheetno).FirstOrDefault(); 150 bill.F_STATUS = 11; 151 tApp.UpdateForm(bill); 152 } 153 } 154 } 155 } 156 break; 157 } 158 159 timeStamp = NFine.Code.DateTimeUtil.DateTimeToTimeStamp(DateTime.Now).ToString(); 160 string encrypt = ""; 161 string signature = ""; 162 dingTalk = new DingTalkCrypt(mToken, mEncodingAesKey, mSuiteKey); 163 dingTalk.EncryptMsg(res, timeStamp, nonce, ref encrypt, ref signature); 164 Hashtable jsonMap = new Hashtable 165 { 166 {"msg_signature", signature}, 167 {"encrypt", encrypt}, 168 {"timeStamp", timeStamp}, 169 {"nonce", nonce} 170 }; 171 string result = JsonConvert.SerializeObject(jsonMap); 172 context.Response.Write(result); 173 #endregion 174 } 175 catch (Exception ex) 176 { 177 log.Error(ex.Message); 178 179 } 180 181 182 } 183 184 public bool IsReusable 185 { 186 get 187 { 188 return false; 189 } 190 } 191 192 193 } 194 }
获取时间戳的方法
/// <summary> /// DateTime转换为10位时间戳(单位:秒) /// </summary> /// <param name="dateTime"> DateTime</param> /// <returns>10位时间戳(单位:秒)</returns> public static long DateTimeToTimeStamp(DateTime dateTime) { return (long)(dateTime.ToUniversalTime() - timeStampStartTime).TotalSeconds; }
必要的两个类,
using System; using System.Collections; using System.Security.Cryptography; using System.Text; namespace DDApi.PXTSC.COM { /// <summary> /// 加密类 /// </summary> public class DingTalkCrypt { private string m_sEncodingAESKey; private string m_sToken; private string m_sSuiteKey; /**ask getPaddingBytes key固定长度**/ private static int AES_ENCODE_KEY_LENGTH = 43; /**加密随机字符串字节长度**/ //private static int RANDOM_LENGTH = 16; enum DingTalkCryptErrorCode { /**成功**/ SUCCESS = 0, /**加密明文文本非法**/ ENCRYPTION_PLAINTEXT_ILLEGAL = 900001, /**加密时间戳参数非法**/ ENCRYPTION_TIMESTAMP_ILLEGAL = 900002, /**加密随机字符串参数非法**/ ENCRYPTION_NONCE_ILLEGAL = 900003, /**不合法的aeskey**/ AES_KEY_ILLEGAL = 900004, /**签名不匹配**/ SIGNATURE_NOT_MATCH = 900005, /**计算签名错误**/ COMPUTE_SIGNATURE_ERROR = 900006, /**计算加密文字错误**/ COMPUTE_ENCRYPT_TEXT_ERROR = 900007, /**计算解密文字错误**/ COMPUTE_DECRYPT_TEXT_ERROR = 900008, /**计算解密文字长度不匹配**/ COMPUTE_DECRYPT_TEXT_LENGTH_ERROR = 900009, /**计算解密文字suiteKey不匹配**/ COMPUTE_DECRYPT_TEXT_SuiteKey_ERROR = 900010, }; /// <summary> /// 构造函数 /// </summary> /// <param name="token">钉钉开放平台上,开发者设置的token</param> /// <param name="encodingAesKey">钉钉开放台上,开发者设置的EncodingAESKey</param> /// <param name="suiteKey">钉钉开放平台上,开发者设置的suiteKey</param> public DingTalkCrypt(string token, string encodingAesKey, string suiteKey) { m_sToken = token; m_sSuiteKey = suiteKey; m_sEncodingAESKey = encodingAesKey; } /// <summary> /// 将消息加密,返回加密后字符串 /// </summary> /// <param name="sReplyMsg">传递的消息体明文</param> /// <param name="sTimeStamp">时间戳</param> /// <param name="sNonce">随机字符串</param> /// <param name="sEncryptMsg">加密后的消息信息</param> /// <returns>成功0,失败返回对应的错误码</returns> public int EncryptMsg(string sReplyMsg, string sTimeStamp, string sNonce, ref string sEncryptMsg, ref string signature) { if (string.IsNullOrEmpty(sReplyMsg)) return (int)DingTalkCryptErrorCode.ENCRYPTION_PLAINTEXT_ILLEGAL; if (string.IsNullOrEmpty(sTimeStamp)) return (int)DingTalkCryptErrorCode.ENCRYPTION_TIMESTAMP_ILLEGAL; if (string.IsNullOrEmpty(sNonce)) return (int)DingTalkCryptErrorCode.ENCRYPTION_NONCE_ILLEGAL; if (m_sEncodingAESKey.Length != AES_ENCODE_KEY_LENGTH) return (int)DingTalkCryptErrorCode.AES_KEY_ILLEGAL; string raw = ""; try { raw = CropCrytography.AES_encrypt(sReplyMsg, m_sEncodingAESKey, m_sSuiteKey); } catch (Exception) { return (int)DingTalkCryptErrorCode.AES_KEY_ILLEGAL; } string msgSigature = ""; int ret = GenerateSignature(m_sToken, sTimeStamp, sNonce, raw, ref msgSigature); sEncryptMsg = raw; signature = msgSigature; return ret; } /// <summary> /// 密文解密 /// </summary> /// <param name="sMsgSignature">签名串</param> /// <param name="sTimeStamp">时间戳</param> /// <param name="sNonce">随机串</param> /// <param name="sPostData">密文</param> /// <param name="sMsg">解密后的原文,当return返回0时有效</param> /// <returns>成功0,失败返回对应的错误码</returns> public int DecryptMsg(string sMsgSignature, string sTimeStamp, string sNonce, string sPostData, ref string sMsg) { if (m_sEncodingAESKey.Length != AES_ENCODE_KEY_LENGTH) return (int)DingTalkCryptErrorCode.AES_KEY_ILLEGAL; string sEncryptMsg = sPostData; int ret = VerifySignature(m_sToken, sTimeStamp, sNonce, sEncryptMsg, sMsgSignature); string cpid = ""; try { sMsg = CropCrytography.AES_decrypt(sEncryptMsg, m_sEncodingAESKey, ref cpid); } catch (FormatException) { sMsg = ""; return (int)DingTalkCryptErrorCode.COMPUTE_DECRYPT_TEXT_SuiteKey_ERROR; } catch (Exception) { sMsg = ""; return (int)DingTalkCryptErrorCode.COMPUTE_DECRYPT_TEXT_SuiteKey_ERROR; } if (cpid != m_sSuiteKey) return (int)DingTalkCryptErrorCode.COMPUTE_DECRYPT_TEXT_SuiteKey_ERROR; return ret; } /// <summary> /// 生成签名 /// </summary> /// <param name="sToken"></param> /// <param name="sTimeStamp"></param> /// <param name="sNonce"></param> /// <param name="sMsgEncrypt"></param> /// <param name="sMsgSignature"></param> /// <returns></returns> public int GenerateSignature(string sToken, string sTimeStamp, string sNonce, string sMsgEncrypt, ref string sMsgSignature) { ArrayList AL = new ArrayList(); AL.Add(sToken); AL.Add(sTimeStamp); AL.Add(sNonce); AL.Add(sMsgEncrypt); AL.Sort(new DictionarySort()); string raw = ""; for (int i = 0; i < AL.Count; ++i) { raw += AL[i]; } SHA1 sha; ASCIIEncoding enc; string hash = ""; try { sha = new SHA1CryptoServiceProvider(); enc = new ASCIIEncoding(); byte[] dataToHash = enc.GetBytes(raw); byte[] dataHashed = sha.ComputeHash(dataToHash); hash = BitConverter.ToString(dataHashed).Replace("-", ""); hash = hash.ToLower(); } catch (Exception) { return (int)DingTalkCryptErrorCode.COMPUTE_SIGNATURE_ERROR; } sMsgSignature = hash; return 0; } /// <summary> /// 验证签名 /// </summary> /// <param name="sToken"></param> /// <param name="sTimeStamp"></param> /// <param name="sNonce"></param> /// <param name="sMsgEncrypt"></param> /// <param name="sSigture"></param> /// <returns></returns> public int VerifySignature(string sToken, string sTimeStamp, string sNonce, string sMsgEncrypt, string sSigture) { string hash = ""; int ret = 0; ret = GenerateSignature(sToken, sTimeStamp, sNonce, sMsgEncrypt, ref hash); if (ret != 0) return ret; if (hash == sSigture) return 0; else { return (int)DingTalkCryptErrorCode.SIGNATURE_NOT_MATCH; } } /// <summary> /// 验证URL /// </summary> /// <param name="sMsgSignature">签名串,对应URL参数的msg_signature</param> /// <param name="sTimeStamp">时间戳,对应URL参数的timestamp</param> /// <param name="sNonce">随机串,对应URL参数的nonce</param> /// <param name="sEchoStr">经过加密的消息体,对应URL参数的encrypt</param> /// <param name="sReplyEchoStr"></param> /// <returns></returns> public int VerifyURL(string sMsgSignature, string sTimeStamp, string sNonce, string sEchoStr, ref string sReplyEchoStr) { int ret = 0; if (m_sEncodingAESKey.Length != 43) { return (int)DingTalkCryptErrorCode.AES_KEY_ILLEGAL; } ret = VerifySignature(m_sToken, sTimeStamp, sNonce, sEchoStr, sMsgSignature); sReplyEchoStr = ""; string cpid = ""; try { sReplyEchoStr = CropCrytography.AES_decrypt(sEchoStr, m_sEncodingAESKey, ref cpid); //m_sCorpID); } catch (Exception) { sReplyEchoStr = ""; return (int)DingTalkCryptErrorCode.COMPUTE_SIGNATURE_ERROR; } if (cpid != m_sSuiteKey) { sReplyEchoStr = ""; return (int)DingTalkCryptErrorCode.COMPUTE_DECRYPT_TEXT_SuiteKey_ERROR; } return ret; } /// <summary> /// 字典排序 /// </summary> public class DictionarySort : System.Collections.IComparer { public int Compare(object oLeft, object oRight) { string sLeft = oLeft as string; string sRight = oRight as string; int iLeftLength = sLeft.Length; int iRightLength = sRight.Length; int index = 0; while (index < iLeftLength && index < iRightLength) { if (sLeft[index] < sRight[index]) return -1; else if (sLeft[index] > sRight[index]) return 1; else index++; } return iLeftLength - iRightLength; } } } }
using System; using System.IO; using System.Net; using System.Security.Cryptography; using System.Text; namespace DDApi.PXTSC.COM { /// <summary> /// 加密 /// </summary> public class CropCrytography { public static UInt32 HostToNetworkOrder(UInt32 inval) { UInt32 outval = 0; for (int i = 0; i < 4; i++) outval = (outval << 8) + ((inval >> (i * 8)) & 255); return outval; } public static Int32 HostToNetworkOrder(Int32 inval) { Int32 outval = 0; for (int i = 0; i < 4; i++) outval = (outval << 8) + ((inval >> (i * 8)) & 255); return outval; } /// <summary> /// 解密方法 /// </summary> /// <param name="Input">密文</param> /// <param name="EncodingAESKey"></param> /// <returns></returns> /// public static string AES_decrypt(string Input, string EncodingAESKey, ref string corpid) { byte[] Key; Key = Convert.FromBase64String(EncodingAESKey + "="); byte[] Iv = new byte[16]; Array.Copy(Key, Iv, 16); byte[] btmpMsg = AES_decrypt(Input, Iv, Key); int len = BitConverter.ToInt32(btmpMsg, 16); len = IPAddress.NetworkToHostOrder(len); byte[] bMsg = new byte[len]; byte[] bCorpid = new byte[btmpMsg.Length - 20 - len]; Array.Copy(btmpMsg, 20, bMsg, 0, len); Array.Copy(btmpMsg, 20 + len, bCorpid, 0, btmpMsg.Length - 20 - len); string oriMsg = Encoding.UTF8.GetString(bMsg); corpid = Encoding.UTF8.GetString(bCorpid); return oriMsg; } /// <summary> /// 加密方法 /// </summary> /// <param name="Input"></param> /// <param name="EncodingAESKey"></param> /// <param name="corpid"></param> /// <returns></returns> public static string AES_encrypt(string Input, string EncodingAESKey, string corpid) { byte[] Key; Key = Convert.FromBase64String(EncodingAESKey + "="); byte[] Iv = new byte[16]; Array.Copy(Key, Iv, 16); string Randcode = CreateRandCode(16); byte[] bRand = Encoding.UTF8.GetBytes(Randcode); byte[] bCorpid = Encoding.UTF8.GetBytes(corpid); byte[] btmpMsg = Encoding.UTF8.GetBytes(Input); byte[] bMsgLen = BitConverter.GetBytes(HostToNetworkOrder(btmpMsg.Length)); byte[] bMsg = new byte[bRand.Length + bMsgLen.Length + bCorpid.Length + btmpMsg.Length]; Array.Copy(bRand, bMsg, bRand.Length); Array.Copy(bMsgLen, 0, bMsg, bRand.Length, bMsgLen.Length); Array.Copy(btmpMsg, 0, bMsg, bRand.Length + bMsgLen.Length, btmpMsg.Length); Array.Copy(bCorpid, 0, bMsg, bRand.Length + bMsgLen.Length + btmpMsg.Length, bCorpid.Length); return AES_encrypt(bMsg, Iv, Key); } public static string CreateRandCode(int codeLen) { string codeSerial = "2,3,4,5,6,7,a,c,d,e,f,h,i,j,k,m,n,p,r,s,t,A,C,D,E,F,G,H,J,K,M,N,P,Q,R,S,U,V,W,X,Y,Z"; if (codeLen == 0) { codeLen = 16; } string[] arr = codeSerial.Split(‘,‘); string code = ""; int randValue = -1; Random rand = new Random(unchecked((int)DateTime.Now.Ticks)); for (int i = 0; i < codeLen; i++) { randValue = rand.Next(0, arr.Length - 1); code += arr[randValue]; } return code; } private static string AES_encrypt(string Input, byte[] Iv, byte[] Key) { var aes = new RijndaelManaged(); //秘钥的大小,以位为单位 aes.KeySize = 256; //支持的块大小 aes.BlockSize = 128; //填充模式 aes.Padding = PaddingMode.PKCS7; aes.Mode = CipherMode.CBC; aes.Key = Key; aes.IV = Iv; var encrypt = aes.CreateEncryptor(aes.Key, aes.IV); byte[] xBuff = null; using (var ms = new MemoryStream()) { using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write)) { byte[] xXml = Encoding.UTF8.GetBytes(Input); cs.Write(xXml, 0, xXml.Length); } xBuff = ms.ToArray(); } string Output = Convert.ToBase64String(xBuff); return Output; } private static string AES_encrypt(byte[] Input, byte[] Iv, byte[] Key) { var aes = new RijndaelManaged(); //秘钥的大小,以位为单位 aes.KeySize = 256; //支持的块大小 aes.BlockSize = 128; //填充模式 //aes.Padding = PaddingMode.PKCS7; aes.Padding = PaddingMode.None; aes.Mode = CipherMode.CBC; aes.Key = Key; aes.IV = Iv; var encrypt = aes.CreateEncryptor(aes.Key, aes.IV); byte[] xBuff = null; #region 自己进行PKCS7补位,用系统自己带的不行 byte[] msg = new byte[Input.Length + 32 - Input.Length % 32]; Array.Copy(Input, msg, Input.Length); byte[] pad = KCS7Encoder(Input.Length); Array.Copy(pad, 0, msg, Input.Length, pad.Length); #endregion #region 注释的也是一种方法,效果一样 //ICryptoTransform transform = aes.CreateEncryptor(); //byte[] xBuff = transform.TransformFinalBlock(msg, 0, msg.Length); #endregion using (var ms = new MemoryStream()) { using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write)) { cs.Write(msg, 0, msg.Length); } xBuff = ms.ToArray(); } string Output = Convert.ToBase64String(xBuff); return Output; } public static byte[] KCS7Encoder(int text_length) { int block_size = 32; // 计算需要填充的位数 int amount_to_pad = block_size - (text_length % block_size); if (amount_to_pad == 0) { amount_to_pad = block_size; } // 获得补位所用的字符 char pad_chr = chr(amount_to_pad); string tmp = ""; for (int index = 0; index < amount_to_pad; index++) { tmp += pad_chr; } return Encoding.UTF8.GetBytes(tmp); } /** * 将数字转化成ASCII码对应的字符,用于对明文进行补码 * * @param a 需要转化的数字 * @return 转化得到的字符 */ static char chr(int a) { byte target = (byte)(a & 0xFF); return (char)target; } private static byte[] AES_decrypt(string Input, byte[] Iv, byte[] Key) { RijndaelManaged aes = new RijndaelManaged(); aes.KeySize = 256; aes.BlockSize = 128; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.None; aes.Key = Key; aes.IV = Iv; var decrypt = aes.CreateDecryptor(aes.Key, aes.IV); byte[] xBuff = null; using (var ms = new MemoryStream()) { using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write)) { byte[] xXml = Convert.FromBase64String(Input); byte[] msg = new byte[xXml.Length + 32 - xXml.Length % 32]; Array.Copy(xXml, msg, xXml.Length); cs.Write(xXml, 0, xXml.Length); } xBuff = decode2(ms.ToArray()); } return xBuff; } private static byte[] decode2(byte[] decrypted) { int pad = (int)decrypted[decrypted.Length - 1]; if (pad < 1 || pad > 32) { pad = 0; } byte[] res = new byte[decrypted.Length - pad]; Array.Copy(decrypted, 0, res, 0, decrypted.Length - pad); return res; } } }
以上是关于钉钉审批流回调的主要内容,如果未能解决你的问题,请参考以下文章