mirror of
http://git.coreshop.cn/jianweie/coreshoppro.git
synced 2025-12-06 18:43:26 +08:00
添加项目文件。
This commit is contained in:
72
CoreCms.Net.WeChat.Service/Configuration/EventType.cs
Normal file
72
CoreCms.Net.WeChat.Service/Configuration/EventType.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/30 14:19:49
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// 常见消息类型
|
||||
/// </summary>
|
||||
public static class EventType
|
||||
{
|
||||
|
||||
#region 公众号类型
|
||||
|
||||
/// <summary>
|
||||
/// 关注
|
||||
/// </summary>
|
||||
public const string Subscribe = "subscribe";
|
||||
/// <summary>
|
||||
/// 取消订阅
|
||||
/// </summary>
|
||||
public const string Unsubscribe = "unsubscribe";
|
||||
/// <summary>
|
||||
/// 上报地理位置事件
|
||||
/// 用户同意上报地理位置后,每次进入公众号会话时,都会在进入时上报地理位置,或在进入会话后每5秒上报一次地理位置,公众号可以在公众平台网站中修改以上设置。上报地理位置时,微信会将上报地理位置事件推送到开发者填写的URL。
|
||||
/// </summary>
|
||||
public const string Localtion = "LOCATION";
|
||||
|
||||
/// <summary>
|
||||
/// 自定义菜单事件-用户点击自定义菜单后,微信会把点击事件推送给开发者,请注意,点击菜单弹出子菜单,不会产生上报。
|
||||
/// </summary>
|
||||
public const string Click = "CLICK";
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 小程序
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 自定义交易组件
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 图片消息
|
||||
/// </summary>
|
||||
public const string Image = "image";
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
69
CoreCms.Net.WeChat.Service/Configuration/RequestMsgType.cs
Normal file
69
CoreCms.Net.WeChat.Service/Configuration/RequestMsgType.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/30 14:19:49
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// 常用常量配置
|
||||
/// </summary>
|
||||
public static class RequestMsgType
|
||||
{
|
||||
// 各种消息类型,除了扫带二维码事件
|
||||
/// <summary>
|
||||
/// 文本消息
|
||||
/// </summary>
|
||||
public const string Text = "text";
|
||||
|
||||
/// <summary>
|
||||
/// 图片消息
|
||||
/// </summary>
|
||||
public const string Image = "image";
|
||||
|
||||
/// <summary>
|
||||
/// 语音消息
|
||||
/// </summary>
|
||||
public const string Voice = "voice";
|
||||
|
||||
/// <summary>
|
||||
/// 视频消息
|
||||
/// </summary>
|
||||
public const string Video = "video";
|
||||
|
||||
/// <summary>
|
||||
/// 小视频消息
|
||||
/// </summary>
|
||||
public const string ShortVideo = "shortvideo";
|
||||
|
||||
/// <summary>
|
||||
/// 地理位置消息
|
||||
/// </summary>
|
||||
public const string Location = "location";
|
||||
|
||||
/// <summary>
|
||||
/// 链接消息
|
||||
/// </summary>
|
||||
public const string Link = "link";
|
||||
|
||||
/// <summary>
|
||||
/// 事件推送消息
|
||||
/// </summary>
|
||||
public const string MessageEvent = "event";
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
21
CoreCms.Net.WeChat.Service/CoreCms.Net.WeChat.Service.csproj
Normal file
21
CoreCms.Net.WeChat.Service/CoreCms.Net.WeChat.Service.csproj
Normal file
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MediatR" Version="9.0.0" />
|
||||
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="SKIT.FlurlHttpClient.Wechat.Api" Version="1.9.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CoreCms.Net.Utility\CoreCms.Net.Utility.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
289
CoreCms.Net.WeChat.Service/Enums/ReturnCode.cs
Normal file
289
CoreCms.Net.WeChat.Service/Enums/ReturnCode.cs
Normal file
@@ -0,0 +1,289 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 1:46:08
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Enums
|
||||
{
|
||||
public class WeChatReturnCode
|
||||
{
|
||||
/// <summary>
|
||||
/// 公众号返回码(JSON)
|
||||
/// 应该更名为ReturnCode_MP,但为减少项目中的修改,此处依旧用ReturnCode命名
|
||||
/// </summary>
|
||||
public enum ReturnCode
|
||||
{
|
||||
SenparcWeixinSDK配置错误 = -99, // 0xFFFFFF9D
|
||||
系统繁忙此时请开发者稍候再试 = -1, // 0xFFFFFFFF
|
||||
请求成功 = 0,
|
||||
工商数据返回_企业已注销 = 101, // 0x00000065
|
||||
工商数据返回_企业不存在或企业信息未更新 = 102, // 0x00000066
|
||||
工商数据返回_企业法定代表人姓名不一致 = 103, // 0x00000067
|
||||
工商数据返回_企业法定代表人身份证号码不一致 = 104, // 0x00000068
|
||||
法定代表人身份证号码_工商数据未更新_请5_15个工作日之后尝试 = 105, // 0x00000069
|
||||
工商数据返回_企业信息或法定代表人信息不一致 = 1000, // 0x000003E8
|
||||
对方不是粉丝 = 10700, // 0x000029CC
|
||||
发送消息失败_对方关闭了接收消息 = 10703, // 0x000029CF
|
||||
发送消息失败_48小时内用户未互动 = 10706, // 0x000029D2
|
||||
POST参数非法 = 20002, // 0x00004E22
|
||||
获取access_token时AppSecret错误或者access_token无效 = 40001, // 0x00009C41
|
||||
/// <summary>
|
||||
/// <para>公众号:不合法的凭证类型</para>
|
||||
/// <para>小程序:暂无生成权限</para>
|
||||
/// </summary>
|
||||
不合法的凭证类型 = 40002, // 0x00009C42
|
||||
不合法的OpenID = 40003, // 0x00009C43
|
||||
不合法的媒体文件类型 = 40004, // 0x00009C44
|
||||
不合法的文件类型 = 40005, // 0x00009C45
|
||||
不合法的文件大小 = 40006, // 0x00009C46
|
||||
不合法的媒体文件id = 40007, // 0x00009C47
|
||||
不合法的消息类型_40008 = 40008, // 0x00009C48
|
||||
不合法的图片文件大小 = 40009, // 0x00009C49
|
||||
不合法的语音文件大小 = 40010, // 0x00009C4A
|
||||
不合法的视频文件大小 = 40011, // 0x00009C4B
|
||||
不合法的缩略图文件大小 = 40012, // 0x00009C4C
|
||||
/// <summary>
|
||||
/// <para>微信:不合法的APPID</para>
|
||||
/// <para>小程序:生成权限被封禁</para>
|
||||
/// </summary>
|
||||
不合法的APPID = 40013, // 0x00009C4D
|
||||
不合法的access_token = 40014, // 0x00009C4E
|
||||
不合法的菜单类型 = 40015, // 0x00009C4F
|
||||
不合法的按钮个数1 = 40016, // 0x00009C50
|
||||
不合法的按钮个数2 = 40017, // 0x00009C51
|
||||
不合法的按钮名字长度 = 40018, // 0x00009C52
|
||||
不合法的按钮KEY长度 = 40019, // 0x00009C53
|
||||
不合法的按钮URL长度 = 40020, // 0x00009C54
|
||||
不合法的菜单版本号 = 40021, // 0x00009C55
|
||||
不合法的子菜单级数 = 40022, // 0x00009C56
|
||||
不合法的子菜单按钮个数 = 40023, // 0x00009C57
|
||||
不合法的子菜单按钮类型 = 40024, // 0x00009C58
|
||||
不合法的子菜单按钮名字长度 = 40025, // 0x00009C59
|
||||
不合法的子菜单按钮KEY长度 = 40026, // 0x00009C5A
|
||||
不合法的子菜单按钮URL长度 = 40027, // 0x00009C5B
|
||||
不合法的自定义菜单使用用户 = 40028, // 0x00009C5C
|
||||
不合法的oauth_code = 40029, // 0x00009C5D
|
||||
不合法的refresh_token = 40030, // 0x00009C5E
|
||||
不合法的openid列表 = 40031, // 0x00009C5F
|
||||
不合法的openid列表长度 = 40032, // 0x00009C60
|
||||
不合法的请求字符不能包含uxxxx格式的字符 = 40033, // 0x00009C61
|
||||
不合法的参数 = 40035, // 0x00009C63
|
||||
template_id不正确 = 40037, // 0x00009C65
|
||||
不合法的请求格式 = 40038, // 0x00009C66
|
||||
不合法的URL长度 = 40039, // 0x00009C67
|
||||
不合法的分组id = 40050, // 0x00009C72
|
||||
分组名字不合法 = 40051, // 0x00009C73
|
||||
/// <summary>
|
||||
/// <para>公众号:输入参数有误</para>
|
||||
/// <para>小程序:参数expire_time填写错误</para>
|
||||
/// </summary>
|
||||
输入参数有误 = 40097, // 0x00009CA1
|
||||
appsecret不正确 = 40125, // 0x00009CBD
|
||||
调用接口的IP地址不在白名单中 = 40164, // 0x00009CE4
|
||||
参数path填写错误 = 40165, // 0x00009CE5
|
||||
小程序Appid不存在 = 40166, // 0x00009CE6
|
||||
参数query填写错误 = 40212, // 0x00009D14
|
||||
缺少access_token参数 = 41001, // 0x0000A029
|
||||
缺少appid参数 = 41002, // 0x0000A02A
|
||||
缺少refresh_token参数 = 41003, // 0x0000A02B
|
||||
缺少secret参数 = 41004, // 0x0000A02C
|
||||
缺少多媒体文件数据 = 41005, // 0x0000A02D
|
||||
缺少media_id参数 = 41006, // 0x0000A02E
|
||||
缺少子菜单数据 = 41007, // 0x0000A02F
|
||||
缺少oauth_code = 41008, // 0x0000A030
|
||||
缺少openid = 41009, // 0x0000A031
|
||||
form_id不正确_或者过期 = 41028, // 0x0000A044
|
||||
form_id已被使用 = 41029, // 0x0000A045
|
||||
page不正确 = 41030, // 0x0000A046
|
||||
access_token超时 = 42001, // 0x0000A411
|
||||
refresh_token超时 = 42002, // 0x0000A412
|
||||
oauth_code超时 = 42003, // 0x0000A413
|
||||
需要GET请求 = 43001, // 0x0000A7F9
|
||||
需要POST请求 = 43002, // 0x0000A7FA
|
||||
需要HTTPS请求 = 43003, // 0x0000A7FB
|
||||
需要接收者关注 = 43004, // 0x0000A7FC
|
||||
需要好友关系 = 43005, // 0x0000A7FD
|
||||
/// <summary>[小程序订阅消息]用户拒绝接受消息,如果用户之前曾经订阅过,则表示用户取消了订阅关系</summary>
|
||||
用户拒绝接受消息 = 43101, // 0x0000A85D
|
||||
没有权限 = 43104, // 0x0000A860
|
||||
多媒体文件为空 = 44001, // 0x0000ABE1
|
||||
POST的数据包为空 = 44002, // 0x0000ABE2
|
||||
图文消息内容为空 = 44003, // 0x0000ABE3
|
||||
文本消息内容为空 = 44004, // 0x0000ABE4
|
||||
多媒体文件大小超过限制 = 45001, // 0x0000AFC9
|
||||
消息内容超过限制 = 45002, // 0x0000AFCA
|
||||
标题字段超过限制 = 45003, // 0x0000AFCB
|
||||
描述字段超过限制 = 45004, // 0x0000AFCC
|
||||
链接字段超过限制 = 45005, // 0x0000AFCD
|
||||
图片链接字段超过限制 = 45006, // 0x0000AFCE
|
||||
语音播放时间超过限制 = 45007, // 0x0000AFCF
|
||||
图文消息超过限制 = 45008, // 0x0000AFD0
|
||||
接口调用超过限制 = 45009, // 0x0000AFD1
|
||||
创建菜单个数超过限制 = 45010, // 0x0000AFD2
|
||||
回复时间超过限制 = 45015, // 0x0000AFD7
|
||||
系统分组不允许修改 = 45016, // 0x0000AFD8
|
||||
分组名字过长 = 45017, // 0x0000AFD9
|
||||
分组数量超过上限 = 45018, // 0x0000AFDA
|
||||
超出响应数量限制 = 45047, // 0x0000AFF7
|
||||
创建的标签数过多请注意不能超过100个 = 45056, // 0x0000B000
|
||||
标签名非法请注意不能和其他标签重名 = 45157, // 0x0000B065
|
||||
标签名长度超过30个字节 = 45158, // 0x0000B066
|
||||
不存在媒体数据 = 46001, // 0x0000B3B1
|
||||
不存在的菜单版本 = 46002, // 0x0000B3B2
|
||||
不存在的菜单数据 = 46003, // 0x0000B3B3
|
||||
解析JSON_XML内容错误 = 47001, // 0x0000B799
|
||||
/// <summary>[小程序订阅消息]模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错</summary>
|
||||
模板参数不准确 = 47003, // 0x0000B79B
|
||||
api功能未授权 = 48001, // 0x0000BB81
|
||||
用户未授权该api = 50001, // 0x0000C351
|
||||
名称格式不合法 = 53010, // 0x0000CF12
|
||||
名称检测命中频率限制 = 53011, // 0x0000CF13
|
||||
禁止使用该名称 = 53012, // 0x0000CF14
|
||||
公众号_名称与已有公众号名称重复_小程序_该名称与已有小程序名称重复 = 53013, // 0x0000CF15
|
||||
公众号_公众号已有_名称A_时_需与该帐号相同主体才可申请_名称A_小程序_小程序已有_名称A_时_需与该帐号相同主体才可申请_名称A_ = 53014, // 0x0000CF16
|
||||
公众号_该名称与已有小程序名称重复_需与该小程序帐号相同主体才可申请_小程序_该名称与已有公众号名称重复_需与该公众号帐号相同主体才可申请 = 53015, // 0x0000CF17
|
||||
公众号_该名称与已有多个小程序名称重复_暂不支持申请_小程序_该名称与已有多个公众号名称重复_暂不支持申请 = 53016, // 0x0000CF18
|
||||
公众号_小程序已有_名称A_时_需与该帐号相同主体才可申请_名称A_小程序_公众号已有_名称A_时_需与该帐号相同主体才可申请_名称A = 53017, // 0x0000CF19
|
||||
名称命中微信号 = 53018, // 0x0000CF1A
|
||||
名称在保护期内 = 53019, // 0x0000CF1B
|
||||
法人姓名与微信号不一致 = 61070, // 0x0000EE8E
|
||||
系统错误system_error = 61450, // 0x0000F00A
|
||||
参数错误invalid_parameter = 61451, // 0x0000F00B
|
||||
无效客服账号invalid_kf_account = 61452, // 0x0000F00C
|
||||
客服帐号已存在kf_account_exsited = 61453, // 0x0000F00D
|
||||
/// <summary>
|
||||
/// 客服帐号名长度超过限制(仅允许10个英文字符,不包括@及@后的公众号的微信号)(invalid kf_acount length)
|
||||
/// </summary>
|
||||
客服帐号名长度超过限制 = 61454, // 0x0000F00E
|
||||
/// <summary>
|
||||
/// 客服帐号名包含非法字符(仅允许英文+数字)(illegal character in kf_account)
|
||||
/// </summary>
|
||||
客服帐号名包含非法字符 = 61455, // 0x0000F00F
|
||||
/// <summary>客服帐号个数超过限制(10个客服账号)(kf_account count exceeded)</summary>
|
||||
客服帐号个数超过限制 = 61456, // 0x0000F010
|
||||
无效头像文件类型invalid_file_type = 61457, // 0x0000F011
|
||||
日期格式错误 = 61500, // 0x0000F03C
|
||||
日期范围错误 = 61501, // 0x0000F03D
|
||||
发送消息失败_该用户已被加入黑名单_无法向此发送消息 = 62751, // 0x0000F51F
|
||||
门店不存在 = 65115, // 0x0000FE5B
|
||||
该门店状态不允许更新 = 65118, // 0x0000FE5E
|
||||
标签格式错误 = 85006, // 0x00014C0E
|
||||
页面路径错误 = 85007, // 0x00014C0F
|
||||
类目填写错误 = 85008, // 0x00014C10
|
||||
已经有正在审核的版本 = 85009, // 0x00014C11
|
||||
item_list有项目为空 = 85010, // 0x00014C12
|
||||
标题填写错误 = 85011, // 0x00014C13
|
||||
无效的审核id = 85012, // 0x00014C14
|
||||
版本输入错误 = 85015, // 0x00014C17
|
||||
没有审核版本 = 85019, // 0x00014C1B
|
||||
审核状态未满足发布 = 85020, // 0x00014C1C
|
||||
状态不可变 = 85021, // 0x00014C1D
|
||||
action非法 = 85022, // 0x00014C1E
|
||||
审核列表填写的项目数不在1到5以内 = 85023, // 0x00014C1F
|
||||
需要补充相应资料_填写org_code和other_files参数 = 85024, // 0x00014C20
|
||||
管理员手机登记数量已超过上限 = 85025, // 0x00014C21
|
||||
该微信号已绑定5个管理员 = 85026, // 0x00014C22
|
||||
管理员身份证已登记过5次 = 85027, // 0x00014C23
|
||||
该主体登记数量已超过上限 = 85028, // 0x00014C24
|
||||
商家名称已被占用 = 85029, // 0x00014C25
|
||||
不能使用该名称 = 85031, // 0x00014C27
|
||||
该名称在侵权投诉保护期 = 85032, // 0x00014C28
|
||||
名称包含违规内容或微信等保留字 = 85033, // 0x00014C29
|
||||
商家名称在改名15天保护期内 = 85034, // 0x00014C2A
|
||||
需与该帐号相同主体才可申请 = 85035, // 0x00014C2B
|
||||
介绍中含有虚假混淆内容 = 85036, // 0x00014C2C
|
||||
头像或者简介修改达到每个月上限 = 85049, // 0x00014C39
|
||||
正在审核中_请勿重复提交 = 85050, // 0x00014C3A
|
||||
请先成功创建门店后再调用 = 85053, // 0x00014C3D
|
||||
临时mediaid无效 = 85056, // 0x00014C40
|
||||
链接错误 = 85066, // 0x00014C4A
|
||||
测试链接不是子链接 = 85068, // 0x00014C4C
|
||||
校验文件失败 = 85069, // 0x00014C4D
|
||||
个人类型小程序无法设置二维码规则 = 85070, // 0x00014C4E
|
||||
已添加该链接_请勿重复添加 = 85071, // 0x00014C4F
|
||||
该链接已被占用 = 85072, // 0x00014C50
|
||||
二维码规则已满 = 85073, // 0x00014C51
|
||||
小程序未发布_小程序必须先发布代码才可以发布二维码跳转规则 = 85074, // 0x00014C52
|
||||
个人类型小程序无法设置二维码规则1 = 85075, // 0x00014C53
|
||||
小程序没有线上版本_不能进行灰度 = 85079, // 0x00014C57
|
||||
小程序提交的审核未审核通过 = 85080, // 0x00014C58
|
||||
无效的发布比例 = 85081, // 0x00014C59
|
||||
当前的发布比例需要比之前设置的高 = 85082, // 0x00014C5A
|
||||
小程序提审数量已达本月上限 = 85085, // 0x00014C5D
|
||||
提交代码审核之前需提前上传代码 = 85086, // 0x00014C5E
|
||||
小程序已使用_api_navigateToMiniProgram_请声明跳转_appid_列表后再次提交 = 85087, // 0x00014C5F
|
||||
不是由第三方代小程序进行调用 = 86000, // 0x00014FF0
|
||||
不存在第三方的已经提交的代码 = 86001, // 0x00014FF1
|
||||
小程序还未设置昵称_头像_简介_请先设置完后再重新提交 = 86002, // 0x00014FF2
|
||||
无效微信号 = 86004, // 0x00014FF4
|
||||
/// <summary>
|
||||
/// 小程序为“签名错误”。对应公众号: 87009, “errmsg” : “reply is not exists” //该回复不存在
|
||||
/// </summary>
|
||||
签名错误 = 87009, // 0x000153E1
|
||||
现网已经在灰度发布_不能进行版本回退 = 87011, // 0x000153E3
|
||||
该版本不能回退_可能的原因_1_无上一个线上版用于回退_2_此版本为已回退版本_不能回退_3_此版本为回退功能上线之前的版本_不能回退 = 87012, // 0x000153E4
|
||||
内容含有违法违规内容 = 87014, // 0x000153E6
|
||||
没有留言权限 = 88000, // 0x000157C0
|
||||
该图文不存在 = 88001, // 0x000157C1
|
||||
文章存在敏感信息 = 88002, // 0x000157C2
|
||||
精选评论数已达上限 = 88003, // 0x000157C3
|
||||
已被用户删除_无法精选 = 88004, // 0x000157C4
|
||||
已经回复过了 = 88005, // 0x000157C5
|
||||
回复超过长度限制或为0 = 88007, // 0x000157C7
|
||||
该评论不存在 = 88008, // 0x000157C8
|
||||
获取评论数目不合法 = 88010, // 0x000157CA
|
||||
该公众号_小程序已经绑定了开放平台帐号 = 89000, // 0x00015BA8
|
||||
业务域名无更改_无需重复设置 = 89019, // 0x00015BBB
|
||||
尚未设置小程序业务域名_请先在第三方平台中设置小程序业务域名后在调用本接口 = 89020, // 0x00015BBC
|
||||
请求保存的域名不是第三方平台中已设置的小程序业务域名或子域名 = 89021, // 0x00015BBD
|
||||
业务域名数量超过限制_最多可以添加100个业务域名 = 89029, // 0x00015BC5
|
||||
个人小程序不支持调用_setwebviewdomain_接口 = 89231, // 0x00015C8F
|
||||
内部错误 = 89247, // 0x00015C9F
|
||||
企业代码类型无效_请选择正确类型填写 = 89248, // 0x00015CA0
|
||||
该主体已有任务执行中_距上次任务24h后再试 = 89249, // 0x00015CA1
|
||||
未找到该任务 = 89250, // 0x00015CA2
|
||||
待法人人脸核身校验 = 89251, // 0x00015CA3
|
||||
法人_企业信息一致性校验中 = 89252, // 0x00015CA4
|
||||
缺少参数 = 89253, // 0x00015CA5
|
||||
第三方权限集不全_补全权限集全网发布后生效 = 89254, // 0x00015CA6
|
||||
系统不稳定_请稍后再试_如多次失败请通过社区反馈 = 89401, // 0x00015D39
|
||||
该审核单不在待审核队列_请检查是否已提交审核或已审完 = 89402, // 0x00015D3A
|
||||
本单属于平台不支持加急种类_请等待正常审核流程 = 89403, // 0x00015D3B
|
||||
本单已加速成功_请勿重复提交 = 89404, // 0x00015D3C
|
||||
本月加急额度不足_请提升提审质量以获取更多额度 = 89405, // 0x00015D3D
|
||||
该经营资质已添加_请勿重复添加 = 92000, // 0x00016760
|
||||
附近地点添加数量达到上线_无法继续添加 = 92002, // 0x00016762
|
||||
地点已被其它小程序占用 = 92003, // 0x00016763
|
||||
附近功能被封禁 = 92004, // 0x00016764
|
||||
地点正在审核中 = 92005, // 0x00016765
|
||||
地点正在展示小程序 = 92006, // 0x00016766
|
||||
地点审核失败 = 92007, // 0x00016767
|
||||
程序未展示在该地点 = 92008, // 0x00016768
|
||||
小程序未上架或不可见 = 92009, // 0x00016769
|
||||
地点不存在 = 93010, // 0x00016B52
|
||||
个人类型小程序不可用 = 93011, // 0x00016B53
|
||||
已下发的模板消息法人并未确认且已超时_24h_未进行身份证校验 = 100001, // 0x000186A1
|
||||
已下发的模板消息法人并未确认且已超时_24h_未进行人脸识别校验 = 100002, // 0x000186A2
|
||||
已下发的模板消息法人并未确认且已超时_24h = 100003, // 0x000186A3
|
||||
此账号已被封禁_无法操作 = 200011, // 0x00030D4B
|
||||
私有模板数已达上限_上限_50_个 = 200012, // 0x00030D4C
|
||||
此模版已被封禁_无法选用 = 200013, // 0x00030D4D
|
||||
模版tid参数错误 = 200014, // 0x00030D4E
|
||||
关键词列表kidList参数错误 = 200020, // 0x00030D54
|
||||
场景描述sceneDesc参数错误 = 200021, // 0x00030D55
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms.Net *
|
||||
* Web: https://CoreCms.Net *
|
||||
* ProjectName: 核心内容管理系统 *
|
||||
* Author: 大灰灰 *
|
||||
* Email: JianWeie@163.com *
|
||||
* CreateTime: 2020-08-13 23:57:23
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CoreCms.Net.Utility.Helper;
|
||||
using CoreCms.Net.WeChat.Service.HttpClients;
|
||||
using CoreCms.Net.WeChat.Service.Models;
|
||||
using MediatR;
|
||||
using SKIT.FlurlHttpClient.Wechat.Api;
|
||||
using SKIT.FlurlHttpClient.Wechat.Api.Events;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Mediator
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示 TEXT 事件的数据
|
||||
/// </summary>
|
||||
public class ImageMessageEventCommand : IRequest<WeChatApiCallBack>
|
||||
{
|
||||
public ImageMessageEvent EventObj { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理TEXT 事件的数据-以被动回复文本消息为例
|
||||
/// </summary>
|
||||
public class ImageMessageEventCommandHandler : IRequestHandler<ImageMessageEventCommand, WeChatApiCallBack>
|
||||
{
|
||||
private readonly WeChat.Service.HttpClients.IWeChatApiHttpClientFactory _weChatApiHttpClientFactory;
|
||||
|
||||
|
||||
|
||||
public ImageMessageEventCommandHandler(IWeChatApiHttpClientFactory weChatApiHttpClientFactory)
|
||||
{
|
||||
_weChatApiHttpClientFactory = weChatApiHttpClientFactory;
|
||||
}
|
||||
|
||||
public async Task<WeChatApiCallBack> Handle(ImageMessageEventCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
var jm = new WeChatApiCallBack() { Status = true };
|
||||
|
||||
if (request.EventObj != null)
|
||||
{
|
||||
var client = _weChatApiHttpClientFactory.CreateWxOpenClient();
|
||||
var replyModel = new SKIT.FlurlHttpClient.Wechat.Api.Events.TransferCustomerServiceReply()
|
||||
{
|
||||
ToUserName = request.EventObj.FromUserName,
|
||||
FromUserName = request.EventObj.ToUserName,
|
||||
CreateTimestamp = CommonHelper.GetTimeStampByTotalSeconds()
|
||||
};
|
||||
var replyXml = client.SerializeEventToXml(replyModel);
|
||||
jm.Data = replyXml;
|
||||
}
|
||||
|
||||
return await Task.FromResult(jm);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms.Net *
|
||||
* Web: https://CoreCms.Net *
|
||||
* ProjectName: 核心内容管理系统 *
|
||||
* Author: 大灰灰 *
|
||||
* Email: JianWeie@163.com *
|
||||
* CreateTime: 2020-08-13 23:57:23
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CoreCms.Net.Utility.Helper;
|
||||
using CoreCms.Net.WeChat.Service.HttpClients;
|
||||
using CoreCms.Net.WeChat.Service.Models;
|
||||
using MediatR;
|
||||
using SKIT.FlurlHttpClient.Wechat.Api;
|
||||
using SKIT.FlurlHttpClient.Wechat.Api.Events;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Mediator
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示 TEXT 事件的数据
|
||||
/// </summary>
|
||||
public class TextMessageEventCommand : IRequest<WeChatApiCallBack>
|
||||
{
|
||||
public TextMessageEvent EventObj { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理TEXT 事件的数据-以被动回复文本消息为例
|
||||
/// </summary>
|
||||
public class TextMessageEventCommandHandler : IRequestHandler<TextMessageEventCommand, WeChatApiCallBack>
|
||||
{
|
||||
private readonly WeChat.Service.HttpClients.IWeChatApiHttpClientFactory _weChatApiHttpClientFactory;
|
||||
|
||||
|
||||
|
||||
public TextMessageEventCommandHandler(IWeChatApiHttpClientFactory weChatApiHttpClientFactory)
|
||||
{
|
||||
_weChatApiHttpClientFactory = weChatApiHttpClientFactory;
|
||||
}
|
||||
|
||||
public async Task<WeChatApiCallBack> Handle(TextMessageEventCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
var jm = new WeChatApiCallBack() { Status = true };
|
||||
|
||||
if (request.EventObj != null)
|
||||
{
|
||||
var client = _weChatApiHttpClientFactory.CreateWxOpenClient();
|
||||
var replyModel = new SKIT.FlurlHttpClient.Wechat.Api.Events.TransferCustomerServiceReply()
|
||||
{
|
||||
ToUserName = request.EventObj.FromUserName,
|
||||
FromUserName = request.EventObj.ToUserName,
|
||||
CreateTimestamp = CommonHelper.GetTimeStampByTotalSeconds()
|
||||
};
|
||||
var replyXml = client.SerializeEventToXml(replyModel);
|
||||
jm.Data = replyXml;
|
||||
}
|
||||
|
||||
return await Task.FromResult(jm);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms.Net *
|
||||
* Web: https://CoreCms.Net *
|
||||
* ProjectName: 核心内容管理系统 *
|
||||
* Author: 大灰灰 *
|
||||
* Email: JianWeie@163.com *
|
||||
* CreateTime: 2020-08-13 23:57:23
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CoreCms.Net.Utility.Helper;
|
||||
using CoreCms.Net.WeChat.Service.HttpClients;
|
||||
using CoreCms.Net.WeChat.Service.Models;
|
||||
using MediatR;
|
||||
using SKIT.FlurlHttpClient.Wechat.Api;
|
||||
using SKIT.FlurlHttpClient.Wechat.Api.Events;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Mediator
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示 TEXT 事件的数据
|
||||
/// </summary>
|
||||
public class VoiceMessageEventCommand : IRequest<WeChatApiCallBack>
|
||||
{
|
||||
public VoiceMessageEvent EventObj { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理TEXT 事件的数据-以被动回复文本消息为例
|
||||
/// </summary>
|
||||
public class VoiceMessageEventCommandHandler : IRequestHandler<VoiceMessageEventCommand, WeChatApiCallBack>
|
||||
{
|
||||
private readonly WeChat.Service.HttpClients.IWeChatApiHttpClientFactory _weChatApiHttpClientFactory;
|
||||
|
||||
|
||||
|
||||
public VoiceMessageEventCommandHandler(IWeChatApiHttpClientFactory weChatApiHttpClientFactory)
|
||||
{
|
||||
_weChatApiHttpClientFactory = weChatApiHttpClientFactory;
|
||||
}
|
||||
|
||||
public async Task<WeChatApiCallBack> Handle(VoiceMessageEventCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
var jm = new WeChatApiCallBack() { Status = true };
|
||||
|
||||
if (request.EventObj != null)
|
||||
{
|
||||
var client = _weChatApiHttpClientFactory.CreateWxOpenClient();
|
||||
var replyModel = new SKIT.FlurlHttpClient.Wechat.Api.Events.TransferCustomerServiceReply()
|
||||
{
|
||||
ToUserName = request.EventObj.FromUserName,
|
||||
FromUserName = request.EventObj.ToUserName,
|
||||
CreateTimestamp = CommonHelper.GetTimeStampByTotalSeconds()
|
||||
};
|
||||
var replyXml = client.SerializeEventToXml(replyModel);
|
||||
jm.Data = replyXml;
|
||||
}
|
||||
|
||||
return await Task.FromResult(jm);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
38
CoreCms.Net.WeChat.Service/Models/DecodedPhoneNumber.cs
Normal file
38
CoreCms.Net.WeChat.Service/Models/DecodedPhoneNumber.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 1:08:20
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户绑定手机号解密类
|
||||
/// </summary>
|
||||
public class DecodedPhoneNumber : DecodeEntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户绑定的手机号(国外手机号会有区号)
|
||||
/// </summary>
|
||||
public string phoneNumber { get; set; }
|
||||
/// <summary>
|
||||
/// 没有区号的手机号
|
||||
/// </summary>
|
||||
public string purePhoneNumber { get; set; }
|
||||
/// <summary>
|
||||
/// 区号(Senparc注:国别号)
|
||||
/// </summary>
|
||||
public string countryCode { get; set; }
|
||||
}
|
||||
}
|
||||
32
CoreCms.Net.WeChat.Service/Models/DecodedRunData.cs
Normal file
32
CoreCms.Net.WeChat.Service/Models/DecodedRunData.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 11:09:03
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Models
|
||||
{
|
||||
[Serializable]
|
||||
public class DecodedRunData : DecodeEntityBase
|
||||
{
|
||||
public List<DecodedRunData_StepModel> stepInfoList { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class DecodedRunData_StepModel
|
||||
{
|
||||
public long timestamp { get; set; }
|
||||
public long step { get; set; }
|
||||
}
|
||||
}
|
||||
53
CoreCms.Net.WeChat.Service/Models/EncryptPostModel.cs
Normal file
53
CoreCms.Net.WeChat.Service/Models/EncryptPostModel.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 21:25:25
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Models
|
||||
{
|
||||
/// <summary>接收加密信息统一基类(同时也支持非加密信息)</summary>
|
||||
public abstract class EncryptPostModel : IEncryptPostModel
|
||||
{
|
||||
/// <summary>指定当前服务账号的唯一领域定义(主要为 APM 服务),例如 AppId</summary>
|
||||
public abstract string DomainId { get; set; }
|
||||
|
||||
/// <summary>Signature</summary>
|
||||
public string Signature { get; set; }
|
||||
|
||||
/// <summary>Msg_Signature</summary>
|
||||
public string Msg_Signature { get; set; }
|
||||
|
||||
/// <summary>Timestamp</summary>
|
||||
public string Timestamp { get; set; }
|
||||
|
||||
/// <summary>Nonce</summary>
|
||||
public string Nonce { get; set; }
|
||||
|
||||
/// <summary>Token</summary>
|
||||
public string Token { get; set; }
|
||||
|
||||
/// <summary>EncodingAESKey</summary>
|
||||
public string EncodingAESKey { get; set; }
|
||||
|
||||
/// <summary>设置服务器内部保密信息</summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="encodingAESKey"></param>
|
||||
public virtual void SetSecretInfo(string token, string encodingAESKey)
|
||||
{
|
||||
this.Token = token;
|
||||
this.EncodingAESKey = encodingAESKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
CoreCms.Net.WeChat.Service/Models/IEncryptPostModel.cs
Normal file
44
CoreCms.Net.WeChat.Service/Models/IEncryptPostModel.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 21:25:02
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Models
|
||||
{
|
||||
/// <summary>接收加密信息统一接口(同时也支持非加密信息)</summary>
|
||||
public interface IEncryptPostModel
|
||||
{
|
||||
/// <summary>指定当前服务账号的唯一领域定义(主要为 APM 服务),例如 AppId</summary>
|
||||
string DomainId { get; set; }
|
||||
|
||||
/// <summary>Signature</summary>
|
||||
string Signature { get; set; }
|
||||
|
||||
/// <summary>Msg_Signature</summary>
|
||||
string Msg_Signature { get; set; }
|
||||
|
||||
/// <summary>Timestamp</summary>
|
||||
string Timestamp { get; set; }
|
||||
|
||||
/// <summary>Nonce</summary>
|
||||
string Nonce { get; set; }
|
||||
|
||||
/// <summary>Token</summary>
|
||||
string Token { get; set; }
|
||||
|
||||
/// <summary>EncodingAESKey</summary>
|
||||
string EncodingAESKey { get; set; }
|
||||
}
|
||||
}
|
||||
45
CoreCms.Net.WeChat.Service/Models/PostModel.cs
Normal file
45
CoreCms.Net.WeChat.Service/Models/PostModel.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 21:25:51
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 微信公众服务器Post过来的加密参数集合(不包括PostData)
|
||||
/// <para>如需使用 NeuChar,需要在 MessageHandler 中提供 PostModel 并设置 AppId</para>
|
||||
/// </summary>
|
||||
public class PostModel : EncryptPostModel
|
||||
{
|
||||
public override string DomainId
|
||||
{
|
||||
get => this.AppId;
|
||||
set => this.AppId = value;
|
||||
}
|
||||
|
||||
public string AppId { get; set; }
|
||||
|
||||
/// <summary>设置服务器内部保密信息</summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="encodingAESKey"></param>
|
||||
/// <param name="appId"></param>
|
||||
public void SetSecretInfo(string token, string encodingAESKey, string appId)
|
||||
{
|
||||
this.Token = token;
|
||||
this.EncodingAESKey = encodingAESKey;
|
||||
this.AppId = appId;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
CoreCms.Net.WeChat.Service/Models/SendWxTemplateMessage.cs
Normal file
36
CoreCms.Net.WeChat.Service/Models/SendWxTemplateMessage.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/14 16:27:23
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理器-微信模板消息【小程序,公众号都走这里】
|
||||
/// </summary>
|
||||
public class SendWxTemplateMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户序列
|
||||
/// </summary>
|
||||
public int userId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 类型
|
||||
/// </summary>
|
||||
public string code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 传递数据
|
||||
/// </summary>
|
||||
public JObject parameters { get; set; }
|
||||
}
|
||||
}
|
||||
35
CoreCms.Net.WeChat.Service/Models/WaterMark.cs
Normal file
35
CoreCms.Net.WeChat.Service/Models/WaterMark.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 1:09:19
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CoreCms.Net.WeChat.Service.Utilities;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 水印
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Watermark
|
||||
{
|
||||
public string appid { get; set; }
|
||||
public long timestamp { get; set; }
|
||||
|
||||
public DateTimeOffset DateTimeStamp
|
||||
{
|
||||
get { return DateTimeHelper.GetDateTimeFromXml(timestamp); }
|
||||
}
|
||||
}
|
||||
}
|
||||
38
CoreCms.Net.WeChat.Service/Models/WeChatApiCallBack.cs
Normal file
38
CoreCms.Net.WeChat.Service/Models/WeChatApiCallBack.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 微信接口回调Json实体
|
||||
/// </summary>
|
||||
public class WeChatApiCallBack
|
||||
{
|
||||
/// <summary>
|
||||
/// 提交数据
|
||||
/// </summary>
|
||||
public object OtherData { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 状态码
|
||||
/// </summary>
|
||||
public bool Status { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 信息说明。
|
||||
/// </summary>
|
||||
public string Msg { get; set; } = "响应成功";
|
||||
|
||||
/// <summary>
|
||||
/// 返回数据
|
||||
/// </summary>
|
||||
public string Data { get; set; } = "success";
|
||||
}
|
||||
}
|
||||
71
CoreCms.Net.WeChat.Service/Models/WeChatUserInfo.cs
Normal file
71
CoreCms.Net.WeChat.Service/Models/WeChatUserInfo.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 1:19:20
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 微信小程序用户信息结构
|
||||
/// </summary>
|
||||
|
||||
public class WeChatUserInfo
|
||||
|
||||
{
|
||||
public string openId { get; set; }
|
||||
|
||||
public string nickName { get; set; }
|
||||
|
||||
public int gender { get; set; }
|
||||
|
||||
public string city { get; set; }
|
||||
|
||||
public string province { get; set; }
|
||||
|
||||
public string country { get; set; }
|
||||
|
||||
public string avatarUrl { get; set; }
|
||||
|
||||
public string unionId { get; set; }
|
||||
|
||||
public Watermark watermark { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
public class DecodeEntityBase
|
||||
{
|
||||
public Watermark watermark { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解码后的用户信息
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class DecodedUserInfo : DecodeEntityBase
|
||||
{
|
||||
public string openId { get; set; }
|
||||
public string nickName { get; set; }
|
||||
public int gender { get; set; }
|
||||
public string city { get; set; }
|
||||
public string province { get; set; }
|
||||
public string country { get; set; }
|
||||
public string avatarUrl { get; set; }
|
||||
public string unionId { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
48
CoreCms.Net.WeChat.Service/Options/WechatOptions.cs
Normal file
48
CoreCms.Net.WeChat.Service/Options/WechatOptions.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Options
|
||||
{
|
||||
public partial class WeChatOptions : IOptions<WeChatOptions>
|
||||
{
|
||||
WeChatOptions IOptions<WeChatOptions>.Value => this;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 微信公众号AppId
|
||||
/// </summary>
|
||||
public string WeiXinAppId { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string WeiXinAppSecret { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string WeiXinEncodingAESKey { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string WeiXinToken { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 微信小程序
|
||||
/// </summary>
|
||||
public string WxOpenAppId { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string WxOpenAppSecret { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string WxOpenToken { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string WxOpenEncodingAESKey { get; set; } = string.Empty;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using SKIT.FlurlHttpClient.Wechat.Api;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.HttpClients
|
||||
{
|
||||
public interface IWeChatApiHttpClientFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 微信公众号请求
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
WechatApiClient CreateWeXinClient();
|
||||
|
||||
/// <summary>
|
||||
/// 微信小程序请求
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
WechatApiClient CreateWxOpenClient();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Flurl;
|
||||
using Flurl.Http;
|
||||
using Flurl.Http.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
using SKIT.FlurlHttpClient;
|
||||
using SKIT.FlurlHttpClient.Wechat.Api;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.HttpClients
|
||||
{
|
||||
public partial class WeChatApiHttpClientFactory : IWeChatApiHttpClientFactory
|
||||
{
|
||||
private readonly System.Net.Http.IHttpClientFactory _httpClientFactory;
|
||||
private readonly Options.WeChatOptions _weChatOptions;
|
||||
|
||||
public WeChatApiHttpClientFactory(
|
||||
System.Net.Http.IHttpClientFactory httpClientFactory,
|
||||
IOptions<Options.WeChatOptions> weChatOptions)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_weChatOptions = weChatOptions.Value;
|
||||
|
||||
FlurlHttp.GlobalSettings.FlurlClientFactory = new DelegatingFlurlClientFactory(_httpClientFactory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信公众号请求
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public WechatApiClient CreateWeXinClient()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_weChatOptions.WeiXinAppId) || string.IsNullOrEmpty(_weChatOptions.WeiXinAppSecret))
|
||||
throw new Exception("未在配置项中找到微信公众号配置讯息。");
|
||||
|
||||
var wechatApiClient = new WechatApiClient(new WechatApiClientOptions()
|
||||
{
|
||||
AppId = _weChatOptions.WeiXinAppId,
|
||||
AppSecret = _weChatOptions.WeiXinAppSecret,
|
||||
});
|
||||
|
||||
wechatApiClient.Configure(settings =>
|
||||
{
|
||||
settings.JsonSerializer = new FlurlNewtonsoftJsonSerializer();
|
||||
});
|
||||
|
||||
return wechatApiClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信小程序请求
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public WechatApiClient CreateWxOpenClient()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_weChatOptions.WxOpenAppId) || string.IsNullOrEmpty(_weChatOptions.WxOpenAppSecret))
|
||||
throw new Exception("未在配置项中找到微信小程序配置讯息。");
|
||||
|
||||
var WechatApiClient = new WechatApiClient(new WechatApiClientOptions()
|
||||
{
|
||||
AppId = _weChatOptions.WxOpenAppId,
|
||||
AppSecret = _weChatOptions.WxOpenAppSecret
|
||||
});
|
||||
|
||||
WechatApiClient.Configure(settings =>
|
||||
{
|
||||
settings.JsonSerializer = new FlurlNewtonsoftJsonSerializer();
|
||||
});
|
||||
|
||||
return WechatApiClient;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class WeChatApiHttpClientFactory
|
||||
{
|
||||
internal class DelegatingFlurlClientFactory : IFlurlClientFactory
|
||||
{
|
||||
private readonly System.Net.Http.IHttpClientFactory _httpClientFactory;
|
||||
|
||||
public DelegatingFlurlClientFactory(System.Net.Http.IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
|
||||
}
|
||||
|
||||
public IFlurlClient Get(Url url)
|
||||
{
|
||||
return new FlurlClient(_httpClientFactory.CreateClient(url.ToUri().Host));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Do Nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
68
CoreCms.Net.WeChat.Service/Utilities/CheckSignature.cs
Normal file
68
CoreCms.Net.WeChat.Service/Utilities/CheckSignature.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 21:44:44
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CoreCms.Net.WeChat.Service.Models;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Utilities
|
||||
{
|
||||
/// <summary>签名验证类</summary>
|
||||
public class CheckSignature
|
||||
{
|
||||
/// <summary>在网站没有提供Token(或传入为null)的情况下的默认Token,建议在网站中进行配置。</summary>
|
||||
public const string Token = "weixin";
|
||||
|
||||
/// <summary>检查签名是否正确</summary>
|
||||
/// <param name="signature"></param>
|
||||
/// <param name="postModel">需要提供:Timestamp、Nonce、Token</param>
|
||||
/// <returns></returns>
|
||||
public static bool Check(string signature, PostModel postModel) => CheckSignature.Check(signature, postModel.Timestamp, postModel.Nonce, postModel.Token);
|
||||
|
||||
/// <summary>检查签名是否正确</summary>
|
||||
/// <param name="signature"></param>
|
||||
/// <param name="timestamp"></param>
|
||||
/// <param name="nonce"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Check(string signature, string timestamp, string nonce, string token = null) => signature == CheckSignature.GetSignature(timestamp, nonce, token);
|
||||
|
||||
/// <summary>返回正确的签名</summary>
|
||||
/// <param name="postModel">需要提供:Timestamp、Nonce、Token</param>
|
||||
/// <returns></returns>
|
||||
public static string GetSignature(PostModel postModel) => CheckSignature.GetSignature(postModel.Timestamp, postModel.Nonce, postModel.Token);
|
||||
|
||||
/// <summary>返回正确的签名</summary>
|
||||
/// <param name="timestamp"></param>
|
||||
/// <param name="nonce"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetSignature(string timestamp, string nonce, string token = null)
|
||||
{
|
||||
token = token ?? "weixin";
|
||||
string s = string.Join("", ((IEnumerable<string>)new string[3]
|
||||
{
|
||||
token,
|
||||
timestamp,
|
||||
nonce
|
||||
}).OrderBy<string, string>((Func<string, string>)(z => z)).ToArray<string>());
|
||||
byte[] hash = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(s));
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
foreach (byte num in hash)
|
||||
stringBuilder.AppendFormat("{0:x2}", (object)num);
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
232
CoreCms.Net.WeChat.Service/Utilities/Cryptography.cs
Normal file
232
CoreCms.Net.WeChat.Service/Utilities/Cryptography.cs
Normal file
@@ -0,0 +1,232 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
namespace CoreCms.Net.WeChat.Service.Utilities
|
||||
{
|
||||
class Cryptography
|
||||
{
|
||||
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 appid)
|
||||
{
|
||||
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[] bAppid = new byte[btmpMsg.Length - 20 - len];
|
||||
Array.Copy(btmpMsg, 20, bMsg, 0, len);
|
||||
Array.Copy(btmpMsg, 20+len , bAppid, 0, btmpMsg.Length - 20 - len);
|
||||
string oriMsg = Encoding.UTF8.GetString(bMsg);
|
||||
appid = Encoding.UTF8.GetString(bAppid);
|
||||
|
||||
|
||||
return oriMsg;
|
||||
}
|
||||
|
||||
public static String AES_encrypt(String Input, string EncodingAESKey, string appid)
|
||||
{
|
||||
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[] bAppid = Encoding.UTF8.GetBytes(appid);
|
||||
byte[] btmpMsg = Encoding.UTF8.GetBytes(Input);
|
||||
byte[] bMsgLen = BitConverter.GetBytes(HostToNetworkOrder(btmpMsg.Length));
|
||||
byte[] bMsg = new byte[bRand.Length + bMsgLen.Length + bAppid.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(bAppid, 0, bMsg, bRand.Length + bMsgLen.Length + btmpMsg.Length, bAppid.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(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;
|
||||
}
|
||||
|
||||
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[] 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
62
CoreCms.Net.WeChat.Service/Utilities/DateTimeHelper.cs
Normal file
62
CoreCms.Net.WeChat.Service/Utilities/DateTimeHelper.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 11:06:40
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Utilities
|
||||
{
|
||||
/// <summary>微信日期处理帮助类</summary>
|
||||
public class DateTimeHelper
|
||||
{
|
||||
/// <summary>Unix起始时间</summary>
|
||||
public static readonly DateTimeOffset BaseTime = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
|
||||
/// <summary>转换微信DateTime时间到C#时间</summary>
|
||||
/// <param name="dateTimeFromXml">微信DateTime</param>
|
||||
/// <returns></returns>
|
||||
public static DateTime GetDateTimeFromXml(long dateTimeFromXml) => DateTimeHelper.GetDateTimeOffsetFromXml(dateTimeFromXml).LocalDateTime;
|
||||
|
||||
/// <summary>转换微信DateTime时间到C#时间</summary>
|
||||
/// <param name="dateTimeFromXml">微信DateTime</param>
|
||||
/// <returns></returns>
|
||||
public static DateTime GetDateTimeFromXml(string dateTimeFromXml) => DateTimeHelper.GetDateTimeFromXml(long.Parse(dateTimeFromXml));
|
||||
|
||||
/// <summary>转换微信DateTimeOffset时间到C#时间</summary>
|
||||
/// <param name="dateTimeFromXml">微信DateTime</param>
|
||||
/// <returns></returns>
|
||||
public static DateTimeOffset GetDateTimeOffsetFromXml(long dateTimeFromXml) => DateTimeHelper.BaseTime.AddSeconds((double)dateTimeFromXml).ToLocalTime();
|
||||
|
||||
/// <summary>转换微信DateTimeOffset时间到C#时间</summary>
|
||||
/// <param name="dateTimeFromXml">微信DateTime</param>
|
||||
/// <returns></returns>
|
||||
public static DateTimeOffset GetDateTimeOffsetFromXml(string dateTimeFromXml) => (DateTimeOffset)DateTimeHelper.GetDateTimeFromXml(long.Parse(dateTimeFromXml));
|
||||
|
||||
/// <summary>获取微信DateTime(UNIX时间戳)</summary>
|
||||
/// <param name="dateTime">时间</param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("请使用 GetUnixDateTime(dateTime) 方法")]
|
||||
public static long GetWeixinDateTime(DateTime dateTime) => DateTimeHelper.GetUnixDateTime(dateTime);
|
||||
|
||||
/// <summary>获取Unix时间戳</summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <returns></returns>
|
||||
public static long GetUnixDateTime(DateTimeOffset dateTime) => (long)(dateTime - DateTimeHelper.BaseTime).TotalSeconds;
|
||||
|
||||
/// <summary>获取Unix时间戳</summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <returns></returns>
|
||||
public static long GetUnixDateTime(DateTime dateTime) => (long)((DateTimeOffset)dateTime.ToUniversalTime() - DateTimeHelper.BaseTime).TotalSeconds;
|
||||
}
|
||||
}
|
||||
44
CoreCms.Net.WeChat.Service/Utilities/DocumentExtensions.cs
Normal file
44
CoreCms.Net.WeChat.Service/Utilities/DocumentExtensions.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 23:53:54
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Utilities
|
||||
{
|
||||
public static class DocumentExtensions
|
||||
{
|
||||
public static XmlDocument ToXmlDocument(this XDocument xDocument)
|
||||
{
|
||||
var xmlDocument = new XmlDocument();
|
||||
using (var xmlReader = xDocument.CreateReader())
|
||||
{
|
||||
xmlDocument.Load(xmlReader);
|
||||
}
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
public static XDocument ToXDocument(this XmlDocument xmlDocument)
|
||||
{
|
||||
using (var nodeReader = new XmlNodeReader(xmlDocument))
|
||||
{
|
||||
nodeReader.MoveToContent();
|
||||
return XDocument.Load(nodeReader);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
329
CoreCms.Net.WeChat.Service/Utilities/EncryptHelper.cs
Normal file
329
CoreCms.Net.WeChat.Service/Utilities/EncryptHelper.cs
Normal file
@@ -0,0 +1,329 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 1:06:57
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CoreCms.Net.WeChat.Service.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Utilities
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 签名及加密帮助类
|
||||
/// </summary>
|
||||
public static class EncryptHelper
|
||||
{
|
||||
///// <summary>
|
||||
///// SHA1加密
|
||||
///// </summary>
|
||||
///// <param name="str"></param>
|
||||
///// <returns></returns>
|
||||
//public static string EncryptToSHA1(string str)
|
||||
//{
|
||||
// SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
|
||||
// byte[] str1 = Encoding.UTF8.GetBytes(str);
|
||||
// byte[] str2 = sha1.ComputeHash(str1);
|
||||
// sha1.Clear();
|
||||
// (sha1 as IDisposable).Dispose();
|
||||
// return Convert.ToBase64String(str2);
|
||||
//}
|
||||
|
||||
#region 签名
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获得签名
|
||||
/// </summary>
|
||||
/// <param name="rawData"></param>
|
||||
/// <param name="sessionKey"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetSignature(string rawData, string sessionKey)
|
||||
{
|
||||
var signature = GetSha1(rawData + sessionKey);
|
||||
//Senparc.Weixin.Helpers.EncryptHelper.SHA1_Encrypt(rawData + sessionKey);
|
||||
return signature;
|
||||
}
|
||||
|
||||
/// <summary>采用SHA-1算法加密字符串(小写)</summary>
|
||||
/// <param name="encypStr">需要加密的字符串</param>
|
||||
/// <returns></returns>
|
||||
public static string GetSha1(string encypStr)
|
||||
{
|
||||
byte[] hash = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(encypStr));
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
foreach (byte num in hash)
|
||||
stringBuilder.AppendFormat("{0:x2}", (object)num);
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 比较签名是否正确
|
||||
/// </summary>
|
||||
/// <param name="sessionKey"></param>
|
||||
/// <param name="rawData"></param>
|
||||
/// <param name="compareSignature"></param>
|
||||
/// <exception cref="WxOpenException">当SessionId或SessionKey无效时抛出异常</exception>
|
||||
/// <returns></returns>
|
||||
public static bool CheckSignature(string sessionKey, string rawData, string compareSignature)
|
||||
{
|
||||
var signature = GetSignature(rawData, sessionKey);
|
||||
return signature == compareSignature;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 解密
|
||||
|
||||
#region 私有方法
|
||||
|
||||
private static byte[] AES_Decrypt(String Input, byte[] Iv, byte[] Key)
|
||||
{
|
||||
#if NET45
|
||||
RijndaelManaged aes = new RijndaelManaged();
|
||||
#else
|
||||
SymmetricAlgorithm aes = Aes.Create();
|
||||
#endif
|
||||
aes.KeySize = 128;//原始:256
|
||||
aes.BlockSize = 128;
|
||||
aes.Mode = CipherMode.CBC;
|
||||
aes.Padding = PaddingMode.PKCS7;
|
||||
aes.Key = Key;
|
||||
aes.IV = Iv;
|
||||
var decrypt = aes.CreateDecryptor(aes.Key, aes.IV);
|
||||
byte[] xBuff = null;
|
||||
|
||||
//using (ICryptoTransform decrypt = aes.CreateDecryptor(aes.Key, aes.IV) /*aes.CreateDecryptor()*/)
|
||||
//{
|
||||
// var src = Convert.FromBase64String(Input);
|
||||
// byte[] dest = decrypt.TransformFinalBlock(src, 0, src.Length);
|
||||
// return dest;
|
||||
// //return Encoding.UTF8.GetString(dest);
|
||||
//}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write))
|
||||
{
|
||||
//cs.Read(decryptBytes, 0, decryptBytes.Length);
|
||||
//cs.Close();
|
||||
//ms.Close();
|
||||
|
||||
//cs.FlushFinalBlock();//用于解决第二次获取小程序Session解密出错的情况
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
//cs.Dispose();
|
||||
xBuff = decode2(ms.ToArray());
|
||||
}
|
||||
}
|
||||
catch (System.Security.Cryptography.CryptographicException)
|
||||
{
|
||||
//Padding is invalid and cannot be removed.
|
||||
Console.WriteLine("===== CryptographicException =====");
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
//cs 不自动释放,用于避免“Padding is invalid and cannot be removed”的错误 —— 2019.07.27 Jeffrey
|
||||
var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write);
|
||||
{
|
||||
//cs.Read(decryptBytes, 0, decryptBytes.Length);
|
||||
//cs.Close();
|
||||
//ms.Close();
|
||||
|
||||
//cs.FlushFinalBlock();//用于解决第二次获取小程序Session解密出错的情况
|
||||
|
||||
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);
|
||||
}
|
||||
//cs.Dispose();
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 解密所有消息的基础方法
|
||||
/// </summary>
|
||||
/// <param name="sessionKey">储存在 SessionBag 中的当前用户 会话 SessionKey</param>
|
||||
/// <param name="encryptedData">接口返回数据中的 encryptedData 参数</param>
|
||||
/// <param name="iv">接口返回数据中的 iv 参数,对称解密算法初始向量</param>
|
||||
/// <returns></returns>
|
||||
public static string DecodeEncryptedData(string sessionKey, string encryptedData, string iv)
|
||||
{
|
||||
//var aesCipher = Convert.FromBase64String(encryptedData);
|
||||
var aesKey = Convert.FromBase64String(sessionKey);
|
||||
var aesIV = Convert.FromBase64String(iv);
|
||||
|
||||
var result = AES_Decrypt(encryptedData, aesIV, aesKey);
|
||||
var resultStr = Encoding.UTF8.GetString(result);
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解密消息(通过SessionId获取)
|
||||
/// </summary>
|
||||
/// <param name="sessionKey"></param>
|
||||
/// <param name="encryptedData"></param>
|
||||
/// <param name="iv"></param>
|
||||
/// <exception cref="WxOpenException">当SessionId或SessionKey无效时抛出异常</exception>
|
||||
/// <returns></returns>
|
||||
public static string DecodeEncryptedDataBySessionId(string sessionKey, string encryptedData, string iv)
|
||||
{
|
||||
var resultStr = DecodeEncryptedData(sessionKey, encryptedData, iv);
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 检查解密消息水印
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="appId"></param>
|
||||
/// <returns>entity为null时也会返回false</returns>
|
||||
public static bool CheckWatermark(this DecodeEntityBase entity, string appId)
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return entity.watermark.appid == appId;
|
||||
}
|
||||
|
||||
#region 解密实例信息
|
||||
|
||||
/// <summary>
|
||||
/// 解密到实例信息
|
||||
/// </summary>
|
||||
/// <typeparam name="T">DecodeEntityBase</typeparam>
|
||||
/// <param name="sessionKey"></param>
|
||||
/// <param name="encryptedData"></param>
|
||||
/// <param name="iv"></param>
|
||||
/// <returns></returns>
|
||||
public static T DecodeEncryptedDataToEntity<T>(string sessionKey, string encryptedData, string iv)
|
||||
{
|
||||
var jsonStr = DecodeEncryptedDataBySessionId(sessionKey, encryptedData, iv);
|
||||
|
||||
//Console.WriteLine("===== jsonStr =====");
|
||||
//Console.WriteLine(jsonStr);
|
||||
//Console.WriteLine();
|
||||
|
||||
var entity = JsonConvert.DeserializeObject<T>(jsonStr);
|
||||
return entity;
|
||||
}
|
||||
/// <summary>
|
||||
/// 解密到实例信息
|
||||
/// </summary>
|
||||
/// <typeparam name="T">DecodeEntityBase</typeparam>
|
||||
/// <param name="sessionKey"></param>
|
||||
/// <param name="encryptedData"></param>
|
||||
/// <param name="iv"></param>
|
||||
/// <returns></returns>
|
||||
public static T DecodeEncryptedDataToEntityEasy<T>(string sessionKey, string encryptedData, string iv)
|
||||
{
|
||||
var jsonStr = DecodeEncryptedData(sessionKey, encryptedData, iv);
|
||||
var entity = JsonConvert.DeserializeObject<T>(jsonStr);
|
||||
return entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解密UserInfo消息(通过SessionId获取)
|
||||
/// </summary>
|
||||
/// <param name="sessionKey"></param>
|
||||
/// <param name="encryptedData"></param>
|
||||
/// <param name="iv"></param>
|
||||
/// <exception cref="WxOpenException">当SessionId或SessionKey无效时抛出异常</exception>
|
||||
/// <returns></returns>
|
||||
public static DecodedUserInfo DecodeUserInfoBySessionId(string sessionKey, string encryptedData, string iv)
|
||||
{
|
||||
return DecodeEncryptedDataToEntity<DecodedUserInfo>(sessionKey, encryptedData, iv);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解密手机号
|
||||
/// </summary>
|
||||
/// <param name="sessionKey"></param>
|
||||
/// <param name="encryptedData"></param>
|
||||
/// <param name="iv"></param>
|
||||
/// <returns></returns>
|
||||
public static DecodedPhoneNumber DecryptPhoneNumber(string sessionKey, string encryptedData, string iv)
|
||||
{
|
||||
return DecodeEncryptedDataToEntity<DecodedPhoneNumber>(sessionKey, encryptedData, iv);
|
||||
}
|
||||
/// <summary>
|
||||
/// 解密手机号(根据sessionKey解密)
|
||||
/// </summary>
|
||||
/// <param name="sessionKey"></param>
|
||||
/// <param name="encryptedData"></param>
|
||||
/// <param name="iv"></param>
|
||||
/// <returns></returns>
|
||||
public static DecodedPhoneNumber DecryptPhoneNumberBySessionKey(string sessionKey, string encryptedData, string iv)
|
||||
{
|
||||
//var resultStr = DecodeEncryptedData(sessionKey, encryptedData, iv);
|
||||
|
||||
//var entity = SerializerHelper.GetObject<DecodedPhoneNumber>(resultStr);
|
||||
//return entity;
|
||||
|
||||
return DecodeEncryptedDataToEntityEasy<DecodedPhoneNumber>(sessionKey, encryptedData, iv);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解密微信小程序运动步数
|
||||
/// 2019-04-02
|
||||
/// </summary>
|
||||
/// <param name="sessionId"></param>
|
||||
/// <param name="encryptedData"></param>
|
||||
/// <param name="iv"></param>
|
||||
/// <returns></returns>
|
||||
public static DecodedRunData DecryptRunData(string sessionId, string encryptedData, string iv)
|
||||
{
|
||||
return DecodeEncryptedDataToEntity<DecodedRunData>(sessionId, encryptedData, iv);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
76
CoreCms.Net.WeChat.Service/Utilities/RequestUtility.cs
Normal file
76
CoreCms.Net.WeChat.Service/Utilities/RequestUtility.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 23:24:45
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Utilities
|
||||
{
|
||||
/// <summary>HTTP 请求工具类</summary>
|
||||
public static class RequestUtility
|
||||
{
|
||||
/// <summary>【异步方法】从 Request.Body 中读取流,并复制到一个独立的 MemoryStream 对象中</summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="allowSynchronousIO"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<Stream> GetRequestMemoryStreamAsync(
|
||||
this HttpRequest request,
|
||||
bool? allowSynchronousIO = true)
|
||||
{
|
||||
IHttpBodyControlFeature bodyControlFeature = request.HttpContext.Features.Get<IHttpBodyControlFeature>();
|
||||
if (bodyControlFeature != null && allowSynchronousIO.HasValue)
|
||||
bodyControlFeature.AllowSynchronousIO = allowSynchronousIO.Value;
|
||||
return (Stream)new MemoryStream(Encoding.UTF8.GetBytes(await new StreamReader(request.Body).ReadToEndAsync()));
|
||||
}
|
||||
|
||||
/// <summary>从 Request.Body 中读取流,并复制到一个独立的 MemoryStream 对象中</summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="allowSynchronousIO"></param>
|
||||
/// <returns></returns>
|
||||
public static Stream GetRequestStream(
|
||||
this HttpRequest request,
|
||||
bool? allowSynchronousIO = true)
|
||||
{
|
||||
IHttpBodyControlFeature bodyControlFeature = request.HttpContext.Features.Get<IHttpBodyControlFeature>();
|
||||
if (bodyControlFeature != null && allowSynchronousIO.HasValue)
|
||||
bodyControlFeature.AllowSynchronousIO = allowSynchronousIO.Value;
|
||||
return (Stream)new MemoryStream(Encoding.UTF8.GetBytes(new StreamReader(request.Body).ReadToEnd()));
|
||||
}
|
||||
|
||||
/// <summary>从 Request.Body 中读取流,并复制到一个独立的 MemoryStream 对象中</summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="allowSynchronousIO"></param>
|
||||
/// <returns></returns>
|
||||
public static MemoryStream GetRequestMemoryStream(
|
||||
this HttpRequest request,
|
||||
bool? allowSynchronousIO = true)
|
||||
{
|
||||
IHttpBodyControlFeature bodyControlFeature = request.HttpContext.Features.Get<IHttpBodyControlFeature>();
|
||||
if (bodyControlFeature != null && allowSynchronousIO.HasValue)
|
||||
bodyControlFeature.AllowSynchronousIO = allowSynchronousIO.Value;
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes(new StreamReader(request.Body).ReadToEnd()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
221
CoreCms.Net.WeChat.Service/Utilities/WXBizMsgCrypt.cs
Normal file
221
CoreCms.Net.WeChat.Service/Utilities/WXBizMsgCrypt.cs
Normal file
@@ -0,0 +1,221 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Collections;
|
||||
//using System.Web;
|
||||
using System.Security.Cryptography;
|
||||
//-40001 : 签名验证错误
|
||||
//-40002 : xml解析失败
|
||||
//-40003 : sha加密生成签名失败
|
||||
//-40004 : AESKey 非法
|
||||
//-40005 : appid 校验错误
|
||||
//-40006 : AES 加密失败
|
||||
//-40007 : AES 解密失败
|
||||
//-40008 : 解密后得到的buffer非法
|
||||
//-40009 : base64加密异常
|
||||
//-40010 : base64解密异常
|
||||
namespace CoreCms.Net.WeChat.Service.Utilities
|
||||
{
|
||||
public class WXBizMsgCrypt
|
||||
{
|
||||
string m_sToken;
|
||||
string m_sEncodingAESKey;
|
||||
string m_sAppID;
|
||||
enum WXBizMsgCryptErrorCode
|
||||
{
|
||||
WXBizMsgCrypt_OK = 0,
|
||||
WXBizMsgCrypt_ValidateSignature_Error = -40001,
|
||||
WXBizMsgCrypt_ParseXml_Error = -40002,
|
||||
WXBizMsgCrypt_ComputeSignature_Error = -40003,
|
||||
WXBizMsgCrypt_IllegalAesKey = -40004,
|
||||
WXBizMsgCrypt_ValidateAppid_Error = -40005,
|
||||
WXBizMsgCrypt_EncryptAES_Error = -40006,
|
||||
WXBizMsgCrypt_DecryptAES_Error = -40007,
|
||||
WXBizMsgCrypt_IllegalBuffer = -40008,
|
||||
WXBizMsgCrypt_EncodeBase64_Error = -40009,
|
||||
WXBizMsgCrypt_DecodeBase64_Error = -40010
|
||||
};
|
||||
|
||||
//构造函数
|
||||
// @param sToken: 公众平台上,开发者设置的Token
|
||||
// @param sEncodingAESKey: 公众平台上,开发者设置的EncodingAESKey
|
||||
// @param sAppID: 公众帐号的appid
|
||||
public WXBizMsgCrypt(string sToken, string sEncodingAESKey, string sAppID)
|
||||
{
|
||||
m_sToken = sToken;
|
||||
m_sAppID = sAppID;
|
||||
m_sEncodingAESKey = sEncodingAESKey;
|
||||
}
|
||||
|
||||
|
||||
// 检验消息的真实性,并且获取解密后的明文
|
||||
// @param sMsgSignature: 签名串,对应URL参数的msg_signature
|
||||
// @param sTimeStamp: 时间戳,对应URL参数的timestamp
|
||||
// @param sNonce: 随机串,对应URL参数的nonce
|
||||
// @param sPostData: 密文,对应POST请求的数据
|
||||
// @param sMsg: 解密后的原文,当return返回0时有效
|
||||
// @return: 成功0,失败返回对应的错误码
|
||||
public int DecryptMsg(string sMsgSignature, string sTimeStamp, string sNonce, string sPostData, ref string sMsg)
|
||||
{
|
||||
if (m_sEncodingAESKey.Length != 43)
|
||||
{
|
||||
return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey;
|
||||
}
|
||||
XmlDocument doc = new XmlDocument();
|
||||
XmlNode root;
|
||||
string sEncryptMsg;
|
||||
try
|
||||
{
|
||||
doc.LoadXml(sPostData);
|
||||
root = doc.FirstChild;
|
||||
sEncryptMsg = root["Encrypt"].InnerText;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ParseXml_Error;
|
||||
}
|
||||
//verify signature
|
||||
int ret = 0;
|
||||
ret = VerifySignature(m_sToken, sTimeStamp, sNonce, sEncryptMsg, sMsgSignature);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
//decrypt
|
||||
string cpid = "";
|
||||
try
|
||||
{
|
||||
sMsg = Cryptography.AES_decrypt(sEncryptMsg, m_sEncodingAESKey, ref cpid);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_DecodeBase64_Error;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_DecryptAES_Error;
|
||||
}
|
||||
if (cpid != m_sAppID)
|
||||
return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ValidateAppid_Error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//将企业号回复用户的消息加密打包
|
||||
// @param sReplyMsg: 企业号待回复用户的消息,xml格式的字符串
|
||||
// @param sTimeStamp: 时间戳,可以自己生成,也可以用URL参数的timestamp
|
||||
// @param sNonce: 随机串,可以自己生成,也可以用URL参数的nonce
|
||||
// @param sEncryptMsg: 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串,
|
||||
// 当return返回0时有效
|
||||
// return:成功0,失败返回对应的错误码
|
||||
public int EncryptMsg(string sReplyMsg, string sTimeStamp, string sNonce, ref string sEncryptMsg)
|
||||
{
|
||||
if (m_sEncodingAESKey.Length != 43)
|
||||
{
|
||||
return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey;
|
||||
}
|
||||
string raw = "";
|
||||
try
|
||||
{
|
||||
raw = Cryptography.AES_encrypt(sReplyMsg, m_sEncodingAESKey, m_sAppID);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_EncryptAES_Error;
|
||||
}
|
||||
string MsgSigature = "";
|
||||
int ret = 0;
|
||||
ret = GenarateSinature(m_sToken, sTimeStamp, sNonce, raw, ref MsgSigature);
|
||||
if (0 != ret)
|
||||
return ret;
|
||||
sEncryptMsg = "";
|
||||
|
||||
string EncryptLabelHead = "<Encrypt><![CDATA[";
|
||||
string EncryptLabelTail = "]]></Encrypt>";
|
||||
string MsgSigLabelHead = "<MsgSignature><![CDATA[";
|
||||
string MsgSigLabelTail = "]]></MsgSignature>";
|
||||
string TimeStampLabelHead = "<TimeStamp><![CDATA[";
|
||||
string TimeStampLabelTail = "]]></TimeStamp>";
|
||||
string NonceLabelHead = "<Nonce><![CDATA[";
|
||||
string NonceLabelTail = "]]></Nonce>";
|
||||
sEncryptMsg = sEncryptMsg + "<xml>" + EncryptLabelHead + raw + EncryptLabelTail;
|
||||
sEncryptMsg = sEncryptMsg + MsgSigLabelHead + MsgSigature + MsgSigLabelTail;
|
||||
sEncryptMsg = sEncryptMsg + TimeStampLabelHead + sTimeStamp + TimeStampLabelTail;
|
||||
sEncryptMsg = sEncryptMsg + NonceLabelHead + sNonce + NonceLabelTail;
|
||||
sEncryptMsg += "</xml>";
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
//Verify Signature
|
||||
private static int VerifySignature(string sToken, string sTimeStamp, string sNonce, string sMsgEncrypt, string sSigture)
|
||||
{
|
||||
string hash = "";
|
||||
int ret = 0;
|
||||
ret = GenarateSinature(sToken, sTimeStamp, sNonce, sMsgEncrypt, ref hash);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
//System.Console.WriteLine(hash);
|
||||
if (hash == sSigture)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ValidateSignature_Error;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GenarateSinature(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)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ComputeSignature_Error;
|
||||
}
|
||||
sMsgSignature = hash;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
CoreCms.Net.WeChat.Service/Utilities/WxOfficialHelper.cs
Normal file
33
CoreCms.Net.WeChat.Service/Utilities/WxOfficialHelper.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 12:25:49
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// 微信公众号帮助类
|
||||
/// </summary>
|
||||
public static class WxOfficialHelper
|
||||
{
|
||||
|
||||
public static string geturl(string url, string weXinAppId, int scope = 1)
|
||||
{
|
||||
|
||||
return "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + weXinAppId + "&redirect_uri=" + url + "&response_type=code&scope=" + scope + "&state=jshop#wechat_redirect";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
97
CoreCms.Net.WeChat.Service/Utilities/XmlUtility.cs
Normal file
97
CoreCms.Net.WeChat.Service/Utilities/XmlUtility.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/7/29 23:21:06
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace CoreCms.Net.WeChat.Service.Utilities
|
||||
{
|
||||
/// <summary>XML 工具类</summary>
|
||||
public static class XmlUtility
|
||||
{
|
||||
/// <summary>反序列化</summary>
|
||||
/// <param name="xml">XML字符串</param>
|
||||
/// <returns></returns>
|
||||
public static object Deserialize<T>(string xml)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (StringReader stringReader = new StringReader(xml))
|
||||
return new XmlSerializer(typeof(T)).Deserialize((TextReader)stringReader);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine((object)ex);
|
||||
return (object)null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>反序列化</summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <returns></returns>
|
||||
public static object Deserialize<T>(Stream stream) => new XmlSerializer(typeof(T)).Deserialize(stream);
|
||||
|
||||
/// <summary>
|
||||
/// 序列化
|
||||
/// 说明:此方法序列化复杂类,如果没有声明XmlInclude等特性,可能会引发“使用 XmlInclude 或 SoapInclude 特性静态指定非已知的类型。”的错误。
|
||||
/// </summary>
|
||||
/// <param name="obj">对象</param>
|
||||
/// <returns></returns>
|
||||
public static string Serializer<T>(T obj)
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
|
||||
try
|
||||
{
|
||||
xmlSerializer.Serialize((Stream)memoryStream, (object)obj);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
memoryStream.Position = 0L;
|
||||
StreamReader streamReader = new StreamReader((Stream)memoryStream);
|
||||
string end = streamReader.ReadToEnd();
|
||||
streamReader.Dispose();
|
||||
memoryStream.Dispose();
|
||||
return end;
|
||||
}
|
||||
|
||||
/// <summary>序列化将流转成XML字符串</summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <returns></returns>
|
||||
public static XDocument Convert(Stream stream)
|
||||
{
|
||||
if (stream.CanSeek)
|
||||
stream.Seek(0L, SeekOrigin.Begin);
|
||||
using (XmlReader reader = XmlReader.Create(stream))
|
||||
return XDocument.Load(reader);
|
||||
}
|
||||
|
||||
/// <summary>序列化将流转成XML字符串</summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <returns></returns>
|
||||
public static string ConvertToString(Stream stream)
|
||||
{
|
||||
StreamReader reader = new StreamReader(stream);
|
||||
string sHtml = reader.ReadToEnd();
|
||||
return sHtml;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user