文章目录

  • 前言
    • 1.cpolar简介
    • 2.cpolar功能
  • 一、无公网IP异地远程连接内网群晖NAS【内网穿透】
    • 1.1 注册cpolar账号
    • 1.2 下载cpolar客户端进行内网穿透
    • 1.3 进行钉钉回调事件的监听测试
    • 1.4 进行钉钉回调事件的监听的源码解析如下
      • 1.4.1 控制器代码
      • 1.4.2 相关加解密代码

前言

1.cpolar简介

cpolar是一款拥有远程控制和内网穿透功能的软件。而且还可以监控端口的HTTP请求,利用实时的cpolar Web UI开发者工具,让您调试代码更容易。您可以监听所有隧道上的HTTP消息包,分析消息包的结构内容,找出问题点。还可以单击重放(Replay)按钮,重新发送该HTTP信令请求。

2.cpolar功能

1、个人使用场景:

  • 远程桌面访问公司电脑
  • 远程方面家中电脑
  • 搭建私人Web站点

2、中小企业远程办公场景:

  • 远程桌面(个人或公司使用)
  • 远程访问文件共享服务器(中小企业使用)
  • 远程访问公司内网财务系统、进销存系统、ERP系统(小中企业使用)

3、游戏玩家使用场景:

  • 搭建个人游戏私服

4、群晖NAS(个人网络存储服务器)用户使用

  • 远程访问家中的NAS文件服务器Web管理界面
  • 远程文件共享服务
  • 远程用手机看视频(通过手机或PC远程访问家中的视频文件库,观看小姐姐)
  • 为啥要用远程,因为NAS服务器通常也是BT迅雷下载服务器,小姐姐或电影都存在这上面。

5、开发人员使用场景:

  • 搭建Web站点,用于测试,用于给客户演示场景
  • 联调公网API服务,例如远程调试支付宝接口
  • 联调开发微信公众号,小程序接口
  • 远程访问数据库
  • 搭建私有git源代码仓库
  • 搭建私有CI服务器
  • 搭建私有SVN源代码服务器
  • 远程SSH服务器家中的服务器,或者公司的服务器
  • 远程使用vs code编辑代码

6、批量商业使用场景:

  • 开发智能终端的用户,希望在他们开发的每个终端上,都安装cpolar,用于可以随时ssh远程访问的能力。例如,初期100台设备上安装(试生产),成功后,再部署到1-4万台设备上。
  • 企业用户,希望在公司的每台电脑上,都配置远程桌面功能,访问疫情期间,远程办公方便。
  • 有一个店家,有5个店,他是老板,但他并不希望每次都跑过去查看电脑上的财务数据。可以安装cpolar到这5个店的电脑中,他只要在家中,远程访问即可。
  • 私有云服务,企业希望打造一套自己的内网穿透系统,独立搭建一套私有云服务。

一、无公网IP异地远程连接内网群晖NAS【内网穿透】

1.1 注册cpolar账号

官网链接:https://i.cpolar.com/m/4VfC

进入cpolar官网,我们先点击右上角的免费注册,使用邮箱注册一个账号,我们后面会需要用到。

1.2 下载cpolar客户端进行内网穿透


下载完一路安装就好了,安装完成进入安装的文件夹执行注册,注册的命令如下:


cpolar authtoken <YOUR_AUTH_TOKEN>
cpolar http 5000

执行成功界面如下

访问网址:https://458ed76c.vip.cpolar.cn/swagger/index.html


内网swagger映射成功

1.3 进行钉钉回调事件的监听测试

进入钉钉后台管理注册事件订阅

进行保存后端断点收到钉钉发过来信息,支持内网应用程序和钉钉已经进行互通了

1.4 进行钉钉回调事件的监听的源码解析如下

