Browse Source

Merge pull request #170 from colinin/4.0

fix some bugs
pull/177/head
cKey 5 years ago
committed by GitHub
parent
commit
ac4f763357
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs
  2. 10
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/MiniProgram/WeChatMiniProgramGrantValidator.cs
  3. 11
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/Official/WeChatOfficialGrantValidator.cs
  4. 14
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/Official/WeChatOfficialSignatureMiddleware.cs
  5. 19
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/Microsoft/AspNetCore/Authentication/WeChat/Official/WeChatOfficialOAuthHandler.cs
  6. 10
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/AbpWeChatMiniProgramModule.cs
  7. 46
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/AbpWeChatMiniProgramOptionsFactory.cs
  8. 34
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/AbpWeChatMiniProgramOptionsManager.cs
  9. 10
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Messages/SubscribeMessager.cs
  10. 3
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.MiniProgram/README.md
  11. 10
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialModule.cs
  12. 48
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialOptionsFactory.cs
  13. 35
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialOptionsManager.cs
  14. 3
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Official/README.md
  15. 11
      aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs
  16. 525
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EventBus/Handlers/TenantSynchronizer.cs

10
aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs

@ -30,7 +30,7 @@ namespace LINGYUN.Abp.Account
protected IIdentityUserRepository UserRepository { get; } protected IIdentityUserRepository UserRepository { get; }
protected IUserSecurityCodeSender SecurityCodeSender { get; } protected IUserSecurityCodeSender SecurityCodeSender { get; }
protected IWeChatOpenIdFinder WeChatOpenIdFinder { get; } protected IWeChatOpenIdFinder WeChatOpenIdFinder { get; }
protected AbpWeChatMiniProgramOptions MiniProgramOptions { get; } protected AbpWeChatMiniProgramOptionsFactory MiniProgramOptionsFactory { get; }
protected IDistributedCache<SmsSecurityTokenCacheItem> SecurityTokenCache { get; } protected IDistributedCache<SmsSecurityTokenCacheItem> SecurityTokenCache { get; }
@ -42,7 +42,7 @@ namespace LINGYUN.Abp.Account
IIdentityUserRepository userRepository, IIdentityUserRepository userRepository,
IUserSecurityCodeSender securityCodeSender, IUserSecurityCodeSender securityCodeSender,
IDistributedCache<SmsSecurityTokenCacheItem> securityTokenCache, IDistributedCache<SmsSecurityTokenCacheItem> securityTokenCache,
IOptions<AbpWeChatMiniProgramOptions> miniProgramOptions) AbpWeChatMiniProgramOptionsFactory miniProgramOptionsFactory)
{ {
TotpService = totpService; TotpService = totpService;
UserStore = userStore; UserStore = userStore;
@ -51,7 +51,7 @@ namespace LINGYUN.Abp.Account
WeChatOpenIdFinder = weChatOpenIdFinder; WeChatOpenIdFinder = weChatOpenIdFinder;
SecurityCodeSender = securityCodeSender; SecurityCodeSender = securityCodeSender;
SecurityTokenCache = securityTokenCache; SecurityTokenCache = securityTokenCache;
MiniProgramOptions = miniProgramOptions.Value; MiniProgramOptionsFactory = miniProgramOptionsFactory;
LocalizationResource = typeof(AccountResource); LocalizationResource = typeof(AccountResource);
} }
@ -61,7 +61,9 @@ namespace LINGYUN.Abp.Account
ThowIfInvalidEmailAddress(input.EmailAddress); ThowIfInvalidEmailAddress(input.EmailAddress);
await CheckSelfRegistrationAsync(); await CheckSelfRegistrationAsync();
var wehchatOpenId = await WeChatOpenIdFinder.FindAsync(input.Code, MiniProgramOptions.AppId, MiniProgramOptions.AppSecret); var options = await MiniProgramOptionsFactory.CreateAsync();
var wehchatOpenId = await WeChatOpenIdFinder.FindAsync(input.Code, options.AppId, options.AppSecret);
var user = await UserManager.FindByLoginAsync(AbpWeChatMiniProgramConsts.ProviderKey, wehchatOpenId.OpenId); var user = await UserManager.FindByLoginAsync(AbpWeChatMiniProgramConsts.ProviderKey, wehchatOpenId.OpenId);
if (user != null) if (user != null)

10
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/MiniProgram/WeChatMiniProgramGrantValidator.cs

