Skip to content

Commit

Permalink
Merge pull request #91 from EasyAbp/official-events
Browse files Browse the repository at this point in the history
Introduce WeChat official account event handling
  • Loading branch information
gdlcf88 committed Jul 13, 2023
2 parents 5fef55f + b074d05 commit 73cc30f
Show file tree
Hide file tree
Showing 41 changed files with 466 additions and 73 deletions.
2 changes: 1 addition & 1 deletion common.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>2.7.0-preview.2</Version>
<Version>3.0.0-preview.1</Version>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>EasyAbp Team</Authors>
Expand Down
8 changes: 4 additions & 4 deletions docs/WeChatOfficial.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ var result = await customMenuService.DeleteCustomMenuAsync();
在您调用服务,或处理微信请求的事件通知回调时,若提供的 `appId` 与 Setting 中的默认值可能不同,则您需要手动实现 `IAbpWeChatOptionsProvider<TOptions>`,若使用 EasyAbp 封装的[微信管理模块](https://github.com/EasyAbp/WeChatManagement),则您无需再手动实现。

本模块提供的用于微信服务器通讯的 HTTP API 接口,也支持多应用和多租户,您需要使用合适的替代路由:
* `/wechat/verify`
* `/wechat/verify/tenant-id/{tenantId}`
* `/wechat/verify/app-id/{appId}`
* `/wechat/verify/tenant-id/{tenantId}/app-id/{appId}`
* `/wechat/notify`
* `/wechat/notify/tenant-id/{tenantId}`
* `/wechat/notify/app-id/{appId}`
* `/wechat/notify/tenant-id/{tenantId}/app-id/{appId}`
* `/wechat/redirect-url`
* `/wechat/redirect-url/tenant-id/{tenantId}`
* `/wechat/redirect-url/app-id/{appId}`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using EasyAbp.Abp.WeChat.Common.RequestHandling;
using JetBrains.Annotations;
using JetBrains.Annotations;

namespace EasyAbp.Abp.WeChat.OpenPlatform.RequestHandling.Dtos;
namespace EasyAbp.Abp.WeChat.Common.RequestHandling.Dtos;

public class AppEventHandlingResult : WeChatRequestHandlingResult
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace EasyAbp.Abp.WeChat.OpenPlatform.RequestHandling.Dtos;
namespace EasyAbp.Abp.WeChat.Common.RequestHandling.Dtos;

public interface IResponseToWeChatModel
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace EasyAbp.Abp.WeChat.OpenPlatform.RequestHandling.Dtos;
namespace EasyAbp.Abp.WeChat.Common.RequestHandling.Dtos;

public class JsonResponseToWeChatModel : IResponseToWeChatModel
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace EasyAbp.Abp.WeChat.Common.RequestHandling.Dtos;

public class PlainTextResponseToWeChatModel : IResponseToWeChatModel
{
public string Content { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ public class WeChatEventRequestModel

public string Timestamp { get; set; }

public string Notice { get; set; }
public string Nonce { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace EasyAbp.Abp.WeChat.OpenPlatform.RequestHandling.Dtos;
namespace EasyAbp.Abp.WeChat.Common.RequestHandling.Dtos;

public class XmlResponseToWeChatModel : IResponseToWeChatModel
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Threading.Tasks;
using EasyAbp.Abp.WeChat.Common.Infrastructure.Encryption;
using EasyAbp.Abp.WeChat.Common.Infrastructure.Options;
using EasyAbp.Abp.WeChat.Common.RequestHandling.Dtos;
using Volo.Abp.ObjectExtending;

namespace EasyAbp.Abp.WeChat.Common.RequestHandling;

public class WeChatEventRequestHandlingServiceBase<TOptions> where TOptions : IAbpWeChatOptions
{
protected IWeChatNotificationEncryptor WeChatNotificationEncryptor { get; }

public WeChatEventRequestHandlingServiceBase(IWeChatNotificationEncryptor weChatNotificationEncryptor)
{
WeChatNotificationEncryptor = weChatNotificationEncryptor;
}

protected virtual async Task<T> DecryptMsgAsync<T>(TOptions options,
WeChatEventRequestModel request) where T : ExtensibleObject, new()
{
return await WeChatNotificationEncryptor.DecryptAsync<T>(
options.Token,
options.EncodingAesKey,
options.AppId,
request.MsgSignature,
request.Timestamp,
request.Nonce,
request.PostData);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>EasyAbp.Abp.WeChat.OpenPlatform</RootNamespace>
<RootNamespace>EasyAbp.Abp.WeChat.Official</RootNamespace>
<Description>ABP vNext微信公众号模块,提供对微信公众号业务的支持。</Description>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using EasyAbp.Abp.WeChat.Common.RequestHandling;

namespace EasyAbp.Abp.WeChat.OpenPlatform.RequestHandling;
namespace EasyAbp.Abp.WeChat.Official.RequestHandling;

public class GetAccessTokenByCodeResult : WeChatRequestHandlingResult
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using EasyAbp.Abp.WeChat.Common.RequestHandling;

namespace EasyAbp.Abp.WeChat.OpenPlatform.RequestHandling;
namespace EasyAbp.Abp.WeChat.Official.RequestHandling;

public class GetJsSdkConfigParametersResult : WeChatRequestHandlingResult
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Threading.Tasks;
using JetBrains.Annotations;

namespace EasyAbp.Abp.WeChat.OpenPlatform.RequestHandling;
namespace EasyAbp.Abp.WeChat.Official.RequestHandling;

public interface IWeChatOfficialClientRequestHandlingService
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
using System.Threading.Tasks;
using System;
using System.Threading.Tasks;
using EasyAbp.Abp.WeChat.Common.RequestHandling.Dtos;
using JetBrains.Annotations;

namespace EasyAbp.Abp.WeChat.OpenPlatform.RequestHandling;
namespace EasyAbp.Abp.WeChat.Official.RequestHandling;

public interface IWeChatOfficialEventRequestHandlingService
{
Task<AppEventHandlingResult> NotifyAsync(WeChatOfficialEventRequestModel input, [CanBeNull] string appId);

[Obsolete("请使用统一的Notify接口")]
Task<StringValueWeChatRequestHandlingResult> VerifyAsync(VerifyRequestDto input, [CanBeNull] string appId);

Task<StringValueWeChatRequestHandlingResult> GetOAuthRedirectUrlAsync(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace EasyAbp.Abp.WeChat.OpenPlatform.RequestHandling
namespace EasyAbp.Abp.WeChat.Official.RequestHandling
{
public class RedirectUrlRequest
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using EasyAbp.Abp.WeChat.Common.RequestHandling;

namespace EasyAbp.Abp.WeChat.OpenPlatform.RequestHandling;
namespace EasyAbp.Abp.WeChat.Official.RequestHandling;

public class StringValueWeChatRequestHandlingResult : WeChatRequestHandlingResult
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
namespace EasyAbp.Abp.WeChat.OpenPlatform.RequestHandling
using System;

namespace EasyAbp.Abp.WeChat.Official.RequestHandling
{
[Obsolete("请使用统一的Notify接口")]
public class VerifyRequestDto
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using EasyAbp.Abp.WeChat.Common.RequestHandling.Dtos;

namespace EasyAbp.Abp.WeChat.Official.RequestHandling;

[Serializable]
public class WeChatOfficialEventRequestModel : WeChatEventRequestModel
{
/// <summary>
/// 用于微信公众号验证
/// </summary>
public string EchoStr { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EasyAbp.Abp.WeChat.Common;
using EasyAbp.Abp.WeChat.OpenPlatform.RequestHandling;
using EasyAbp.Abp.WeChat.Common.RequestHandling.Dtos;
using EasyAbp.Abp.WeChat.Official.RequestHandling;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Net.Http.Headers;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;

Expand All @@ -26,6 +32,7 @@ public class WeChatController : AbpControllerBase
_clientRequestHandlingService = clientRequestHandlingService;
}

[Obsolete("请使用统一的Notify接口")]
[HttpGet]
[Route("verify")]
public virtual async Task<string> VerifyAsync(
Expand All @@ -42,6 +49,7 @@ public class WeChatController : AbpControllerBase
/// 本方法是为了避免多 Route 导致 ABP ApiDescription 报 Warning。
/// 见 <see cref="VerifyAsync"/>
/// </summary>
[Obsolete("请使用统一的Notify接口")]
[HttpGet]
[Route("verify/tenant-id/{tenantId}")]
public virtual Task<string> Verify2Async(
Expand All @@ -54,6 +62,7 @@ public class WeChatController : AbpControllerBase
/// 本方法是为了避免多 Route 导致 ABP ApiDescription 报 Warning。
/// 见 <see cref="VerifyAsync"/>
/// </summary>
[Obsolete("请使用统一的Notify接口")]
[HttpGet]
[Route("verify/app-id/{appId}")]
public virtual Task<string> Verify3Async(
Expand All @@ -66,6 +75,7 @@ public class WeChatController : AbpControllerBase
/// 本方法是为了避免多 Route 导致 ABP ApiDescription 报 Warning。
/// 见 <see cref="VerifyAsync"/>
/// </summary>
[Obsolete("请使用统一的Notify接口")]
[HttpGet]
[Route("verify/tenant-id/{tenantId}/app-id/{appId}")]
public virtual Task<string> Verify4Async(
Expand Down Expand Up @@ -169,5 +179,94 @@ public class WeChatController : AbpControllerBase
jsapi_ticket = result.Ticket
});
}

/// <summary>
/// 微信应用事件通知接口,开发人员需要实现 <see cref="IWeChatOfficialAppEventHandler"/> 处理器来处理回调请求。
/// </summary>
[HttpPost]
[Route("notify")]
public virtual async Task<ActionResult> NotifyAsync([CanBeNull] string tenantId, [CanBeNull] string appId)
{
using var changeTenant = CurrentTenant.Change(tenantId.IsNullOrWhiteSpace() ? null : Guid.Parse(tenantId!));

var result = await _eventRequestHandlingService.NotifyAsync(await CreateRequestModelAsync(), appId);

if (!result.Success)
{
return BadRequest();
}

var contentType = new MediaTypeHeaderValue(result.ResponseToWeChatModel switch
{
JsonResponseToWeChatModel => "application/json",
XmlResponseToWeChatModel => "application/xml",
null => "text/plain",
_ => "text/plain"
})
{
Charset = Encoding.UTF8.WebName
};

return new ContentResult
{
ContentType = contentType.ToString(),
Content = result.ResponseToWeChatModel?.Content ?? "success",
StatusCode = 200
};
}

/// <summary>
/// 本方法是为了避免多 Route 导致 ABP ApiDescription 报 Warning。
/// 见 <see cref="NotifyAsync"/>
/// </summary>
[HttpPost]
[Route("notify/tenant-id/{tenantId}")]
public virtual Task<ActionResult> Notify2Async([CanBeNull] string tenantId, [NotNull] string appId)
{
return NotifyAsync(tenantId, appId);
}

/// <summary>
/// 本方法是为了避免多 Route 导致 ABP ApiDescription 报 Warning。
/// 见 <see cref="NotifyAsync"/>
/// </summary>
[HttpPost]
[Route("notify/app-id/{appId}")]
public virtual Task<ActionResult> Notify3Async([CanBeNull] string tenantId, [NotNull] string appId)
{
return NotifyAsync(tenantId, appId);
}

/// <summary>
/// 本方法是为了避免多 Route 导致 ABP ApiDescription 报 Warning。
/// 见 <see cref="NotifyAsync"/>
/// </summary>
[HttpPost]
[Route("notify/tenant-id/{tenantId}/app-id/{appId}")]
public virtual Task<ActionResult> Notify4Async([CanBeNull] string tenantId, [NotNull] string appId)
{
return NotifyAsync(tenantId, appId);
}

protected virtual async Task<WeChatOfficialEventRequestModel> CreateRequestModelAsync()
{
Request.EnableBuffering();

using var streamReader = new StreamReader(Request.Body);

var postData = await streamReader.ReadToEndAsync();

Request.Body.Position = 0;

return new WeChatOfficialEventRequestModel
{
PostData = postData,
MsgSignature = Request.Query["msg_signature"].FirstOrDefault() ??
Request.Query["signature"].FirstOrDefault(),
Timestamp = Request.Query["timestamp"].FirstOrDefault(),
Nonce = Request.Query["nonce"].FirstOrDefault(),
EchoStr = Request.Query["echostr"].FirstOrDefault()
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Threading.Tasks;
using EasyAbp.Abp.WeChat.Common.Models;
using EasyAbp.Abp.WeChat.Common.RequestHandling.Dtos;
using JetBrains.Annotations;

namespace EasyAbp.Abp.WeChat.Official.RequestHandling;

/// <summary>
/// 微信公众号事件通知处理者
/// </summary>
public interface IWeChatOfficialAppEventHandler
{
/// <summary>
/// 仅处理回调请求中,相应的 MsgType 值的事件
/// </summary>
public string MsgType { get; }

/// <summary>
/// Handler 执行的优先级,值更大的先执行
/// </summary>
public int Priority { get; }

/// <summary>
/// 事件处理实现。
/// </summary>
Task<AppEventHandlingResult> HandleAsync([NotNull] string appId, WeChatAppEventModel model);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using JetBrains.Annotations;

namespace EasyAbp.Abp.WeChat.Official.RequestHandling;

public interface IWeChatOfficialAppEventHandlerResolver
{
Task<List<IWeChatOfficialAppEventHandler>> GetAppEventHandlersAsync([CanBeNull] string msgType);
}

0 comments on commit 73cc30f

Please sign in to comment.