职贝云数AI新零售门户

标题: 运用.NET完成企业微信运用接入:域名验证与音讯处理 [打印本页]

作者: KoVPKB8er8    时间: 3 天前
标题: 运用.NET完成企业微信运用接入:域名验证与音讯处理

本文将引见如何在不依赖任何第三方库的状况下,运用纯.NET完成企业微信运用的疾速接入,涵盖域名验证和音讯处理两个核心功能。

1. 背景

作为.NET开发者,在开发企业外部运用的时分,我们常常需求与企业微信停止集成,完成快捷的外部登录和一些便捷的音讯交互,简化一些功能的开发和反复建设。虽然市面上有一些第三方库可以协助我们完成这些集成工作,但有时分我们希望可以直接运用.NET自带的功能来完成这些需求,以减少对外部依赖的依赖,提升代码的可维护性和安全性。

下面我们就末尾运用纯.NET完成企业微信运用的疾速接入,企业微信运用接入次要包含两个关键环节:

•域名归属认证:验证域名一切权•音讯接收处理:处理企业微信推送的事情和音讯

2. 项目结构与配置

2.1 配置文件设置

首先在appsettings.json中配置企业微信相关参数:
{"DomainVerification":{"xxxx":"xxxxxx"},"WeCom":{"Token":"企业微信后台设置的Token","EncodingAesKey":"企业微信后台设置的EncodingAesKey","CorpId":"企业ID","CorpSecret":"运用凭证密钥"}}2.2 配置模型定义

运用 record 类型定义配置模型:
public record WeCom(stringCorpId,stringCorpSecret,stringToken,stringEncodingAesKey);2.3 依赖注入注册

在 Program.cs 中注册配置:
var builder =WebApplication.CreateBuilder(args);builder.Services.Configure<WeCom>(builder.Configuration.GetSection(nameof(WeCom)));
3. 域名归属认证明现

企业微信要求经过特定格式的URL验证域名归属,我们可以运用Minimal API完成:
app.MapGet("/WW_verify_{name}.txt",(string name)=>{var cfg = app.Configuration;var value = cfg.GetValue<string>($"DomainVerification:{name}");if(string.IsNullOrEmpty(value)){returnResults.NotFound();}
returnResults.Text(value,"text/plain");});

可信域名

完成要点:

•运用路由模板WW_verify_{name}.txt婚配企业微信的验证央求•从配置中读取对应的验证码内容•前往纯文本呼应

4. 音讯接收处理控制器

4.1 控制器基础结构