@ -22,7 +22,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChat.MiniProgram
public override string AuthenticationMethod => AbpWeChatMiniProgramConsts.AuthenticationMethod; public override string AuthenticationMethod => AbpWeChatMiniProgramConsts.AuthenticationMethod;
protected AbpWeChatMiniProgramOptions Options { get; } protected AbpWeChatMiniProgramOptionsFactory MiniProgramOptionsFactory { get; }
public WeChatMiniProgramGrantValidator( public WeChatMiniProgramGrantValidator(
IEventService eventService, IEventService eventService,
@ -31,15 +31,17 @@ namespace LINGYUN.Abp.IdentityServer.WeChat.MiniProgram
IIdentityUserRepository userRepository, IIdentityUserRepository userRepository,
IStringLocalizer<Volo.Abp.Identity.Localization.IdentityResource> identityLocalizer, IStringLocalizer<Volo.Abp.Identity.Localization.IdentityResource> identityLocalizer,
IStringLocalizer<AbpIdentityServerResource> identityServerLocalizer, IStringLocalizer<AbpIdentityServerResource> identityServerLocalizer,
IOptions<AbpWeChatMiniProgramOptions> options) AbpWeChatMiniProgramOptionsFactory miniProgramOptionsFactory)
: base(eventService, weChatOpenIdFinder, userManager, userRepository, identityLocalizer, identityServerLocalizer) : base(eventService, weChatOpenIdFinder, userManager, userRepository, identityLocalizer, identityServerLocalizer)
{ {
Options = options.Value; MiniProgramOptionsFactory = miniProgramOptionsFactory;
} }
protected override async Task<WeChatOpenId> FindOpenIdAsync(string code) protected override async Task<WeChatOpenId> FindOpenIdAsync(string code)
{ {
return await WeChatOpenIdFinder.FindAsync(code, Options.AppId, Options.AppSecret); var options = await MiniProgramOptionsFactory.CreateAsync();
return await WeChatOpenIdFinder.FindAsync(code, options.AppId, options.AppSecret);
} }
} }
} }

11
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/Official/WeChatOfficialGrantValidator.cs

@ -3,7 +3,6 @@ using LINGYUN.Abp.WeChat.Official;
using LINGYUN.Abp.WeChat.OpenId; using LINGYUN.Abp.WeChat.OpenId;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Identity; using Volo.Abp.Identity;
using Volo.Abp.IdentityServer.Localization; using Volo.Abp.IdentityServer.Localization;
@ -22,7 +21,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChat.Official
public override string AuthenticationMethod => AbpWeChatOfficialConsts.AuthenticationMethod; public override string AuthenticationMethod => AbpWeChatOfficialConsts.AuthenticationMethod;
protected AbpWeChatOfficialOptions Options { get; } protected AbpWeChatOfficialOptionsFactory WeChatOfficialOptionsFactory { get; }
public WeChatOfficialGrantValidator( public WeChatOfficialGrantValidator(
IEventService eventService, IEventService eventService,
@ -31,15 +30,17 @@ namespace LINGYUN.Abp.IdentityServer.WeChat.Official
IIdentityUserRepository userRepository, IIdentityUserRepository userRepository,
IStringLocalizer<Volo.Abp.Identity.Localization.IdentityResource> identityLocalizer, IStringLocalizer<Volo.Abp.Identity.Localization.IdentityResource> identityLocalizer,
IStringLocalizer<AbpIdentityServerResource> identityServerLocalizer, IStringLocalizer<AbpIdentityServerResource> identityServerLocalizer,
IOptions<AbpWeChatOfficialOptions> options) AbpWeChatOfficialOptionsFactory weChatOfficialOptionsFactory)
: base(eventService, weChatOpenIdFinder, userManager, userRepository, identityLocalizer, identityServerLocalizer) : base(eventService, weChatOpenIdFinder, userManager, userRepository, identityLocalizer, identityServerLocalizer)
{ {
Options = options.Value; WeChatOfficialOptionsFactory = weChatOfficialOptionsFactory;
} }
protected override async Task<WeChatOpenId> FindOpenIdAsync(string code) protected override async Task<WeChatOpenId> FindOpenIdAsync(string code)
{ {
return await WeChatOpenIdFinder.FindAsync(code, Options.AppId, Options.AppSecret); var options = await WeChatOfficialOptionsFactory.CreateAsync();
return await WeChatOpenIdFinder.FindAsync(code, options.AppId, options.AppSecret);
} }
} }
} }

14
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/Official/WeChatOfficialSignatureMiddleware.cs