1.4.1 控制器代码

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using NSwag.Annotations;
using System.Collections;
using YG.Monomer.Framework.Controllers.Other_Manage.DingDing;
using YG.Monomer.Framework.Filters.格式化返回结果;namespace YG.Monomer.Framework.Controllers.Other_Manage
{[Route("/Other_Manage/[controller]/[action]")][OpenApiTag("第三方回调-钉钉事件监听")]public class DDCallBackController : BaseApiController{private readonly IConfiguration Configuration;/// <summary>/// 日志注入/// </summary>/// <param name="loggerFactory"></param>public DDCallBackController(IConfiguration configuration){Configuration = configuration;}[HttpGet][AllowAnonymous][NoFormatResponse]public string ReadConfig(){return Configuration["DingDing:Token"];}/// <summary>/// 钉钉注册的回调地址/// </summary>/// <param name="signature"></param>/// <param name="timestamp"></param>/// <param name="nonce"></param>/// <param name="body"></param>/// <returns></returns>[HttpPost][AllowAnonymous][NoFormatResponse]public dynamic CallBack(string signature, string timestamp, string nonce, PostBody body){//接收encrypt参数string encryptStr = body.encrypt.Replace("{\"encrypt\":\"", "").Replace("\"}", "");//注册时填写的token、aes_key、suitekeystring token = Configuration["DingDing:Token"];string aes_key = Configuration["DingDing:AesKey"];string suitekey = Configuration["DingDing:Suitekey"];#region 验证回调的urlDingTalkCrypt dingTalk = new DingTalkCrypt(token, aes_key, suitekey);string sEchoStr = "";dingTalk.VerifyURL(signature, timestamp, nonce, encryptStr, ref sEchoStr);#endregion#region 解密接受信息,进行事件处理string plainText = "";dingTalk.DecryptMsg(signature, timestamp, nonce, encryptStr, ref plainText);Hashtable tb = (Hashtable)JsonConvert.DeserializeObject(plainText, typeof(Hashtable))!;string eventType = tb["EventType"].ToString()!;//string processCode = tb["processCode"] == null ? null : tb["processCode"].ToString();//任务码string res = "success";switch (eventType){case "bpms_instance_change"://审批实例改变,执行代码#region 审批实例改变,执行代码//if (processCode == Configuration["PurProcessCode"])//{//    _purdemitem.AddPurDem(_dDHelper.GetProcessInstance(tb["processInstanceId"].ToString()));//}#endregionbreak;default:break;}timestamp = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds).ToString();string encrypt = "";string signature2 = "";dingTalk = new DingTalkCrypt(token, aes_key, suitekey);//返回成功信息dingTalk.EncryptMsg(res, timestamp, nonce, ref encrypt, ref signature2);Hashtable jsonMap = new Hashtable{{"msg_signature", signature2},{"encrypt", encrypt},{"timeStamp", timestamp},{"nonce", nonce}};return JsonConvert.SerializeObject(jsonMap);#endregion}}/// <summary>/// 钉钉解密消息体/// </summary>public class PostBody{/// <summary>/// 密文/// </summary>public string? encrypt { get; set; }}
}

1.4.2 相关加解密代码

AESHepler.cs

using System.Net;
using System.Security.Cryptography;
using System.Text;
namespace YG.Monomer.Framework.Controllers.Other_Manage.DingDing
{/// <summary>/// 钉钉加解密库/// </summary>public class AESHepler{/// <summary>/// 加密/// </summary>/// <param name="input">原文</param>/// <param name="aesKey">AES密钥</param>/// <param name="corpid">企业CorpId</param>/// <returns></returns>public static string AESEncrypt(string input, string aesKey, string corpid){byte[] Key;Key = Convert.FromBase64String(aesKey + "=");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 AESEncrypt(bMsg, Key, Iv);}/// <summary>/// 解密/// </summary>/// <param name="input">密文</param>/// <param name="aesKey">AES密钥</param>/// <param name="corpId"></param>/// <returns></returns>public static string AESDecrypt(string input, string aesKey, ref string corpId){byte[] Key;Key = Convert.FromBase64String(aesKey + "=");byte[] Iv = new byte[16];Array.Copy(Key, Iv, 16);byte[] btmpMsg = null;using (var aesAlg = Aes.Create()){aesAlg.KeySize = 256;aesAlg.BlockSize = 128;aesAlg.Padding = PaddingMode.None;aesAlg.Mode = CipherMode.CBC;using (var decryptor = aesAlg.CreateDecryptor(Key, Iv)){using (var ms = new MemoryStream()){using (var cs = new CryptoStream(ms, decryptor, 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);}btmpMsg = decode2(ms.ToArray());}}}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="key">密钥</param>/// <param name="iv">IV偏移量</param>/// <returns></returns>public static string AESEncrypt(byte[] input, byte[] key, byte[] iv){using (var aesAlg = Aes.Create()){aesAlg.KeySize = 256;aesAlg.BlockSize = 128;aesAlg.Padding = PaddingMode.None;aesAlg.Mode = CipherMode.CBC;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);byte[] xBuff = null;using (var encryptor = aesAlg.CreateEncryptor(key, iv)){using (var msEncrypt = new MemoryStream()){using (var ms = new MemoryStream()){using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)){cs.Write(msg, 0, msg.Length);}xBuff = ms.ToArray();}return Convert.ToBase64String(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;}/// <summary>/// /// </summary>/// <param name="codeLen"></param>/// <returns></returns>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;}/// <summary>/// /// </summary>/// <param name="inval"></param>/// <returns></returns>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;}/// <summary>/// /// </summary>/// <param name="inval"></param>/// <returns></returns>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;}private 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);}static char chr(int a){byte target = (byte)(a & 0xFF);return (char)target;}}
}

Cryptography.cs

using System.Text;namespace YG.Monomer.Framework.Controllers.Other_Manage.DingDing
{/// <summary>/// /// </summary>public class Cryptography{/// <summary>/// /// </summary>/// <param name="inval"></param>/// <returns></returns>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;}/// <summary>/// /// </summary>/// <param name="inval"></param>/// <returns></returns>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>/// <param name="corpid"></param>/// <returns></returns>public static string AES_decrypt(String Input, string EncodingAESKey, ref string corpid){//扩展改造成Core版AES解密算法return AESHepler.AESDecrypt(Input, EncodingAESKey, ref corpid);}/// <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);}private 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(byte[] Input, byte[] Iv, byte[] Key){//扩展改造成Core版AES加密算法return AESHepler.AESEncrypt(Input, Key, Iv);}private 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[] 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;}}
}

DingTalkCrypt.cs

using System.Collections;
using System.Security.Cryptography;
using System.Text;
namespace YG.Monomer.Framework.Controllers.Other_Manage.DingDing
{/// <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>/// <param name="signature"></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 = Cryptography.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 = Cryptography.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 static 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 = SHA1.Create();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>private static 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 = Cryptography.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{/// <summary>/// /// </summary>/// <param name="oLeft"></param>/// <param name="oRight"></param>/// <returns></returns>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;elseindex++;}return iLeftLength - iRightLength;}}}
}

DDHelper.cs 这边是进行钉钉主业务的类

using AlibabaCloud.SDK.Dingtalkoauth2_1_0;
using AlibabaCloud.OpenApiClient.Models;
using AlibabaCloud.SDK.Dingtalkoauth2_1_0.Models;
using Tea;namespace YG.Monomer.Framework.Controllers.Other_Manage.DingDing
{/// <summary>/// 钉钉SDK相关方法/// </summary>public class DDHelper{readonly IConfiguration Configuration;/// <summary>/// 钉钉SDK构造函数/// </summary>/// <param name="configuration"></param>public DDHelper(IConfiguration configuration){Configuration = configuration;}/*** 使用 Token 初始化账号Client* @return Client* @throws Exception*/public static Client CreateClient(){Config config = new Config();config.Protocol = "https";config.RegionId = "central";return new Client(config);}/// <summary>/// 获取钉钉授权token,带着就可以访问任何接口了/// </summary>/// <returns></returns>public string? GetAccessToken(){Client client = CreateClient();GetAccessTokenRequest getAccessTokenRequest = new GetAccessTokenRequest{AppKey = Configuration["DingDing:AppKey"],AppSecret = Configuration["DingDing:AppSecret"],};try{return client.GetAccessToken(getAccessTokenRequest).Body.AccessToken;}catch (TeaException err){if (!AlibabaCloud.TeaUtil.Common.Empty(err.Code) && !AlibabaCloud.TeaUtil.Common.Empty(err.Message)){// err 中含有 code 和 message 属性,可帮助开发定位问题}}catch (Exception _err){TeaException err = new TeaException(new Dictionary<string, object>{{ "message", _err.Message }});if (!AlibabaCloud.TeaUtil.Common.Empty(err.Code) && !AlibabaCloud.TeaUtil.Common.Empty(err.Message)){// err 中含有 code 和 message 属性,可帮助开发定位问题}}return null;}}
}

【愚公系列】2022年10月 .Net Core使用cpolar内网穿透功能实现钉钉回调事件的监听相关推荐

  1. 推荐10款简单好用的免费内网穿透工具

    远程办公越来越普遍,但是如何应对在外远程桌面控制公司电脑.远程公司内网办公系统.调阅公司文件资料.远程公司内网服务器是个问题.而解决方案其实很简单,做内网穿透就可以突破局域网的限制,轻松实现公网访问内 ...

  2. 【愚公系列】2022年01月 华为鸿蒙OS-03-四种模式开发实操

    文章目录 前言 一.使用JS语言开发(传统代码方式) 1.index页面源码 2.details页面源码 二.使用JS语言开发(低代码方式) 1.新建工程:注意选择 2.选择低代码新建页面 3.页面分 ...

  3. 一周速递|全球车联网产业动态(2022年10月16日)

    政策法规 1.10月13日,上海市经济信息化委透露,上海将加快智能网联汽车终端发展,力争到2025年塑造3个以上具有上海标识度的品牌,打造10款以上爆款产品,产值达到5000亿元,具有辅助自动驾驶功能 ...

  4. 2022年10月30日马丁·加德纳聚会线上活动重磅来袭!

    早点关注我,精彩不错过! 随着秋风的日益清冷,一年一度的马丁·加德纳聚会悄然而至,这红叶纷飞的十月,恰是数学爱好者们期盼的欢聚时刻. 聚会时间:2022年10月30号全天 形式:腾讯线上会议. 地点: ...

  5. 关于2022年10月谷歌浏览器无法使用翻译功能的解决办法

    关于2022年10月谷歌浏览器无法使用翻译功能的解决办法 具体步骤 1.运行CMD(以管理员身份运行) 2.输入下面的代码 echo 203.208.40.66 translate.googleapi ...

  6. 李迟2022年10月工作生活总结

    本文为 2022 年 10 月工作生活总结. 研发编码 Go 判断interface{}是否为空 判断interface{}类型是否为空,不能直接使用==nil来判断(用之无效),需先用reflect ...

  7. 携创教育:2022年10月自考英语二高分技巧有哪些?

    自考英语二是水平性考试,60分及格,不是选拔性考试,跟我们一起备考的同学不是竞争对手,而是自考路上风雨相伴的战友. 今天小编整理了自考英语二的高分技巧,一起来看看吧! 2022年10月自考英语二高分技 ...

  8. CNAS 实验室认可规范文件清单 (截止2022年10月1日)

    CNAS 实验室认可规范文件清单 (截止2022年10月1日) 序号 类别 文件编号 文件名称 发布日期 实施日期 被代替文件 备注 注:有效文件发布实施日期 文件编号/文件名 旧文件废止时间 1 通 ...

  9. 2022年10月各大学网络教育统考大学英语B考试复习题库及辅导

    自2022年起,网络教育统考将不再由网考办统一组织全国统考,网络统考已由各高校自行组织:2022年10月部分高校已发布了统考通知,截止目前,已发布10月统考的院校有:2022年10月东北师范大学网络教 ...

  10. 这些环保相关的标准和规范自2022年10月起实施

    从2022年10月1日开始,又有新一批环保法律法规,环境规范和标准正式实施. 一. 全国文件及标准 1.<危险废物管理计划和管理台账制定技术导则> 为贯彻<中华人民共和国环境保护法& ...

最新文章

  1. python二维数组怎么写_python的二维数组操作
  2. 企业CIO如何让IT部门成为价值中心
  3. .NET Core/Framework 创建委托以大幅度提高反射调用的性能
  4. C++网络编程快速入门(四):EPOLL模型使用
  5. 我的世界服务器自定义欢迎界面,我的世界启动界面如何修改 diy修改启动界面攻略...
  6. Android 系统(60)---JSON
  7. php的数组key删除,php删除数组的key
  8. ecshop根目录调用_ecshop调用指定商品分类下的商品
  9. 《Python硬件编程实战》——1.3 Python的特点
  10. 三菱驱动器参数表_三菱伺服驱动器参数设置CM100TJ-24F
  11. Android 终端使用 JavaCV
  12. Looksery Cup 2015 A. Face Detection
  13. Pandas学习任务1-3
  14. linux下安装jdk7
  15. Thingworx配置mysql的jdbc
  16. Word如何操作压缩图片?干货经验!怎么在Word中压缩图片?
  17. 利用Linux自带的logrotate管理日志
  18. 域渗透基础_域渗透实战下gpo策略利用
  19. 计算机网络--串行传输与并行传输
  20. Vue时间戳(年/月/日/时:分:秒and 刚刚/一分钟前···)

热门文章

  1. word制作多个单位联合发文的文件头
  2. app store android退款,买完 App、游戏内购就后悔了?手把手教你如何申请 App Store 退款...
  3. excel 常用技巧
  4. CF342E Xenia and Tree
  5. Hammer.js 进行图片缩放
  6. python爬虫可以爬哪些网站-网络爬虫都能干什么?有哪些网站的数据可以爬取?...
  7. Python,还有一些鲜为人知的特性!你知道吗?
  8. javamail模拟邮箱功能--邮件删除-中级实战篇【邮件标记方法】(javamail API电子邮件实例)
  9. 内网服务器设置proxy权限联通外网
  10. [学点经济]什么是SDR [the IMF's Special Drawing Rights (SDR) basket of currencies]