[ApiController][Route("wecom/callback")]publicclassWeComController:ControllerBase{privatereadonlyILogger<WeComController> _logger;privatereadonlyWeCom _weCom;
publicWeComController(ILogger<WeComController> logger,IOptionsSnapshot<WeCom> weCom){        _logger = logger;        _weCom = weCom.Value;}
// 后续方法完成...}4.2 URL验证接口(GET央求)

企业微信在配置回调URL时会发送GET央求停止验证:
[HttpGet]publicIActionResultGet([FromQuery]string msg_signature,[FromQuery]string timestamp,[FromQuery]string nonce,[FromQuery]string echostr){var token = _weCom.Token;var encodingAesKey = _weCom.EncodingAesKey;var corpId = _weCom.CorpId;
// 配置验证if(string.IsNullOrEmpty(token)||string.IsNullOrEmpty(encodingAesKey)||string.IsNullOrEmpty(corpId)){        _logger.LogWarning("WeCom config missing");returnBadRequest("WeCom config missing");}
if(string.IsNullOrEmpty(echostr))returnBadRequest();
// 签名验证if(!VerifySignature(token, timestamp, nonce, echostr, msg_signature)){        _logger.LogWarning("WeCom signature invalid (GET)");returnBadRequest("signature invalid");}
try{var plain =DecryptMessage(encodingAesKey, echostr, corpId);// 前往明文完成验证returnContent(plain,"text/plain",Encoding.UTF8);}catch(Exception ex){        _logger.LogWarning(ex,"WeCom decrypt failed (GET)");returnBadRequest("decrypt failed");}}4.3 音讯处理接口(POST央求)

处理企业微信推送的各种事情和音讯:
[HttpPost]public async Task<IActionResult>Post([FromQuery]string msg_signature,[FromQuery]string timestamp,[FromQuery]string nonce){var token = _weCom.Token;var encodingAesKey = _weCom.EncodingAesKey;var corpId = _weCom.CorpId;
// 配置验证if(string.IsNullOrEmpty(token)||string.IsNullOrEmpty(encodingAesKey)||string.IsNullOrEmpty(corpId)){        _logger.LogWarning("WeCom config missing");returnBadRequest();}
// 读取央求体usingvar reader =newSystem.IO.StreamReader(Request.Body,Encoding.UTF8);var body = await reader.ReadToEndAsync();
var encrypt =ExtractXmlNode(body,"Encrypt");if(string.IsNullOrEmpty(encrypt)){// 非加密音讯或格式不对,按企业微信要求前往 success        _logger.LogDebug("WeCom POST without Encrypt node, return success");returnContent("success","text/plain");}
// 签名验证if(!VerifySignature(token, timestamp, nonce, encrypt, msg_signature)){        _logger.LogWarning("WeCom signature invalid (POST)");returnBadRequest("signature invalid");}
string xml;try{        xml =DecryptMessage(encodingAesKey, encrypt, corpId);}catch(Exception ex){        _logger.LogWarning(ex,"WeCom decrypt failed (POST)");returnBadRequest("decrypt failed");}
// 处理XML音讯内容// 这里可以添加详细的业务逻辑处理
// 企业微信要求前往固定字符串 "success"returnContent("success","text/plain");}
5. 核心工具方法完成

5.1 签名验证

privatestaticboolVerifySignature(string token,string timestamp,string nonce,string encrypt,string signature){var arr =new[]{ token ??string.Empty, timestamp ??string.Empty,                     nonce ??string.Empty, encrypt ??string.Empty};Array.Sort(arr,StringComparer.Ordinal);var raw =string.Join("", arr);
usingvar sha1 = SHA1.Create();var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(raw));var computed =BitConverter.ToString(hash).Replace("-","").ToLowerInvariant();
returnstring.Equals(computed, signature ??string.Empty,StringComparison.OrdinalIgnoreCase);}5.2 音讯解密

privatestaticstringDecryptMessage(string encodingAesKey,string inputEncryptBase64,string corpId){// 补齐 base64 填充var pad = encodingAesKey;if(pad.Length%4!=0)        pad +=newstring('=',4- pad.Length%4);var aesKey =Convert.FromBase64String(pad);
var encrypted =Convert.FromBase64String(inputEncryptBase64);
usingvar aes =Aes.Create();    aes.Key= aesKey;    aes.IV = aesKey.Take(16).ToArray();    aes.Mode=CipherMode.CBC;    aes.Padding=PaddingMode.None;
usingvar decryptor = aes.CreateDecryptor();var decrypted = decryptor.TransformFinalBlock(encrypted,0, encrypted.Length);
// 移除 PKCS#7 填充var padLen = decrypted[^1];if(padLen <1|| padLen >32) padLen =0;var noPad = decrypted[..(decrypted.Length- padLen)];
// 结构:16 random | 4 msgLen | msg | corpIdvar msgLenBytes = noPad.Skip(16).Take(4).ToArray();if(msgLenBytes.Length<4)thrownewException("invalid msg len");
// 处理字节序if(BitConverter.IsLittleEndian)Array.Reverse(msgLenBytes);
var msgLen =BitConverter.ToInt32(msgLenBytes,0);var msgBytes = noPad.Skip(20).Take(msgLen).ToArray();var msg =Encoding.UTF8.GetString(msgBytes);
var fromCorpIdBytes = noPad.Skip(20+ msgLen).ToArray();var fromCorpId =Encoding.UTF8.GetString(fromCorpIdBytes);
// 验证企业IDif(!string.IsNullOrEmpty(corpId)&&!string.IsNullOrEmpty(fromCorpId)){if(!fromCorpId.StartsWith(corpId,StringComparison.Ordinal))thrownewException("corpId mismatch");}
return msg;}5.3 XML节点提取

privatestaticstringExtractXmlNode(string xml,string nodeName){try{var doc =newXmlDocument();        doc.LoadXml(xml);var node = doc.SelectSingleNode($"/xml/{nodeName}");return node?.InnerText;}catch{returnnull;}}
6. 测试与部署

在实践部署和测试时,请确保完成以下步骤:

1.域名验证测试:访问https://your-domain.com/WW_verify_xxxx.txt验证能否前往正确内容2.URL配置:在企业微信后台配置回调URL为https://your-domain.com/wecom/callback3.音讯测试:经过企业微信的在线测试工具[1]测试集成效果

7. 最后

本文残缺展现了如何运用纯.NET技术栈完成企业微信运用的接入,涵盖了从域名验证到音讯处理的残缺流程。这种完成方式不依赖任何第三方库,代码简约明晰,易于了解和维护,合适需求疾速接入企业微信的.NET项目运用。您可以根据实践业务需求在此基础上停止扩展,如添加音讯类型处理、业务逻辑集成等功能。
References

[1] 在线测试工具: https://developer.work.weixin.qq.com/resource/devtool




欢迎光临 职贝云数AI新零售门户 (https://www.taojin168.com/cloud/) Powered by Discuz! X3.5