@ -1,6 +1,5 @@
using LINGYUN.Abp.WeChat.Official; using LINGYUN.Abp.WeChat.Official;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using System; using System;
using System.Collections; using System.Collections;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -11,26 +10,29 @@ namespace LINGYUN.Abp.IdentityServer.WeChat.Official
{ {
public class WeChatOfficialSignatureMiddleware : IMiddleware, ITransientDependency public class WeChatOfficialSignatureMiddleware : IMiddleware, ITransientDependency
{ {
protected AbpWeChatOfficialOptions Options { get; } protected AbpWeChatOfficialOptionsFactory WeChatOfficialOptionsFactory { get; }
public WeChatOfficialSignatureMiddleware(IOptions<AbpWeChatOfficialOptions> options) public WeChatOfficialSignatureMiddleware(
AbpWeChatOfficialOptionsFactory weChatOfficialOptionsFactory)
{ {
Options = options.Value; WeChatOfficialOptionsFactory = weChatOfficialOptionsFactory;
} }
public async Task InvokeAsync(HttpContext context, RequestDelegate next) public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{ {
if (context.Request.Path.HasValue) if (context.Request.Path.HasValue)
{ {
var options = await WeChatOfficialOptionsFactory.CreateAsync();
var requestPath = context.Request.Path.Value; var requestPath = context.Request.Path.Value;
// 访问地址是否与定义的地址匹配 // 访问地址是否与定义的地址匹配
if (requestPath.Equals(Options.Url)) if (requestPath.Equals(options.Url))
{ {
var timestamp = context.Request.Query["timestamp"]; var timestamp = context.Request.Query["timestamp"];
var nonce = context.Request.Query["nonce"]; var nonce = context.Request.Query["nonce"];
var signature = context.Request.Query["signature"]; var signature = context.Request.Query["signature"];
var echostr = context.Request.Query["echostr"]; var echostr = context.Request.Query["echostr"];
// 验证消息合法性 // 验证消息合法性
var check = CheckWeChatSignature(Options.Token, timestamp, nonce, signature); var check = CheckWeChatSignature(options.Token, timestamp, nonce, signature);
if (check) if (check)
{ {
// 验证通过需要把微信服务器传递的字符原封不动传回 // 验证通过需要把微信服务器传递的字符原封不动传回

19
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/Microsoft/AspNetCore/Authentication/WeChat/Official/WeChatOfficialOAuthHandler.cs

@ -26,26 +26,29 @@ namespace Microsoft.AspNetCore.Authentication.WeChat.Official
public class WeChatOfficialOAuthHandler : OAuthHandler<WeChatOfficialOAuthOptions> public class WeChatOfficialOAuthHandler : OAuthHandler<WeChatOfficialOAuthOptions>
{ {
protected IDistributedCache<WeChatOfficialStateCacheItem> Cache { get; } protected IDistributedCache<WeChatOfficialStateCacheItem> Cache { get; }
protected AbpWeChatOfficialOptions WeChatOfficialOptions { get; } protected AbpWeChatOfficialOptionsFactory WeChatOfficialOptionsFactory { get; }
public WeChatOfficialOAuthHandler( public WeChatOfficialOAuthHandler(
IDistributedCache<WeChatOfficialStateCacheItem> cache, IDistributedCache<WeChatOfficialStateCacheItem> cache,
IOptionsMonitor<WeChatOfficialOAuthOptions> options, IOptionsMonitor<WeChatOfficialOAuthOptions> options,
IOptions<AbpWeChatOfficialOptions> weChatOfficialOptions, AbpWeChatOfficialOptionsFactory weChatOfficialOptionsFactory,
ILoggerFactory logger, ILoggerFactory logger,
UrlEncoder encoder, UrlEncoder encoder,
ISystemClock clock) ISystemClock clock)
: base(options, logger, encoder, clock) : base(options, logger, encoder, clock)
{ {
Cache = cache; Cache = cache;
WeChatOfficialOptions = weChatOfficialOptions.Value; WeChatOfficialOptionsFactory = weChatOfficialOptionsFactory;
} }
protected override Task InitializeHandlerAsync() protected override async Task InitializeHandlerAsync()
{ {
var weChatOfficialOptions = await WeChatOfficialOptionsFactory.CreateAsync();
// 用配置项重写 // 用配置项重写
Options.ClientId = WeChatOfficialOptions.AppId; Options.ClientId = weChatOfficialOptions.AppId;
Options.ClientSecret = WeChatOfficialOptions.AppSecret; Options.ClientSecret = weChatOfficialOptions.AppSecret;
return base.InitializeHandlerAsync();
await base.InitializeHandlerAsync();
} }
protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens) protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)

10
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/AbpWeChatMiniProgramModule.cs

@ -1,7 +1,5 @@
using LINGYUN.Abp.WeChat.Localization; using LINGYUN.Abp.WeChat.Localization;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using System; using System;
using Volo.Abp.Localization; using Volo.Abp.Localization;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
@ -34,13 +32,7 @@ namespace LINGYUN.Abp.WeChat.MiniProgram
options.BaseAddress = new Uri("https://api.weixin.qq.com"); options.BaseAddress = new Uri("https://api.weixin.qq.com");
}); });
AddAbpWeChatMiniProgramOptionsFactory(context.Services); context.Services.AddAbpDynamicOptions<AbpWeChatMiniProgramOptions, AbpWeChatMiniProgramOptionsManager>();
}
private static void AddAbpWeChatMiniProgramOptionsFactory(IServiceCollection services)
{
services.Replace(ServiceDescriptor.Transient<IOptionsFactory<AbpWeChatMiniProgramOptions>, AbpWeChatMiniProgramOptionsFactory>());
services.Replace(ServiceDescriptor.Scoped<IOptions<AbpWeChatMiniProgramOptions>, OptionsManager<AbpWeChatMiniProgramOptions>>());
} }
} }
} }

46
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/AbpWeChatMiniProgramOptionsFactory.cs

@ -1,50 +1,24 @@
using LINGYUN.Abp.WeChat.MiniProgram.Settings; using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Options; using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
using Volo.Abp.Threading;
namespace LINGYUN.Abp.WeChat.MiniProgram namespace LINGYUN.Abp.WeChat.MiniProgram
{ {
public class AbpWeChatMiniProgramOptionsFactory : AbpOptionsFactory<AbpWeChatMiniProgramOptions> public class AbpWeChatMiniProgramOptionsFactory : ITransientDependency
{ {
protected ISettingProvider SettingProvider { get; } protected IOptions<AbpWeChatMiniProgramOptions> Options { get; }
public AbpWeChatMiniProgramOptionsFactory(
ISettingProvider settingProvider,
IEnumerable<IConfigureOptions<AbpWeChatMiniProgramOptions>> setups,
IEnumerable<IPostConfigureOptions<AbpWeChatMiniProgramOptions>> postConfigures)
: base(setups, postConfigures)
{
SettingProvider = settingProvider;
}
public override AbpWeChatMiniProgramOptions Create(string name)
{
var options = base.Create(name);
OverrideOptions(options); public AbpWeChatMiniProgramOptionsFactory(
IOptions<AbpWeChatMiniProgramOptions> options)
return options;
}
protected virtual void OverrideOptions(AbpWeChatMiniProgramOptions options)
{ {
AsyncHelper.RunSync(() => OverrideOptionsAsync(options)); Options = options;
} }
protected virtual async Task OverrideOptionsAsync(AbpWeChatMiniProgramOptions options) public virtual async Task<AbpWeChatMiniProgramOptions> CreateAsync()
{ {
var appId = await SettingProvider.GetOrNullAsync(WeChatMiniProgramSettingNames.AppId); await Options.SetAsync();
var appSecret = await SettingProvider.GetOrNullAsync(WeChatMiniProgramSettingNames.AppSecret);
var token = await SettingProvider.GetOrNullAsync(WeChatMiniProgramSettingNames.Token);
var aesKey = await SettingProvider.GetOrNullAsync(WeChatMiniProgramSettingNames.EncodingAESKey);
options.AppId = appId ?? options.AppId; return Options.Value;
options.AppSecret = appSecret ?? options.AppSecret;
options.Token = token ?? options.Token;
options.EncodingAESKey = aesKey ?? options.EncodingAESKey;
} }
} }
} }

34
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/AbpWeChatMiniProgramOptionsManager.cs

@ -0,0 +1,34 @@
using LINGYUN.Abp.WeChat.MiniProgram.Settings;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using Volo.Abp.Options;
using Volo.Abp.Settings;
namespace LINGYUN.Abp.WeChat.MiniProgram
{
public class AbpWeChatMiniProgramOptionsManager : AbpDynamicOptionsManager<AbpWeChatMiniProgramOptions>
{
protected ISettingProvider SettingProvider { get; }
public AbpWeChatMiniProgramOptionsManager(
ISettingProvider settingProvider,
IOptionsFactory<AbpWeChatMiniProgramOptions> factory)
: base(factory)
{
SettingProvider = settingProvider;
}
protected override async Task OverrideOptionsAsync(string name, AbpWeChatMiniProgramOptions options)
{
var appId = await SettingProvider.GetOrNullAsync(WeChatMiniProgramSettingNames.AppId);
var appSecret = await SettingProvider.GetOrNullAsync(WeChatMiniProgramSettingNames.AppSecret);
var token = await SettingProvider.GetOrNullAsync(WeChatMiniProgramSettingNames.Token);
var aesKey = await SettingProvider.GetOrNullAsync(WeChatMiniProgramSettingNames.EncodingAESKey);
options.AppId = appId ?? options.AppId;
options.AppSecret = appSecret ?? options.AppSecret;
options.Token = token ?? options.Token;
options.EncodingAESKey = aesKey ?? options.EncodingAESKey;
}
}
}

10
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Messages/SubscribeMessager.cs

@ -20,7 +20,7 @@ namespace LINGYUN.Abp.WeChat.MiniProgram.Messages
public ILogger<SubscribeMessager> Logger { get; set; } public ILogger<SubscribeMessager> Logger { get; set; }
protected IHttpClientFactory HttpClientFactory { get; } protected IHttpClientFactory HttpClientFactory { get; }
protected IJsonSerializer JsonSerializer { get; } protected IJsonSerializer JsonSerializer { get; }
protected AbpWeChatMiniProgramOptions MiniProgramOptions { get; } protected AbpWeChatMiniProgramOptionsFactory MiniProgramOptionsFactory { get; }
protected IWeChatTokenProvider WeChatTokenProvider { get; } protected IWeChatTokenProvider WeChatTokenProvider { get; }
protected IUserWeChatOpenIdFinder UserWeChatOpenIdFinder { get; } protected IUserWeChatOpenIdFinder UserWeChatOpenIdFinder { get; }
public SubscribeMessager( public SubscribeMessager(
@ -28,13 +28,13 @@ namespace LINGYUN.Abp.WeChat.MiniProgram.Messages
IHttpClientFactory httpClientFactory, IHttpClientFactory httpClientFactory,
IWeChatTokenProvider weChatTokenProvider, IWeChatTokenProvider weChatTokenProvider,
IUserWeChatOpenIdFinder userWeChatOpenIdFinder, IUserWeChatOpenIdFinder userWeChatOpenIdFinder,
IOptions<AbpWeChatMiniProgramOptions> miniProgramOptions) AbpWeChatMiniProgramOptionsFactory miniProgramOptionsFactory)
{ {
JsonSerializer = jsonSerializer; JsonSerializer = jsonSerializer;
HttpClientFactory = httpClientFactory; HttpClientFactory = httpClientFactory;
WeChatTokenProvider = weChatTokenProvider; WeChatTokenProvider = weChatTokenProvider;
UserWeChatOpenIdFinder = userWeChatOpenIdFinder; UserWeChatOpenIdFinder = userWeChatOpenIdFinder;
MiniProgramOptions = miniProgramOptions.Value; MiniProgramOptionsFactory = miniProgramOptionsFactory;
Logger = NullLogger<SubscribeMessager>.Instance; Logger = NullLogger<SubscribeMessager>.Instance;
} }
@ -64,7 +64,9 @@ namespace LINGYUN.Abp.WeChat.MiniProgram.Messages
public virtual async Task SendAsync(SubscribeMessage message, CancellationToken cancellationToken = default) public virtual async Task SendAsync(SubscribeMessage message, CancellationToken cancellationToken = default)
{ {
var weChatToken = await WeChatTokenProvider.GetTokenAsync(MiniProgramOptions.AppId, MiniProgramOptions.AppSecret, cancellationToken); var options = await MiniProgramOptionsFactory.CreateAsync();
var weChatToken = await WeChatTokenProvider.GetTokenAsync(options.AppId, options.AppSecret, cancellationToken);
var requestParamters = new Dictionary<string, string> var requestParamters = new Dictionary<string, string>
{ {
{ "access_token", weChatToken.AccessToken } { "access_token", weChatToken.AccessToken }

3
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.MiniProgram/README.md

@ -7,7 +7,8 @@
#### 注意 #### 注意
在动态配置中有一个已知的问题: https://github.com/abpframework/abp/issues/6318
因此必须要重建一个动态变更 AbpWeChatMiniProgramOptions 的方法,请使用AbpWeChatMiniProgramOptionsFactory.CreateAsync()
## 配置使用 ## 配置使用

10
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialModule.cs

@ -1,7 +1,5 @@
using LINGYUN.Abp.WeChat.Localization; using LINGYUN.Abp.WeChat.Localization;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Volo.Abp.Localization; using Volo.Abp.Localization;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem; using Volo.Abp.VirtualFileSystem;
@ -26,13 +24,7 @@ namespace LINGYUN.Abp.WeChat.Official
.AddVirtualJson("/LINGYUN/Abp/WeChat/Official/Localization/Resources"); .AddVirtualJson("/LINGYUN/Abp/WeChat/Official/Localization/Resources");
}); });
AddAbpWeChatOfficialOptionsFactory(context.Services); context.Services.AddAbpDynamicOptions<AbpWeChatOfficialOptions, AbpWeChatOfficialOptionsManager>();
}
private static void AddAbpWeChatOfficialOptionsFactory(IServiceCollection services)
{
services.Replace(ServiceDescriptor.Transient<IOptionsFactory<AbpWeChatOfficialOptions>, AbpWeChatOfficialOptionsFactory>());
services.Replace(ServiceDescriptor.Scoped<IOptions<AbpWeChatOfficialOptions>, OptionsManager<AbpWeChatOfficialOptions>>());
} }
} }
} }

