Browse Source

增加微信小程序通知提供者;增加微信公共token模块

pull/7/head
cKey 6 years ago
parent
commit
0a1b5dd977
  1. 4
      aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN.Abp.IdentityServer.WeChatValidator.csproj
  2. 6
      aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/AbpIdentityServerWeChatValidatorModule.cs
  3. 21
      aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatValidator/WeChatTokenGrantValidator.cs
  4. 6
      aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Net/Http/HttpClientTokenRequestExtensions.cs
  5. 2
      aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Net/Http/WeChatOpenIdRequest.cs
  6. 2
      aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Net/Http/WeChatOpenIdResponse.cs
  7. 3
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN.Abp.Notifications.WeChat.WeApp.csproj
  8. 30
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/AbpNotificationsWeChatWeAppModule.cs
  9. 18
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/AbpWeChatWeAppNotificationOptions.cs
  10. 9
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/IWeChatWeAppNotificationSender.cs
  11. 76
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppNotificationPublishProvider.cs
  12. 93
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppNotificationSender.cs
  13. 45
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppSendNotificationData.cs
  14. 25
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeChatNotificationPublishProvider.cs
  15. 3
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDispatcher.cs
  16. 59
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSubscriptionManager.cs
  17. 24
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/DefaultNotificationDispatcher.cs
  18. 55
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/NotificationSubscriptionManager.cs
  19. 30
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs
  20. 16
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Local/UserCreateSendWelcomeEventHandler.cs
  21. 14
      aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN.Abp.WeChat.Authorization.csproj
  22. 25
      aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/AbpWeChatAuthorizationModule.cs
  23. 4
      aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/AbpWeChatOptions.cs
  24. 9
      aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/IWeChatTokenProvider.cs
  25. 26
      aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatToken.cs
  26. 24
      aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatTokenCacheItem.cs
  27. 88
      aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatTokenProvider.cs
  28. 10
      aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatTokenRequest.cs
  29. 41
      aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatTokenResponse.cs
  30. 26
      aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/System/Net/Http/HttpClientWeChatTokenRequestExtensions.cs
  31. 5
      aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Controllers/NotificationController.cs
  32. 1
      aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj
  33. 2
      aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs

4
aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN.Abp.IdentityServer.WeChatValidator.csproj

@ -19,4 +19,8 @@
<PackageReference Include="Volo.Abp.IdentityServer.Domain" Version="2.9.0" /> <PackageReference Include="Volo.Abp.IdentityServer.Domain" Version="2.9.0" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\moudles\common\LINGYUN.Abp.WeChat.Authorization\LINGYUN.Abp.WeChat.Authorization.csproj" />
</ItemGroup>
</Project> </Project>

6
aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/AbpIdentityServerWeChatValidatorModule.cs