48
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialOptionsFactory.cs

@ -1,52 +1,24 @@
using LINGYUN.Abp.WeChat.Official.Settings; using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Options; using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
using Volo.Abp.Threading;
namespace LINGYUN.Abp.WeChat.Official namespace LINGYUN.Abp.WeChat.Official
{ {
public class AbpWeChatOfficialOptionsFactory : AbpOptionsFactory<AbpWeChatOfficialOptions> public class AbpWeChatOfficialOptionsFactory : ITransientDependency
{ {
protected ISettingProvider SettingProvider { get; } protected IOptions<AbpWeChatOfficialOptions> Options { get; }
public AbpWeChatOfficialOptionsFactory(
ISettingProvider settingProvider,
IEnumerable<IConfigureOptions<AbpWeChatOfficialOptions>> setups,
IEnumerable<IPostConfigureOptions<AbpWeChatOfficialOptions>> postConfigures)
: base(setups, postConfigures)
{
SettingProvider = settingProvider;
}
public override AbpWeChatOfficialOptions Create(string name)
{
var options = base.Create(name);
OverrideOptions(options); public AbpWeChatOfficialOptionsFactory(
IOptions<AbpWeChatOfficialOptions> options)
return options;
}
protected virtual void OverrideOptions(AbpWeChatOfficialOptions options)
{ {
AsyncHelper.RunSync(() => OverrideOptionsAsync(options)); Options = options;
} }
protected virtual async Task OverrideOptionsAsync(AbpWeChatOfficialOptions options) public virtual async Task<AbpWeChatOfficialOptions> CreateAsync()
{ {
var appId = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.AppId); await Options.SetAsync();
var appSecret = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.AppSecret);
var url = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.Url);
var token = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.Token);
var aesKey = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.EncodingAESKey);
options.AppId = appId ?? options.AppId; return Options.Value;
options.AppSecret = appSecret ?? options.AppSecret;
options.Url = url ?? options.Url;
options.Token = token ?? options.Token;
options.EncodingAESKey = aesKey ?? options.EncodingAESKey;
} }
} }
} }