@ -1,4 +1,5 @@
using LINGYUN.Abp.IdentityServer.WeChatValidator; using LINGYUN.Abp.IdentityServer.WeChatValidator;
using LINGYUN.Abp.WeChat.Authorization;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.IdentityServer; using Volo.Abp.IdentityServer;
using Volo.Abp.IdentityServer.Localization; using Volo.Abp.IdentityServer.Localization;
@ -8,7 +9,9 @@ using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.IdentityServer namespace LINGYUN.Abp.IdentityServer
{ {
[DependsOn(typeof(AbpIdentityServerDomainModule))] [DependsOn(
typeof(AbpWeChatAuthorizationModule),
typeof(AbpIdentityServerDomainModule))]
public class AbpIdentityServerWeChatValidatorModule : AbpModule public class AbpIdentityServerWeChatValidatorModule : AbpModule
{ {
public override void PreConfigureServices(ServiceConfigurationContext context) public override void PreConfigureServices(ServiceConfigurationContext context)
@ -23,7 +26,6 @@ namespace LINGYUN.Abp.IdentityServer
{ {
var configuration = context.Services.GetConfiguration(); var configuration = context.Services.GetConfiguration();
Configure<AbpWeChatValidatorOptions>(configuration.GetSection("AuthServer:WeChat"));
Configure<WeChatSignatureOptions>(configuration.GetSection("WeChat:Signature")); Configure<WeChatSignatureOptions>(configuration.GetSection("WeChat:Signature"));
context.Services.AddHttpClient(WeChatValidatorConsts.WeChatValidatorClientName, options => context.Services.AddHttpClient(WeChatValidatorConsts.WeChatValidatorClientName, options =>

21
aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatValidator/WeChatTokenGrantValidator.cs

@ -3,6 +3,7 @@ using IdentityServer4.Events;
using IdentityServer4.Models; using IdentityServer4.Models;
using IdentityServer4.Services; using IdentityServer4.Services;
using IdentityServer4.Validation; using IdentityServer4.Validation;
using LINGYUN.Abp.WeChat.Authorization;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -22,7 +23,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChatValidator
public class WeChatTokenGrantValidator : IExtensionGrantValidator public class WeChatTokenGrantValidator : IExtensionGrantValidator
{ {
protected ILogger<WeChatTokenGrantValidator> Logger { get; } protected ILogger<WeChatTokenGrantValidator> Logger { get; }
protected AbpWeChatValidatorOptions Options { get; } protected AbpWeChatOptions Options { get; }
protected IHttpClientFactory HttpClientFactory{ get; } protected IHttpClientFactory HttpClientFactory{ get; }
protected IEventService EventService { get; } protected IEventService EventService { get; }
protected IIdentityUserRepository UserRepository { get; } protected IIdentityUserRepository UserRepository { get; }
@ -40,7 +41,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChatValidator
SignInManager<IdentityUser> signInManager, SignInManager<IdentityUser> signInManager,
IStringLocalizer<AbpIdentityServerResource> stringLocalizer, IStringLocalizer<AbpIdentityServerResource> stringLocalizer,
PhoneNumberTokenProvider<IdentityUser> phoneNumberTokenProvider, PhoneNumberTokenProvider<IdentityUser> phoneNumberTokenProvider,
IOptionsSnapshot<AbpWeChatValidatorOptions> options, IOptions<AbpWeChatOptions> options,
ILogger<WeChatTokenGrantValidator> logger) ILogger<WeChatTokenGrantValidator> logger)
{ {
Logger = logger; Logger = logger;
@ -77,7 +78,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChatValidator
return; return;
} }
var httpClient = HttpClientFactory.CreateClient(WeChatValidatorConsts.WeChatValidatorClientName); var httpClient = HttpClientFactory.CreateClient(WeChatValidatorConsts.WeChatValidatorClientName);
var httpRequest = new WeChatTokenRequest var httpRequest = new WeChatOpenIdRequest
{ {
Code = wechatCode, Code = wechatCode,
AppId = Options.AppId, AppId = Options.AppId,
@ -85,19 +86,19 @@ namespace LINGYUN.Abp.IdentityServer.WeChatValidator
BaseUrl = httpClient.BaseAddress.AbsoluteUri BaseUrl = httpClient.BaseAddress.AbsoluteUri
}; };
var wechatTokenResponse = await httpClient.RequestWeChatCodeTokenAsync(httpRequest); var wechatOpenIdResponse = await httpClient.RequestWeChatCodeTokenAsync(httpRequest);
if (wechatTokenResponse.IsError) if (wechatOpenIdResponse.IsError)
{ {
Logger.LogWarning("Authentication failed for token: {0}, reason: invalid token", wechatCode); Logger.LogWarning("Authentication failed for token: {0}, reason: invalid token", wechatCode);
Logger.LogWarning("WeChat auth failed, error: {0}", wechatTokenResponse.ErrorMessage); Logger.LogWarning("WeChat auth failed, error: {0}", wechatOpenIdResponse.ErrorMessage);
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant,
Localizer["InvalidGrant:WeChatTokenInvalid"]); Localizer["InvalidGrant:WeChatTokenInvalid"]);
return; return;
} }
var currentUser = await UserManager.FindByNameAsync(wechatTokenResponse.OpenId); var currentUser = await UserManager.FindByNameAsync(wechatOpenIdResponse.OpenId);
if(currentUser == null) if(currentUser == null)
{ {
Logger.LogWarning("Invalid grant type: wechat openid: {0} not register", wechatTokenResponse.OpenId); Logger.LogWarning("Invalid grant type: wechat openid: {0} not register", wechatOpenIdResponse.OpenId);
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant,
Localizer["InvalidGrant:WeChatNotRegister"]); Localizer["InvalidGrant:WeChatNotRegister"]);
return; return;
@ -109,9 +110,9 @@ namespace LINGYUN.Abp.IdentityServer.WeChatValidator
{ {
additionalClaims.Add(new Claim(AbpClaimTypes.TenantId, currentUser.TenantId?.ToString())); additionalClaims.Add(new Claim(AbpClaimTypes.TenantId, currentUser.TenantId?.ToString()));
} }
additionalClaims.Add(new Claim(WeChatValidatorConsts.ClaimTypes.OpenId, wechatTokenResponse.OpenId)); additionalClaims.Add(new Claim(WeChatValidatorConsts.ClaimTypes.OpenId, wechatOpenIdResponse.OpenId));
await EventService.RaiseAsync(new UserLoginSuccessEvent(currentUser.UserName, wechatTokenResponse.OpenId, null)); await EventService.RaiseAsync(new UserLoginSuccessEvent(currentUser.UserName, wechatOpenIdResponse.OpenId, null));
context.Result = new GrantValidationResult(sub, context.Result = new GrantValidationResult(sub,
WeChatValidatorConsts.AuthenticationMethods.BasedWeChatAuthentication, additionalClaims.ToArray()); WeChatValidatorConsts.AuthenticationMethods.BasedWeChatAuthentication, additionalClaims.ToArray());
} }

6
aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Net/Http/HttpClientTokenRequestExtensions.cs

@ -7,7 +7,7 @@ namespace System.Net.Http
{ {
public static class HttpClientTokenRequestExtensions public static class HttpClientTokenRequestExtensions
{ {
public static async Task<WeChatTokenResponse> RequestWeChatCodeTokenAsync(this HttpMessageInvoker client, WeChatTokenRequest request, CancellationToken cancellationToken = default) public static async Task<WeChatOpenIdResponse> RequestWeChatCodeTokenAsync(this HttpMessageInvoker client, WeChatOpenIdRequest request, CancellationToken cancellationToken = default)
{ {
var getResuestUrlBuiilder = new StringBuilder(); var getResuestUrlBuiilder = new StringBuilder();
getResuestUrlBuiilder.Append(request.BaseUrl); getResuestUrlBuiilder.Append(request.BaseUrl);
@ -24,9 +24,9 @@ namespace System.Net.Http
} }
catch (Exception ex) catch (Exception ex)
{ {
return ProtocolResponse.FromException<WeChatTokenResponse>(ex); return ProtocolResponse.FromException<WeChatOpenIdResponse>(ex);
} }
return await ProtocolResponse.FromHttpResponseAsync<WeChatTokenResponse>(httpResponse).ConfigureAwait(false); return await ProtocolResponse.FromHttpResponseAsync<WeChatOpenIdResponse>(httpResponse).ConfigureAwait(false);
} }
} }
} }

2
aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Net/Http/WeChatTokenRequest.cs → aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Net/Http/WeChatOpenIdRequest.cs

@ -1,6 +1,6 @@
namespace System.Net.Http namespace System.Net.Http
{ {
public class WeChatTokenRequest public class WeChatOpenIdRequest
{ {
public string BaseUrl { get; set; } public string BaseUrl { get; set; }
public string AppId { get; set; } public string AppId { get; set; }

2
aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Net/Http/WeChatTokenResponse.cs → aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Net/Http/WeChatOpenIdResponse.cs

@ -2,7 +2,7 @@
namespace System.Net.Http namespace System.Net.Http
{ {
public class WeChatTokenResponse : ProtocolResponse public class WeChatOpenIdResponse : ProtocolResponse
{ {
/// <summary> /// <summary>
/// 用户唯一标识 /// 用户唯一标识

3
aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN.Abp.Notifications.WeChat.csproj → aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN.Abp.Notifications.WeChat.WeApp.csproj

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
@ -6,6 +6,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\moudles\common\LINGYUN.Abp.WeChat.Authorization\LINGYUN.Abp.WeChat.Authorization.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.Notifications\LINGYUN.Abp.Notifications.csproj" /> <ProjectReference Include="..\LINGYUN.Abp.Notifications\LINGYUN.Abp.Notifications.csproj" />
</ItemGroup> </ItemGroup>

30
aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/AbpNotificationsWeChatWeAppModule.cs

@ -0,0 +1,30 @@
using LINGYUN.Abp.WeChat.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Polly;
using System;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Notifications.WeChat.WeApp
{
[DependsOn(
typeof(AbpWeChatAuthorizationModule),
typeof(AbpNotificationModule))]
public class AbpNotificationsWeChatWeAppModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<AbpWeChatWeAppNotificationOptions>(configuration.GetSection("Notifications:WeChat:WeApp"));
// TODO:是否有必要启用重试机制?
context.Services.AddHttpClient(WeChatWeAppNotificationSender.SendNotificationClientName)
.AddTransientHttpErrorPolicy(builder =>
builder.WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(Math.Pow(2, i))));
Configure<AbpNotificationOptions>(options =>
{
options.PublishProviders.Add<WeChatWeAppNotificationPublishProvider>();
});
}
}
}

18
aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/AbpWeChatWeAppNotificationOptions.cs

@ -0,0 +1,18 @@
namespace LINGYUN.Abp.Notifications.WeChat.WeApp
{
public class AbpWeChatWeAppNotificationOptions
{
/// <summary>
/// 默认小程序模板
/// </summary>
public string DefaultTemplateId { get; set; }
/// <summary>
/// 默认跳转小程序类型
/// </summary>
public string DefaultWeAppState { get; set; } = "developer";
/// <summary>
/// 默认小程序语言
/// </summary>
public string DefaultWeAppLanguage { get; set; } = "zh_CN";
}
}

9
aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/IWeChatWeAppNotificationSender.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.Notifications.WeChat.WeApp
{
public interface IWeChatWeAppNotificationSender
{
Task SendAsync(WeChatWeAppSendNotificationData notificationData);
}
}

76
aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppNotificationPublishProvider.cs

@ -0,0 +1,76 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Notifications.WeChat.WeApp
{
/// <summary>
/// 微信小程序消息推送提供者
/// </summary>
public class WeChatWeAppNotificationPublishProvider : NotificationPublishProvider
{
public override string Name => "WeChat.WeApp";
protected IWeChatWeAppNotificationSender NotificationSender { get; }
protected AbpWeChatWeAppNotificationOptions Options { get; }
public WeChatWeAppNotificationPublishProvider(
IServiceProvider serviceProvider,
IWeChatWeAppNotificationSender notificationSender,
IOptions<AbpWeChatWeAppNotificationOptions> options)
: base(serviceProvider)
{
Options = options.Value;
NotificationSender = notificationSender;
}
public override async Task PublishAsync(NotificationInfo notification, IEnumerable<UserIdentifier> identifiers)
{
// step1 默认微信openid绑定的就是username,
// 如果不是,需要自行处理openid获取逻辑
// step2 调用微信消息推送接口
foreach (var identifier in identifiers)
{
await SendWeChatTemplateMessagAsync(notification, identifier);
}
}
protected virtual async Task SendWeChatTemplateMessagAsync(NotificationInfo notification, UserIdentifier identifier)
{
var templateId = GetOrDefaultTemplateId(notification.Data);
Logger.LogDebug($"Get wechat weapp template id: {templateId}");
var redirect = GetOrDefault(notification.Data, "RedirectPage", "");
Logger.LogDebug($"Get wechat weapp redirect page: {redirect}");
var weAppState = GetOrDefault(notification.Data, "WeAppState", Options.DefaultWeAppState);
Logger.LogDebug($"Get wechat weapp state: {weAppState}");
var weAppLang = GetOrDefault(notification.Data, "WeAppLanguage", Options.DefaultWeAppLanguage);
Logger.LogDebug($"Get wechat weapp language: {weAppLang}");
var weChatWeAppNotificationData = new WeChatWeAppSendNotificationData(identifier.UserName,
templateId, redirect, weAppState, weAppLang);
Logger.LogDebug($"Sending wechat weapp notification: {notification.Name}");
// 发送小程序订阅消息
await NotificationSender.SendAsync(weChatWeAppNotificationData);
}
protected string GetOrDefaultTemplateId(NotificationData data)
{
return GetOrDefault(data, "TemplateId", Options.DefaultTemplateId);
}
protected string GetOrDefault(NotificationData data, string key, string defaultValue)
{
if (data.Properties.TryGetValue(key, out object value))
{
return value.ToString();
}
return defaultValue;
}
}
}

93
aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppNotificationSender.cs

@ -0,0 +1,93 @@
using LINGYUN.Abp.WeChat.Authorization;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
namespace LINGYUN.Abp.Notifications.WeChat.WeApp
{
public class WeChatWeAppNotificationSender : IWeChatWeAppNotificationSender, ITransientDependency
{
public const string SendNotificationClientName = "WeChatWeAppSendNotificationClient";
protected IHttpClientFactory HttpClientFactory { get; }
protected IJsonSerializer JsonSerializer { get; }
protected IWeChatTokenProvider WeChatTokenProvider { get; }
public WeChatWeAppNotificationSender(
IJsonSerializer jsonSerializer,
IHttpClientFactory httpClientFactory,
IWeChatTokenProvider weChatTokenProvider)
{
JsonSerializer = jsonSerializer;
HttpClientFactory = httpClientFactory;
WeChatTokenProvider = weChatTokenProvider;
}
public virtual async Task SendAsync(WeChatWeAppSendNotificationData notificationData)
{
var weChatToken = await WeChatTokenProvider.GetTokenAsync();
var requestParamters = new Dictionary<string, string>
{
{ "access_token", weChatToken.AccessToken }
};
var weChatSendNotificationUrl = "https://api.weixin.qq.com";
var weChatSendNotificationPath = "/cgi-bin/message/subscribe/send";
var requestUrl = BuildRequestUrl(weChatSendNotificationUrl, weChatSendNotificationPath, requestParamters);
var responseContent = await MakeRequestAndGetResultAsync(requestUrl, notificationData);
var weChatSenNotificationResponse = JsonSerializer.Deserialize<WeChatSendNotificationResponse>(responseContent);
weChatSenNotificationResponse.ThrowIfNotSuccess();
}
protected virtual async Task<string> MakeRequestAndGetResultAsync(string url, WeChatWeAppSendNotificationData notificationData)
{
var client = HttpClientFactory.CreateClient(SendNotificationClientName);
var requestContent = new StringContent(JsonSerializer.Serialize(notificationData));
var requestMessage = new HttpRequestMessage(HttpMethod.Post, url)
{
Content = requestContent
};
var response = await client.SendAsync(requestMessage);
if (!response.IsSuccessStatusCode)
{
throw new AbpException($"Baidu http request service returns error! HttpStatusCode: {response.StatusCode}, ReasonPhrase: {response.ReasonPhrase}");
}
var resultContent = await response.Content.ReadAsStringAsync();
return resultContent;
}
protected virtual string BuildRequestUrl(string uri, string path, IDictionary<string, string> paramters)
{
var requestUrlBuilder = new StringBuilder(128);
requestUrlBuilder.Append(uri);
requestUrlBuilder.Append(path).Append("?");
foreach (var paramter in paramters)
{
requestUrlBuilder.AppendFormat("{0}={1}", paramter.Key, paramter.Value);
requestUrlBuilder.Append("&");
}
requestUrlBuilder.Remove(requestUrlBuilder.Length - 1, 1);
return requestUrlBuilder.ToString();
}
}
public class WeChatSendNotificationResponse
{
[JsonProperty("errcode")]
public int ErrorCode { get; set; }
[JsonProperty("errmsg")]
public string ErrorMessage { get; set; }
public void ThrowIfNotSuccess()
{
if (ErrorCode != 0)
{
throw new AbpException($"Send wechat weapp notification error:{ErrorMessage}");
}
}
}
}

45
aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppSendNotificationData.cs

@ -0,0 +1,45 @@
#pragma warning disable IDE1006 // 禁止编译器提示
namespace LINGYUN.Abp.Notifications.WeChat.WeApp
{
public class WeChatWeAppSendNotificationData
{
/// <summary>
/// 接收者(用户)的 openid
/// </summary>
public string touser { get; set; }
/// <summary>
/// 所需下发的订阅模板id
/// </summary>
public string template_id { get; set; }
/// <summary>
/// 点击模板卡片后的跳转页面,仅限本小程序内的页面。
/// 支持带参数,(示例index?foo=bar)。
/// 该字段不填则模板无跳转
/// </summary>
public string page { get; set; }
/// <summary>
/// 跳转小程序类型:
/// developer为开发版;trial为体验版;formal为正式版;
/// 默认为正式版
/// </summary>
public string miniprogram_state { get; set; }
/// <summary>
/// 进入小程序查看”的语言类型,
/// 支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),
/// 默认为zh_CN
/// </summary>
public string lang { get; set; }
public WeChatWeAppSendNotificationData() { }
public WeChatWeAppSendNotificationData(string openId, string templateId, string redirectPage = "",
string state = "formal", string miniLang = "zh_CN")
{
touser = openId;
template_id = templateId;
page = redirectPage;
miniprogram_state = state;
lang = miniLang;
}
}
}
#pragma warning restore IDE1006

25
aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeChatNotificationPublishProvider.cs

@ -1,25 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Notifications.WeChat
{
public class WeChatNotificationPublishProvider : NotificationPublishProvider
{
public override string Name => "WeChat";
public WeChatNotificationPublishProvider(
IServiceProvider serviceProvider)
: base(serviceProvider)
{
}
public override async Task PublishAsync(NotificationInfo notification, IEnumerable<UserIdentifier> identifiers)
{
// step1 默认微信openid绑定的就是username,如果不是,那就根据userid去获取
// step2 调用微信消息推送接口
}
}
}

3
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDispatcher.cs

@ -3,6 +3,9 @@ using System.Threading.Tasks;
namespace LINGYUN.Abp.Notifications namespace LINGYUN.Abp.Notifications
{ {
/// <summary>
/// 通知发送者接口
/// </summary>
public interface INotificationDispatcher public interface INotificationDispatcher
{ {
/// <summary> /// <summary>

59
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSubscriptionManager.cs

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Notifications
{
/// <summary>
/// 通知订阅管理器
/// </summary>
public interface INotificationSubscriptionManager
{
/// <summary>
/// 是否已订阅
/// </summary>
/// <param name="tenantId">租户</param>
/// <param name="userId">用户标识</param>
/// <param name="notificationName">通知名称</param>
/// <returns></returns>
Task<bool> IsSubscribedAsync(Guid? tenantId, Guid userId, string notificationName);
/// <summary>
/// 订阅通知
/// </summary>
/// <param name="tenantId">租户</param>
/// <param name="identifier">用户标识</param>
/// <param name="notificationName">通知名称</param>
/// <returns></returns>
Task SubscribeAsync(Guid? tenantId, UserIdentifier identifier, string notificationName);
/// <summary>
/// 订阅通知
/// </summary>
/// <param name="tenantId">租户</param>
/// <param name="identifiers">用户标识列表</param>
/// <param name="notificationName">通知名称</param>
/// <returns></returns>
Task SubscribeAsync(Guid? tenantId, IEnumerable<UserIdentifier> identifiers, string notificationName);
/// <summary>
/// 取消订阅
/// </summary>
/// <param name="tenantId">租户</param>
/// <param name="identifier">用户标识</param>
/// <param name="notificationName">通知名称</param>
/// <returns></returns>
Task UnsubscribeAsync(Guid? tenantId, UserIdentifier identifier, string notificationName);
/// <summary>
/// 获取通知被订阅用户列表
/// </summary>
/// <param name="tenantId">租户</param>
/// <param name="notificationName">通知名称</param>
/// <returns></returns>
Task<List<NotificationSubscriptionInfo>> GetSubscriptionsAsync(Guid? tenantId, string notificationName);
/// <summary>
/// 获取用户订阅列表
/// </summary>
/// <param name="tenantId">租户</param>
/// <param name="userId">用户标识</param>
/// <returns></returns>
Task<List<NotificationSubscriptionInfo>> GetUserSubscriptionsAsync(Guid? tenantId, Guid userId);
}
}

24
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/DefaultNotificationDispatcher.cs

@ -30,7 +30,14 @@ namespace LINGYUN.Abp.Notifications.Internal
NotificationSeverity notificationSeverity = NotificationSeverity.Info) NotificationSeverity notificationSeverity = NotificationSeverity.Info)
{ {
// 获取自定义的通知 // 获取自定义的通知
var defineNotification = _notificationDefinitionManager.Get(notificationName); var defineNotification = _notificationDefinitionManager.GetOrNull(notificationName);
// 没有定义的通知,应该也要能发布、订阅,
// 比如订单之类的,是以订单编号为通知名称,这是动态的,没法自定义
if(defineNotification == null)
{
defineNotification = new NotificationDefinition(notificationName);
}
var notificationInfo = new NotificationInfo var notificationInfo = new NotificationInfo
{ {
@ -75,31 +82,38 @@ namespace LINGYUN.Abp.Notifications.Internal
protected async Task PublishFromProvidersAsync(IEnumerable<INotificationPublishProvider> providers, protected async Task PublishFromProvidersAsync(IEnumerable<INotificationPublishProvider> providers,
NotificationInfo notificationInfo) NotificationInfo notificationInfo)
{ {
Logger.LogDebug($"Persistent notification {notificationInfo.Name}");
// 持久化通知 // 持久化通知
await _notificationStore.InsertNotificationAsync(notificationInfo); await _notificationStore.InsertNotificationAsync(notificationInfo);
Logger.LogDebug($"Gets a list of user subscriptions {notificationInfo.Name}");
// 获取用户订阅列表 // 获取用户订阅列表
var userSubscriptions = await _notificationStore.GetSubscriptionsAsync(notificationInfo.TenantId, notificationInfo.Name); var userSubscriptions = await _notificationStore.GetSubscriptionsAsync(notificationInfo.TenantId, notificationInfo.Name);
Logger.LogDebug($"Persistent user notifications {notificationInfo.Name}");
// 持久化用户通知 // 持久化用户通知
var subscriptionUserIdentifiers = userSubscriptions.Select(us => new UserIdentifier(us.UserId, us.UserName)); var subscriptionUserIdentifiers = userSubscriptions.Select(us => new UserIdentifier(us.UserId, us.UserName));
await _notificationStore.InsertUserNotificationsAsync(notificationInfo, await _notificationStore.InsertUserNotificationsAsync(notificationInfo,
subscriptionUserIdentifiers.Select(u => u.UserId)); subscriptionUserIdentifiers.Select(u => u.UserId));
// 发通知 // 发通知
foreach (var provider in providers) foreach (var provider in providers)
{ {
try try
{ {
Logger.LogDebug($"Sending notification with provider {provider.Name}");
await provider.PublishAsync(notificationInfo, subscriptionUserIdentifiers); await provider.PublishAsync(notificationInfo, subscriptionUserIdentifiers);
Logger.LogDebug($"Send notification {notificationInfo.Name} with provider {provider.Name} was successful");
} }
catch(Exception ex) catch(Exception ex)
{ {
Logger.LogWarning("Send notification error with provider {0}", provider.Name); Logger.LogWarning($"Send notification error with provider {provider.Name}");
Logger.LogWarning("Error message:{0}", ex.Message); Logger.LogWarning($"Error message:{ex.Message}");
Logger.LogTrace(ex, "Send notification error with provider {0}", provider.Name); Logger.LogTrace(ex, $"Send notification error with provider { provider.Name}");
} }
} }
} }

55
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/NotificationSubscriptionManager.cs

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.Notifications.Internal
{
internal class NotificationSubscriptionManager : INotificationSubscriptionManager, ITransientDependency
{
private readonly INotificationStore _store;
public NotificationSubscriptionManager(
INotificationStore store)
{
_store = store;
}
public virtual async Task<List<NotificationSubscriptionInfo>> GetSubscriptionsAsync(Guid? tenantId, string notificationName)
{
return await _store.GetSubscriptionsAsync(tenantId, notificationName);
}
public virtual async Task<List<NotificationSubscriptionInfo>> GetUserSubscriptionsAsync(Guid? tenantId, Guid userId)
{
return await _store.GetUserSubscriptionsAsync(tenantId, userId);
}
public virtual async Task<bool> IsSubscribedAsync(Guid? tenantId, Guid userId, string notificationName)
{
return await _store.IsSubscribedAsync(tenantId, userId, notificationName);
}
public virtual async Task SubscribeAsync(Guid? tenantId, UserIdentifier identifier, string notificationName)
{
if (await IsSubscribedAsync(tenantId, identifier.UserId, notificationName))
{
return;
}
await _store.InsertUserSubscriptionAsync(tenantId, identifier, notificationName);
}
public virtual async Task SubscribeAsync(Guid? tenantId, IEnumerable<UserIdentifier> identifiers, string notificationName)
{
foreach(var identifier in identifiers)
{
await SubscribeAsync(tenantId, identifier, notificationName);
}
}
public virtual async Task UnsubscribeAsync(Guid? tenantId, UserIdentifier identifier, string notificationName)
{
await _store.DeleteUserSubscriptionAsync(tenantId, identifier.UserId, notificationName);
}
}
}

30
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs

@ -1,4 +1,7 @@
using System; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
@ -11,6 +14,31 @@ namespace LINGYUN.Abp.Notifications
protected IServiceProvider ServiceProvider { get; } protected IServiceProvider ServiceProvider { get; }
protected readonly object ServiceProviderLock = new object();
public ILoggerFactory LoggerFactory => LazyGetRequiredService(ref _loggerFactory);
private ILoggerFactory _loggerFactory;
protected ILogger Logger => _lazyLogger.Value;
private Lazy<ILogger> _lazyLogger => new Lazy<ILogger>(() => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance, true);
protected TService LazyGetRequiredService<TService>(ref TService reference)
{
if (reference == null)
{
lock (ServiceProviderLock)
{
if (reference == null)
{
reference = ServiceProvider.GetRequiredService<TService>();
}
}
}
return reference;
}
protected NotificationPublishProvider(IServiceProvider serviceProvider) protected NotificationPublishProvider(IServiceProvider serviceProvider)
{ {
ServiceProvider = serviceProvider; ServiceProvider = serviceProvider;

16
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Local/UserCreateSendWelcomeEventHandler.cs

@ -18,24 +18,26 @@ namespace LINGYUN.Abp.MessageService.EventBus
{ {
private readonly ISettingProvider _settingProvider; private readonly ISettingProvider _settingProvider;
private readonly IStringLocalizer _stringLocalizer; private readonly IStringLocalizer _stringLocalizer;
private readonly INotificationStore _notificationStore;
private readonly INotificationDispatcher _notificationDispatcher; private readonly INotificationDispatcher _notificationDispatcher;
private readonly INotificationSubscriptionManager _notificationSubscriptionManager;
// 需要模拟用户令牌 // 需要模拟用户令牌
// 是否有必要 // 是否有必要
// private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor; // private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor;
public UserCreateSendWelcomeEventHandler( public UserCreateSendWelcomeEventHandler(
ISettingProvider settingProvider, ISettingProvider settingProvider,
INotificationStore notificationStore,
INotificationDispatcher notificationDispatcher, INotificationDispatcher notificationDispatcher,
IStringLocalizer<MessageServiceResource> stringLocalizer IStringLocalizer<MessageServiceResource> stringLocalizer,
INotificationSubscriptionManager notificationSubscriptionManager
//ICurrentPrincipalAccessor currentPrincipalAccessor //ICurrentPrincipalAccessor currentPrincipalAccessor
) )
{ {
_settingProvider = settingProvider; _settingProvider = settingProvider;
_stringLocalizer = stringLocalizer; _stringLocalizer = stringLocalizer;
_notificationStore = notificationStore;
_notificationDispatcher = notificationDispatcher; _notificationDispatcher = notificationDispatcher;
_notificationSubscriptionManager = notificationSubscriptionManager;
//_currentPrincipalAccessor = currentPrincipalAccessor; //_currentPrincipalAccessor = currentPrincipalAccessor;
} }
@ -53,9 +55,13 @@ namespace LINGYUN.Abp.MessageService.EventBus
{ {
var userIdentifer = new UserIdentifier(eventData.Entity.Id, eventData.Entity.UserName); var userIdentifer = new UserIdentifier(eventData.Entity.Id, eventData.Entity.UserName);
// 订阅用户欢迎消息 // 订阅用户欢迎消息
await _notificationStore.InsertUserSubscriptionAsync(eventData.Entity.TenantId, await _notificationSubscriptionManager.SubscribeAsync(eventData.Entity.TenantId,
userIdentifer, UserNotificationNames.WelcomeToApplication); userIdentifer, UserNotificationNames.WelcomeToApplication);
// Store未检查已订阅
//await _notificationStore.InsertUserSubscriptionAsync(eventData.Entity.TenantId,
// userIdentifer, UserNotificationNames.WelcomeToApplication);
var userWelcomeNotifictionData = new NotificationData(); var userWelcomeNotifictionData = new NotificationData();
// 换成用户名称,而不是用户名 // 换成用户名称,而不是用户名

14
aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN.Abp.WeChat.Authorization.csproj

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="3.1.2" />
<PackageReference Include="Volo.Abp.Caching" Version="2.9.0" />
<PackageReference Include="Volo.Abp.Json" Version="2.9.0" />
</ItemGroup>
</Project>

25
aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/AbpWeChatAuthorizationModule.cs

@ -0,0 +1,25 @@
using Microsoft.Extensions.DependencyInjection;
using Polly;
using System;
using Volo.Abp.Caching;
using Volo.Abp.Json;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.WeChat.Authorization
{
[DependsOn(typeof(AbpJsonModule), typeof(AbpCachingModule))]
public class AbpWeChatAuthorizationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<AbpWeChatOptions>(configuration.GetSection("WeChat:Auth"));
context.Services.AddHttpClient("WeChatTokenProviderClient", options =>
{
options.BaseAddress = new Uri("https://api.weixin.qq.com/cgi-bin/token");
}).AddTransientHttpErrorPolicy(builder =>
builder.WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(Math.Pow(2, i))));
}
}
}

4
aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/AbpWeChatValidatorOptions.cs → aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/AbpWeChatOptions.cs

@ -1,6 +1,6 @@
namespace LINGYUN.Abp.IdentityServer namespace LINGYUN.Abp.WeChat.Authorization
{ {
public class AbpWeChatValidatorOptions public class AbpWeChatOptions
{ {
public string AppId { get; set; } public string AppId { get; set; }
public string AppSecret { get; set; } public string AppSecret { get; set; }

9
aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/IWeChatTokenProvider.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.WeChat.Authorization
{
public interface IWeChatTokenProvider
{
Task<WeChatToken> GetTokenAsync();
}
}

26
aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatToken.cs

@ -0,0 +1,26 @@
namespace LINGYUN.Abp.WeChat.Authorization
{
/// <summary>
/// 微信令牌
/// </summary>
public class WeChatToken
{
/// <summary>
/// 访问令牌
/// </summary>
public string AccessToken { get; set; }
/// <summary>
/// 过期时间,单位(s)
/// </summary>
public int ExpiresIn { get; set; }
public WeChatToken()
{
}
public WeChatToken(string token, int expiresIn)
{
AccessToken = token;
ExpiresIn = expiresIn;
}
}
}

24
aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatTokenCacheItem.cs

@ -0,0 +1,24 @@
namespace LINGYUN.Abp.WeChat.Authorization
{
public class WeChatTokenCacheItem
{
public string AppId { get; set; }
public WeChatToken WeChatToken { get; set; }
public WeChatTokenCacheItem()
{
}
public WeChatTokenCacheItem(string appId, WeChatToken weChatToken)
{
AppId = appId;
WeChatToken = weChatToken;
}
public static string CalculateCacheKey(string provider, string appId)
{
return "p:" + provider + ",o:" + appId;
}
}
}

88
aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatTokenProvider.cs

@ -0,0 +1,88 @@
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
namespace LINGYUN.Abp.WeChat.Authorization
{
public class WeChatTokenProvider : IWeChatTokenProvider, ISingletonDependency
{
public ILogger<WeChatTokenProvider> Logger { get; set; }
protected IHttpClientFactory HttpClientFactory { get; }
protected IJsonSerializer JsonSerializer { get; }
protected IDistributedCache<WeChatTokenCacheItem> Cache { get; }
protected AbpWeChatOptions Options { get; }
public WeChatTokenProvider(
IJsonSerializer jsonSerializer,
IHttpClientFactory httpClientFactory,
IOptions<AbpWeChatOptions> options,
IDistributedCache<WeChatTokenCacheItem> cache)
{
JsonSerializer = jsonSerializer;
HttpClientFactory = httpClientFactory;
Cache = cache;
Options = options.Value;
Logger = NullLogger<WeChatTokenProvider>.Instance;
}
public virtual async Task<WeChatToken> GetTokenAsync()
{
return (await GetCacheItemAsync("WeChatToken", Options.AppId)).WeChatToken;
}
protected virtual async Task<WeChatTokenCacheItem> GetCacheItemAsync(string provider, string appId)
{
var cacheKey = WeChatTokenCacheItem.CalculateCacheKey(provider, appId);
Logger.LogDebug($"WeChatTokenProvider.GetCacheItemAsync: {cacheKey}");
var cacheItem = await Cache.GetAsync(cacheKey);
if (cacheItem != null)
{
Logger.LogDebug($"Found in the cache: {cacheKey}");
return cacheItem;
}
Logger.LogDebug($"Not found in the cache, getting from the httpClient: {cacheKey}");
var client = HttpClientFactory.CreateClient("WeChatTokenProviderClient");
var request = new WeChatTokenRequest
{
BaseUrl = client.BaseAddress.AbsoluteUri,
AppSecret = Options.AppSecret,
AppId = Options.AppId,
GrantType = "client_credential"
};
var response = await client.RequestWeChatCodeTokenAsync(request);
var responseContent = await response.Content.ReadAsStringAsync();
var weChatTokenResponse = JsonSerializer.Deserialize<WeChatTokenResponse>(responseContent);
var weChatToken = weChatTokenResponse.ToWeChatToken();
cacheItem = new WeChatTokenCacheItem(appId, weChatToken);
Logger.LogDebug($"Setting the cache item: {cacheKey}");
var cacheOptions = new DistributedCacheEntryOptions
{
// 设置绝对过期时间为Token有效期剩余的二分钟
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(weChatToken.ExpiresIn - 120)
};
await Cache.SetAsync(cacheKey, cacheItem, cacheOptions);
Logger.LogDebug($"Finished setting the cache item: {cacheKey}");
return cacheItem;
}
}
}

10
aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatTokenRequest.cs

@ -0,0 +1,10 @@
namespace LINGYUN.Abp.WeChat.Authorization
{
public class WeChatTokenRequest
{
public string BaseUrl { get; set; }
public string GrantType { get; set; }
public string AppId { get; set; }
public string AppSecret { get; set; }
}
}

41
aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatTokenResponse.cs

@ -0,0 +1,41 @@
using Newtonsoft.Json;
using Volo.Abp;
namespace LINGYUN.Abp.WeChat.Authorization
{
/// <summary>
/// 微信访问令牌返回对象
/// </summary>
public class WeChatTokenResponse
{
/// <summary>
/// 错误码
/// </summary>
[JsonProperty("errcode")]
public int ErrorCode { get; set; }
/// <summary>
/// 错误消息
/// </summary>
[JsonProperty("errmsg")]
public string ErrorMessage { get; set; }
/// <summary>
/// 访问令牌
/// </summary>
[JsonProperty("access_token")]
public string AccessToken { get; set; }
/// <summary>
/// 过期时间,单位(s)
/// </summary>
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }
public WeChatToken ToWeChatToken()
{
if(ErrorCode != 0)
{
throw new AbpException(ErrorMessage);
}
return new WeChatToken(AccessToken, ExpiresIn);
}
}
}

26
aspnet-core/moudles/common/LINGYUN.Abp.WeChat.Authorization/System/Net/Http/HttpClientWeChatTokenRequestExtensions.cs

@ -0,0 +1,26 @@
using LINGYUN.Abp.WeChat.Authorization;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Http
{
public static class HttpClientWeChatTokenRequestExtensions
{
public static async Task<HttpResponseMessage> RequestWeChatCodeTokenAsync(this HttpMessageInvoker client, WeChatTokenRequest request, CancellationToken cancellationToken = default)
{
var getResuestUrlBuilder = new StringBuilder();
getResuestUrlBuilder.Append(request.BaseUrl);
getResuestUrlBuilder.Append("?grant_type=client_credential");
getResuestUrlBuilder.AppendFormat("&appid={0}", request.AppId);
getResuestUrlBuilder.AppendFormat("&secret={0}", request.AppSecret);
var getRequest = new HttpRequestMessage(HttpMethod.Get, getResuestUrlBuilder.ToString());
HttpResponseMessage httpResponse;
httpResponse = await client.SendAsync(getRequest, cancellationToken).ConfigureAwait(false);
return httpResponse;
}
}
}

5
aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Controllers/NotificationController.cs

@ -1,6 +1,7 @@
using LINGYUN.Abp.Notifications; using LINGYUN.Abp.Notifications;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc;
@ -26,6 +27,8 @@ namespace LINGYUN.Abp.MessageService.Controllers
notificationData.Properties["datetime"] = Clock.Now; notificationData.Properties["datetime"] = Clock.Now;
notificationData.Properties["severity"] = notification.Severity; notificationData.Properties["severity"] = notification.Severity;
notificationData.Properties.AddIfNotContains(notification.Data);
await _notificationDispatcher.DispatchAsync("TestApplicationNotofication", notificationData, await _notificationDispatcher.DispatchAsync("TestApplicationNotofication", notificationData,
notificationSeverity: notification.Severity); notificationSeverity: notification.Severity);
@ -38,7 +41,9 @@ namespace LINGYUN.Abp.MessageService.Controllers
public Guid UserId { get; set; } public Guid UserId { get; set; }
public string Title { get; set; } public string Title { get; set; }
public string Message { get; set; } public string Message { get; set; }
public Dictionary<string, object> Data { get; set; } = new Dictionary<string, object>();
public NotificationSeverity Severity { get; set; } = NotificationSeverity.Success; public NotificationSeverity Severity { get; set; } = NotificationSeverity.Success;
} }
public class TestApplicationNotificationData : NotificationData public class TestApplicationNotificationData : NotificationData

1
aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj

@ -35,6 +35,7 @@
<ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.EventBus.CAP\LINGYUN.Abp.EventBus.CAP.csproj" /> <ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.EventBus.CAP\LINGYUN.Abp.EventBus.CAP.csproj" />
<ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.IM.SignalR\LINGYUN.Abp.IM.SignalR.csproj" /> <ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.IM.SignalR\LINGYUN.Abp.IM.SignalR.csproj" />
<ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.Notifications.SignalR\LINGYUN.Abp.Notifications.SignalR.csproj" /> <ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.Notifications.SignalR\LINGYUN.Abp.Notifications.SignalR.csproj" />
<ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.Notifications.WeChat\LINGYUN.Abp.Notifications.WeChat.WeApp.csproj" />
<ProjectReference Include="..\..\..\modules\message\LINGYUN.Abp.MessageService.EntityFrameworkCore\LINGYUN.Abp.MessageService.EntityFrameworkCore.csproj" /> <ProjectReference Include="..\..\..\modules\message\LINGYUN.Abp.MessageService.EntityFrameworkCore\LINGYUN.Abp.MessageService.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\..\modules\message\LINGYUN.Abp.MessageService.HttpApi\LINGYUN.Abp.MessageService.HttpApi.csproj" /> <ProjectReference Include="..\..\..\modules\message\LINGYUN.Abp.MessageService.HttpApi\LINGYUN.Abp.MessageService.HttpApi.csproj" />
</ItemGroup> </ItemGroup>

2
aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs

@ -5,6 +5,7 @@ using LINGYUN.Abp.IM.SignalR;
using LINGYUN.Abp.MessageService.EntityFrameworkCore; using LINGYUN.Abp.MessageService.EntityFrameworkCore;
using LINGYUN.Abp.MessageService.MultiTenancy; using LINGYUN.Abp.MessageService.MultiTenancy;
using LINGYUN.Abp.Notifications.SignalR; using LINGYUN.Abp.Notifications.SignalR;
using LINGYUN.Abp.Notifications.WeChat.WeApp;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@ -40,6 +41,7 @@ namespace LINGYUN.Abp.MessageService
typeof(AbpAspNetCoreAuthenticationJwtBearerModule), typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
typeof(AbpIMSignalRModule), typeof(AbpIMSignalRModule),
typeof(AbpNotificationsSignalRModule), typeof(AbpNotificationsSignalRModule),
typeof(AbpNotificationsWeChatWeAppModule),
typeof(AbpCAPEventBusModule), typeof(AbpCAPEventBusModule),
typeof(AbpAutofacModule) typeof(AbpAutofacModule)
)] )]

Loading…
Cancel
Save