35
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialOptionsManager.cs

@ -0,0 +1,35 @@
using LINGYUN.Abp.WeChat.Official.Settings;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using Volo.Abp.Options;
using Volo.Abp.Settings;
namespace LINGYUN.Abp.WeChat.Official
{
public class AbpWeChatOfficialOptionsManager : AbpDynamicOptionsManager<AbpWeChatOfficialOptions>
{
protected ISettingProvider SettingProvider { get; }
public AbpWeChatOfficialOptionsManager(
ISettingProvider settingProvider,
IOptionsFactory<AbpWeChatOfficialOptions> factory)
: base(factory)
{
SettingProvider = settingProvider;
}
protected override async Task OverrideOptionsAsync(string name, AbpWeChatOfficialOptions options)
{
var appId = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.AppId);
var appSecret = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.AppSecret);
var url = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.Url);
var token = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.Token);
var aesKey = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.EncodingAESKey);
options.AppId = appId ?? options.AppId;
options.AppSecret = appSecret ?? options.AppSecret;
options.Url = url ?? options.Url;
options.Token = token ?? options.Token;
options.EncodingAESKey = aesKey ?? options.EncodingAESKey;
}
}
}

3
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Official/README.md

@ -7,7 +7,8 @@
#### 注意 #### 注意
在动态配置中有一个已知的问题: https://github.com/abpframework/abp/issues/6318
因此必须要重建一个动态变更 AbpWeChatOfficialOptions 的方法,请使用AbpWeChatOfficialOptionsFactory.CreateAsync()
## 配置使用 ## 配置使用

11
aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Caching.StackExchangeRedis; using Microsoft.Extensions.Caching.StackExchangeRedis;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -154,6 +155,16 @@ namespace AuthServer.Host
options.InstanceName = configuration["Redis:InstanceName"]; options.InstanceName = configuration["Redis:InstanceName"];
}); });
// 增加配置文件定义,在新建租户时需要
Configure<IdentityOptions>(options =>
{
var identityConfiguration = configuration.GetSection("Identity");
if (identityConfiguration.Exists())
{
identityConfiguration.Bind(options);
}
});
Configure<AbpVirtualFileSystemOptions>(options => Configure<AbpVirtualFileSystemOptions>(options =>
{ {
options.FileSets.AddEmbedded<AuthIdentityServerModule>("AuthServer"); options.FileSets.AddEmbedded<AuthIdentityServerModule>("AuthServer");

525
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EventBus/Handlers/TenantSynchronizer.cs

@ -0,0 +1,525 @@
using LINGYUN.Abp.MultiTenancy;
using LINGYUN.Platform.Datas;
using LINGYUN.Platform.Layouts;
using LINGYUN.Platform.Menus;
using LINGYUN.Platform.Routes;
using LINGYUN.Platform.Utils;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Platform.EventBus.Handlers
{
public class TenantSynchronizer :
IDistributedEventHandler<CreateEventData>,
ITransientDependency
{
protected ICurrentTenant CurrentTenant { get; }
protected IGuidGenerator GuidGenerator { get; }
protected IRouteDataSeeder RouteDataSeeder { get; }
protected IDataDictionaryDataSeeder DataDictionaryDataSeeder { get; }
protected IMenuRepository MenuRepository { get; }
protected ILayoutRepository LayoutRepository { get; }
public TenantSynchronizer(
ICurrentTenant currentTenant,
IRouteDataSeeder routeDataSeeder,
IMenuRepository menuRepository,
ILayoutRepository layoutRepository,
IGuidGenerator guidGenerator,
IDataDictionaryDataSeeder dataDictionaryDataSeeder)
{
CurrentTenant = currentTenant;
GuidGenerator = guidGenerator;
RouteDataSeeder = routeDataSeeder;
MenuRepository = menuRepository;
LayoutRepository = layoutRepository;
DataDictionaryDataSeeder = dataDictionaryDataSeeder;
}
/// <summary>
/// 租户创建之后需要预置租户平台数据
/// </summary>
/// <param name="eventData"></param>
/// <returns></returns>
public virtual async Task HandleEventAsync(CreateEventData eventData)
{
using (CurrentTenant.Change(eventData.Id))
{
var data = await SeedDefaultDataDictionaryAsync(eventData.Id);
// 预置
var layout = await SeedDefaultLayoutAsync(data);
// 首页
await SeedHomeMenuAsync(layout, data);
// 管理菜单预置菜单数据
await SeedAdminMenuAsync(layout, data);
// 审计日志菜单数据
await SeedAuditingMenuAsync(layout, data);
// 布局容器预置菜单数据
await SeedContainerMenuAsync(layout, data);
}
}
/// <summary>
/// 租户删除之后删除租户平台数据
/// TODO: 不应删除用户数据
/// </summary>
/// <param name="eventData"></param>
/// <returns></returns>
//public virtual async Task HandleEventAsync(DeleteEventData eventData)
//{
// //await MenuRepository.GetAllAsync();
//}
private async Task<Data> SeedDefaultDataDictionaryAsync(Guid? tenantId)
{
var data = await DataDictionaryDataSeeder
.SeedAsync(
"Layout",
CodeNumberGenerator.CreateCode(1),
"Vue Admin Layout Meta Dictionary",
"Vue Admin Layout Meta Dictionary",
null,
tenantId);
data.AddItem(
GuidGenerator,
"roles", // TODO: 是否需要把这一项写入到预置数据?
"roles",
"",
Datas.ValueType.Array,
"will control the page roles (allow setting multiple roles)");
data.AddItem(
GuidGenerator,
"title",
"title",
"component",
Datas.ValueType.String,
"the name showed in subMenu and breadcrumb (recommend set)");
data.AddItem(
GuidGenerator,
"icon",
"icon",
"icon",
Datas.ValueType.String,
"the icon showed in the sidebar");
data.AddItem(
GuidGenerator,
"hidden",
"hidden",
"false",
Datas.ValueType.Boolean,
"if true, this route will not show in the sidebar (default is false)");
data.AddItem(
GuidGenerator,
"alwaysShow",
"alwaysShow",
"false",
Datas.ValueType.Boolean,
"if true, will always show the root menu (default is false)");
data.AddItem(
GuidGenerator,
"breadcrumb",
"breadcrumb",
"true",
Datas.ValueType.Boolean,
"if false, the item will be hidden in breadcrumb (default is true)");
data.AddItem(
GuidGenerator,
"noCache",
"noCache",
"false",
Datas.ValueType.Boolean,
"if true, the page will not be cached (default is false)");
data.AddItem(
GuidGenerator,
"affix",
"affix",
"false",
Datas.ValueType.Boolean,
"if true, the tag will affix in the tags-view");
data.AddItem(
GuidGenerator,
"activeMenu",
"activeMenu",
"",
Datas.ValueType.String,
"if set path, the sidebar will highlight the path you set");
return data;
}
private async Task<Layout> SeedDefaultLayoutAsync(Data data)
{
var layout = await RouteDataSeeder.SeedLayoutAsync(
"Layout",
"layout/index.vue",
"Vue Admin Layout",
data.Id,
PlatformType.WebMvvm, // 针对当前的vue管理页
"",
"Vue Admin Layout",
data.TenantId
);
return layout;
}
private async Task SeedHomeMenuAsync(Layout layout, Data data)
{
var adminMenu = await SeedMenuAsync(
layout,
data,
"home",
"/",
CodeNumberGenerator.CreateCode(1),
layout.Path,
"Home",
"/dashboard",
"Home",
null,
layout.TenantId,
new Dictionary<string, object>()
{
{ "title", "home" },
{ "icon", "home" },
{ "alwaysShow", true }
},
// isPublic: true,
isPublic: false); // 首页应该是共有的页面
await SeedMenuAsync(
layout,
data,
"dashboard",
"dashboard",
CodeNumberGenerator.AppendCode(adminMenu.Code, CodeNumberGenerator.CreateCode(1)),
"views/dashboard/index.vue",
"Dashboard",
"",
"Dashboard",
adminMenu.Id,
layout.TenantId,
new Dictionary<string, object>()
{
{ "title", "dashboard" },
{ "icon", "dashboard" }
},
isPublic: false);
}
private async Task SeedAdminMenuAsync(Layout layout, Data data)
{
var adminMenu = await SeedMenuAsync(
layout,
data,
"admin",
"/admin",
CodeNumberGenerator.CreateCode(2),
layout.Path,
"Admin",
"",
"Admin",
null,
layout.TenantId,
new Dictionary<string, object>()
{
{ "title", "admin" },
{ "icon", "admin" },
{ "alwaysShow", true }
},
new string[] { "admin" });
await SeedMenuAsync(
layout,
data,
"roles",
"roles",
CodeNumberGenerator.AppendCode(adminMenu.Code, CodeNumberGenerator.CreateCode(1)),
"views/admin/roles/index.vue",
"Manage Roles",
"",
"Manage Roles",
adminMenu.Id,
layout.TenantId,
new Dictionary<string, object>()
{
{ "title", "roles" },
{ "icon", "role" },
{ "roles", new string[] { "AbpIdentity.Roles" } }
},
new string[] { "admin" });
await SeedMenuAsync(
layout,
data,
"users",
"users",
CodeNumberGenerator.AppendCode(adminMenu.Code, CodeNumberGenerator.CreateCode(2)),
"views/admin/users/index.vue",
"Manage Users",
"",
"Manage Users",
adminMenu.Id,
layout.TenantId,
new Dictionary<string, object>()
{
{ "title", "users" },
{ "icon", "users" },
{ "roles", new string[] { "AbpIdentity.Users" } }
},
new string[] { "admin" });
await SeedMenuAsync(
layout,
data,
"organization-unit",
"organization-unit",
CodeNumberGenerator.AppendCode(adminMenu.Code, CodeNumberGenerator.CreateCode(3)),
"views/admin/organization-unit/index.vue",
"Manage Organization Units",
"",
"Manage Organization Units",
adminMenu.Id,
layout.TenantId,
new Dictionary<string, object>()
{
{ "title", "organization-unit" },
{ "icon", "organization-unit" },
{ "roles", new string[] { "AbpIdentity.OrganizationUnits" } }
},
new string[] { "admin" });
await SeedMenuAsync(
layout,
data,
"data-dictionary",
"data-dictionary",
CodeNumberGenerator.AppendCode(adminMenu.Code, CodeNumberGenerator.CreateCode(5)),
"views/admin/data-dictionary/index.vue",
"Manage Data Dictionarys",
"",
"Manage Data Dictionarys",
adminMenu.Id,
layout.TenantId,
new Dictionary<string, object>()
{
{ "title", "data-dictionary" },
{ "icon", "data-dictionary" },
{ "roles", new string[] { "Platform.DataDictionary" } }
},
new string[] { "admin" });
await SeedMenuAsync(
layout,
data,
"settings",
"settings",
CodeNumberGenerator.AppendCode(adminMenu.Code, CodeNumberGenerator.CreateCode(6)),
"views/admin/settings/index.vue",
"Manage Settings",
"",
"Manage Settings",
adminMenu.Id,
layout.TenantId,
new Dictionary<string, object>()
{
{ "title", "settings" },
{ "icon", "settings" },
{ "roles", new string[] { "AbpSettingManagement.Settings" } }
},
new string[] { "admin" });
}
private async Task SeedAuditingMenuAsync(Layout layout, Data data)
{
var auditingMenu = await SeedMenuAsync(
layout,
data,
"auditing",
"/auditing",
CodeNumberGenerator.CreateCode(5),
layout.Path,
"Auditing",
"",
"Auditing",
null,
layout.TenantId,
new Dictionary<string, object>()
{
{ "title", "auditing" },
{ "icon", "auditing" },
{ "alwaysShow", true },
{ "roles", new string[]{ "AbpAuditing.AuditLog", "AbpAuditing.SecurityLog" } }
},
new string[] { "admin" });
await SeedMenuAsync(
layout,
data,
"audit-log",
"audit-log",
CodeNumberGenerator.AppendCode(auditingMenu.Code, CodeNumberGenerator.CreateCode(1)),
"views/admin/auditing/audit-log/index.vue",
"Manage AuditLog",
"",
"Manage AuditLog",
auditingMenu.Id,
layout.TenantId,
new Dictionary<string, object>()
{
{ "title", "audit-log" },
{ "icon", "audit-log" },
{ "roles", new string[]{ "AbpAuditing.AuditLog" } }
},
new string[] { "admin" });
await SeedMenuAsync(
layout,
data,
"security-log",
"security-log",
CodeNumberGenerator.AppendCode(auditingMenu.Code, CodeNumberGenerator.CreateCode(2)),
"views/admin/auditing/security-log/index.vue",
"Manage SecurityLog",
"",
"Manage SecurityLog",
auditingMenu.Id,
layout.TenantId,
new Dictionary<string, object>()
{
{ "title", "security-log" },
{ "icon", "security-log" },
{ "roles", new string[]{ "AbpAuditing.SecurityLog" } }
},
new string[] { "admin" });
}
private async Task SeedContainerMenuAsync(Layout layout, Data data)
{
var containerRoot = await SeedMenuAsync(
layout,
data,
"container",
"/container",
CodeNumberGenerator.CreateCode(6),
layout.Path,
"Container",
"",
"Manage Container",
null,
layout.TenantId,
new Dictionary<string, object>()
{
{ "title", "container" },
{ "icon", "container" },
{ "alwaysShow", true }
},
new string[] { "admin" });
await SeedMenuAsync(
layout,
data,
"layouts",
"layouts",
CodeNumberGenerator.AppendCode(containerRoot.Code, CodeNumberGenerator.CreateCode(1)),
"views/container/layouts/index.vue",
"Manage Layouts",
"",
"Manage Layouts",
containerRoot.Id,
containerRoot.TenantId,
new Dictionary<string, object>()
{
{ "title", "layouts" },
{ "icon", "layout" }
},
new string[] { "admin" });
await SeedMenuAsync(
layout,
data,
"menus",
"menus",
CodeNumberGenerator.AppendCode(containerRoot.Code, CodeNumberGenerator.CreateCode(2)),
"views/container/menus/index.vue",
"Manage Menus",
"",
"Manage Menus",
containerRoot.Id,
containerRoot.TenantId,
new Dictionary<string, object>()
{
{ "title", "menus" },
{ "icon", "menu" }
},
new string[] { "admin" });
}
private async Task<Menu> SeedMenuAsync(
Layout layout,
Data data,
string name,
string path,
string code,
string component,
string displayName,
string redirect = "",
string description = "",
Guid? parentId = null,
Guid? tenantId = null,
Dictionary<string, object> meta = null,
string[] roles = null,
Guid[] users = null,
bool isPublic = false
)
{
var menu = await RouteDataSeeder.SeedMenuAsync(
layout,
name,
path,
code,
component,
displayName,
redirect,
description,
parentId,
tenantId,
isPublic
);
foreach (var item in data.Items)
{
menu.SetProperty(item.Name, item.DefaultValue);
}
if (meta != null)
{
foreach (var item in meta)
{
menu.SetProperty(item.Key, item.Value);
}
}
if (roles != null)
{
foreach (var role in roles)
{
await RouteDataSeeder.SeedRoleMenuAsync(role, menu, tenantId);
}
}
if (users != null)
{
foreach (var user in users)
{
await RouteDataSeeder.SeedUserMenuAsync(user, menu, tenantId);
}
}
return menu;
}
}
}
Loading…
Cancel
Save