From d720281bddd68de9df91b0e7cb925a21aa20fc6d Mon Sep 17 00:00:00 2001 From: colin Date: Sat, 8 Mar 2025 21:22:31 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AbpEncryptionConsoleModule.cs | 4 +- .../LINGYUN.Abp.Encryption.Console/Program.cs | 47 ++- .../IWeChatWorkAuthorizeAppService.cs | 4 +- .../Message/IWeChatWorkMessageAppService.cs | 6 +- .../WeChatWorkAuthorizeAppService.cs | 13 +- .../Message/WeChatWorkMessageAppService.cs | 52 ++- .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 ++ .../LINGYUN.Abp.WeChat.Work.AspNetCore.csproj | 24 ++ .../AbpWeChatWorkAspNetCoreModule.cs | 11 + .../WeChat/Work/WeChatWorkOAuthConsts.cs | 40 +++ .../WeChat/Work/WeChatWorkOAuthHandler.cs | 329 ++++++++++++++++++ .../WeChat/Work/WeChatWorkOAuthOptions.cs | 43 +++ .../WeChatWorkAuthenticationExtensions.cs | 63 ++++ .../System/BytesExtensions.cs | 16 + .../System/StringExtensions.cs | 17 + .../System/Text/Json/JsonElementExtensions.cs | 63 ++++ .../WeChatWorkAuthorizeController.cs | 16 +- .../Message/WeChatWorkMessageController.cs | 10 +- .../WeChat/Work/AbpWeChatWorkGlobalConsts.cs | 4 +- .../Abp/WeChat/Work/AbpWeChatWorkModule.cs | 3 - .../IWeChatWorkAuthorizeGenerator.cs | 4 - .../Work/Authorize/IWeChatWorkUserFinder.cs | 2 - .../Authorize/WeChatWorkAuthorizeGenerator.cs | 16 +- .../Work/Authorize/WeChatWorkUserFinder.cs | 6 +- .../Work/Chat/WeChatWorkAppChatManager.cs | 6 +- .../Work/Localization/Resources/en.json | 12 +- .../Work/Localization/Resources/zh-Hans.json | 8 + .../Work/Media/IWeChatWorkMediaProvider.cs | 6 - .../Work/Media/WeChatWorkMediaProvider.cs | 9 +- .../Messages/IWeChatWorkMessageManager.cs | 3 +- .../Work/Messages/WeChatWorkMessageManager.cs | 4 +- .../Work/Messages/WeChatWorkMessageSender.cs | 4 +- .../WeChat/Work/NumberToStringConverter.cs | 26 ++ .../Claims/AbpWeChatWorkClaimTypes.cs | 16 +- .../Security/WeChatWorkCryptoConfiguration.cs | 35 -- ...WeChatWorkCryptoConfigurationDictionary.cs | 12 - .../WeChatWorkSettingDefinitionProvider.cs | 41 +++ .../Work/Settings/WeChatWorkSettingNames.cs | 20 +- .../Work/Token/IWeChatWorkTokenProvider.cs | 5 +- .../Token/Models/WeChatWorkTokenResponse.cs | 4 + .../Work/Token/WeChatWorkTokenProvider.cs | 68 +--- .../WeChatWorkApplicationConfiguration.cs | 43 --- ...tWorkApplicationConfigurationDictionary.cs | 14 - .../Abp/WeChat/Work/WeChatWorkOptions.cs | 11 - .../DataSeeder/ClientDataSeederContributor.cs | 272 +-------------- ...ications.Single.EntityFrameworkCore.csproj | 1 - .../SingleMigrationsDbContext.cs | 2 - ...ngleMigrationsEntityFrameworkCoreModule.cs | 2 - .../Models/QrCodeUserInfoResult.cs | 5 +- .../Controllers/QrCodeLoginController.cs | 53 +-- .../AbpGdprIdentityUserAccountProvider.cs | 7 +- .../Abp/Identity/QrCode/QrCodeCacheItem.cs | 1 + .../LINGYUN/Abp/Identity/QrCode/QrCodeInfo.cs | 1 + .../WeChat/Work/WeChatWorkGrantValidator.cs | 7 +- .../Work/WeChatWorkTokenExtensionGrant.cs | 7 +- .../WeChatWorkNotificationPublishProvider.cs | 54 +-- .../AbpCookieAuthenticationHandler.cs | 91 ----- .../DataSeeder/DataSeederWorker.cs | 16 - .../GlobalUsings.cs | 14 +- .../CustomIdentityResources.cs | 16 - ...LY.MicroService.Applications.Single.csproj | 14 +- ...rviceApplicationsSingleModule.Configure.cs | 131 +++---- .../MicroServiceApplicationsSingleModule.cs | 15 +- .../Program.cs | 8 +- .../AuthServerModule.Configure.cs | 14 +- .../AuthServerModule.cs | 2 + .../AbpCookieAuthenticationHandler.cs | 89 ----- .../LY.MicroService.AuthServer.csproj | 1 + 69 files changed, 1055 insertions(+), 941 deletions(-) create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/FodyWeavers.xml create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/FodyWeavers.xsd create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/LINGYUN.Abp.WeChat.Work.AspNetCore.csproj create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/LINGYUN/Abp/WeChat/Work/AspNetCore/AbpWeChatWorkAspNetCoreModule.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChat/Work/WeChatWorkOAuthConsts.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChat/Work/WeChatWorkOAuthHandler.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChat/Work/WeChatWorkOAuthOptions.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChatWorkAuthenticationExtensions.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/System/BytesExtensions.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/System/StringExtensions.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/System/Text/Json/JsonElementExtensions.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/NumberToStringConverter.cs delete mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoConfiguration.cs delete mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoConfigurationDictionary.cs delete mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkApplicationConfiguration.cs delete mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkApplicationConfigurationDictionary.cs delete mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkOptions.cs delete mode 100644 aspnet-core/services/LY.MicroService.Applications.Single/Authentication/AbpCookieAuthenticationHandler.cs delete mode 100644 aspnet-core/services/LY.MicroService.Applications.Single/DataSeeder/DataSeederWorker.cs delete mode 100644 aspnet-core/services/LY.MicroService.Applications.Single/IdentityResources/CustomIdentityResources.cs delete mode 100644 aspnet-core/services/LY.MicroService.AuthServer/Authentication/AbpCookieAuthenticationHandler.cs diff --git a/aspnet-core/framework/console/LINGYUN.Abp.Encryption.Console/AbpEncryptionConsoleModule.cs b/aspnet-core/framework/console/LINGYUN.Abp.Encryption.Console/AbpEncryptionConsoleModule.cs index 3f07e2119..4d9eb6bd7 100644 --- a/aspnet-core/framework/console/LINGYUN.Abp.Encryption.Console/AbpEncryptionConsoleModule.cs +++ b/aspnet-core/framework/console/LINGYUN.Abp.Encryption.Console/AbpEncryptionConsoleModule.cs @@ -1,11 +1,13 @@ using LINGYUN.Abp.Encryption.SM4; using System.Text; using Volo.Abp.Modularity; +using Volo.Abp.Security; using Volo.Abp.Security.Encryption; namespace LINGYUN.Abp.Encryption.Console; -[DependsOn(typeof(AbpEncryptionSM4Module))] +//[DependsOn(typeof(AbpEncryptionSM4Module))] +[DependsOn(typeof(AbpSecurityModule))] public class AbpEncryptionConsoleModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/aspnet-core/framework/console/LINGYUN.Abp.Encryption.Console/Program.cs b/aspnet-core/framework/console/LINGYUN.Abp.Encryption.Console/Program.cs index f5daec401..5ffe8a6d9 100644 --- a/aspnet-core/framework/console/LINGYUN.Abp.Encryption.Console/Program.cs +++ b/aspnet-core/framework/console/LINGYUN.Abp.Encryption.Console/Program.cs @@ -16,27 +16,40 @@ namespace LINGYUN.Abp.Encryption.Console application.Initialize(); - WriteLine("D:解密 E:加密"); - - var opt = ReadLine(); - bool en = false; - if ("E".Equals(opt, StringComparison.InvariantCultureIgnoreCase)) - { - en = true; - WriteLine("请输入需要加密的字符串"); - } - else + while (true) { - WriteLine("请输入需要解密的字符串"); + WriteLine("D:解密 E:加密 Q: 退出"); + + var opt = ReadLine(); + var en = false; + + if (opt == "Q") + { + break; + } + + if ("E".Equals(opt, StringComparison.InvariantCultureIgnoreCase)) + { + en = true; + WriteLine("请输入需要加密的字符串"); + } + else + { + WriteLine("请输入需要解密的字符串"); + } + + var sourceChr = ReadLine(); + var encryptionService = application.ServiceProvider.GetRequiredService(); + WriteLine(en ? encryptionService.Encrypt(sourceChr) : encryptionService.Decrypt(sourceChr)); + + WriteLine("按任意键继续"); + + ReadKey(); + + Clear(); } - - var sourceChr = ReadLine(); - var encryptionService = application.ServiceProvider.GetRequiredService(); - WriteLine(en ? encryptionService.Encrypt(sourceChr) : encryptionService.Decrypt(sourceChr)); application.Shutdown(); - - ReadKey(); } } } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application.Contracts/LINGYUN/Abp/WeChat/Work/Authorize/IWeChatWorkAuthorizeAppService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application.Contracts/LINGYUN/Abp/WeChat/Work/Authorize/IWeChatWorkAuthorizeAppService.cs index 6252e321b..06f8a7b06 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application.Contracts/LINGYUN/Abp/WeChat/Work/Authorize/IWeChatWorkAuthorizeAppService.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application.Contracts/LINGYUN/Abp/WeChat/Work/Authorize/IWeChatWorkAuthorizeAppService.cs @@ -5,13 +5,11 @@ namespace LINGYUN.Abp.WeChat.Work.Authorize; public interface IWeChatWorkAuthorizeAppService : IApplicationService { Task GenerateOAuth2AuthorizeAsync( - string agentid, string redirectUri, string responseType = "code", string scope = "snsapi_base"); Task GenerateOAuth2LoginAsync( string redirectUri, - string loginType = "ServiceApp", - string agentid = ""); + string loginType = "ServiceApp"); } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application.Contracts/LINGYUN/Abp/WeChat/Work/Message/IWeChatWorkMessageAppService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application.Contracts/LINGYUN/Abp/WeChat/Work/Message/IWeChatWorkMessageAppService.cs index 334215892..181c1c1c8 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application.Contracts/LINGYUN/Abp/WeChat/Work/Message/IWeChatWorkMessageAppService.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application.Contracts/LINGYUN/Abp/WeChat/Work/Message/IWeChatWorkMessageAppService.cs @@ -13,18 +13,16 @@ public interface IWeChatWorkMessageAppService : IApplicationService /// /// 参考文档: /// - /// /// /// - Task Handle(string agentId, MessageValidationInput input); + Task Handle(MessageValidationInput input); /// /// 处理企业微信消息 /// /// /// 参考文档: /// - /// /// /// - Task Handle(string agentId, MessageHandleInput input); + Task Handle(MessageHandleInput input); } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeAppService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeAppService.cs index 8f4b955f3..cf3112900 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeAppService.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeAppService.cs @@ -21,21 +21,22 @@ public class WeChatWorkAuthorizeAppService : ApplicationService, IWeChatWorkAuth _authorizeGenerator = authorizeGenerator; } - public async virtual Task GenerateOAuth2AuthorizeAsync(string agentid, string redirectUri, string responseType = "code", string scope = "snsapi_base") + public async virtual Task GenerateOAuth2AuthorizeAsync(string redirectUri, string responseType = "code", string scope = "snsapi_base") { - var state = _encryptionService.Encrypt($"agentid={agentid}&redirectUri={redirectUri}&responseType={responseType}&scope={scope}&random={Guid.NewGuid():D}").ToMd5(); - return await _authorizeGenerator.GenerateOAuth2AuthorizeAsync(agentid, redirectUri, state, responseType, scope); + var state = _encryptionService.Encrypt($"redirectUri={redirectUri}&responseType={responseType}&scope={scope}&random={Guid.NewGuid():D}").ToMd5(); + + return await _authorizeGenerator.GenerateOAuth2AuthorizeAsync(redirectUri, state, responseType, scope); } - public async virtual Task GenerateOAuth2LoginAsync(string redirectUri, string loginType = "ServiceApp", string agentid = "") + public async virtual Task GenerateOAuth2LoginAsync(string redirectUri, string loginType = "ServiceApp") { - var state = _encryptionService.Encrypt($"agentid={agentid}&redirectUri={redirectUri}&loginType={loginType}&agentid={agentid}&random={Guid.NewGuid():D}").ToMd5(); + var state = _encryptionService.Encrypt($"redirectUri={redirectUri}&loginType={loginType}&random={Guid.NewGuid():D}").ToMd5(); var corpId = await SettingProvider.GetOrNullAsync(WeChatWorkSettingNames.Connection.CorpId); Check.NotNullOrEmpty(corpId, nameof(corpId)); - return await _authorizeGenerator.GenerateOAuth2LoginAsync(corpId, redirectUri, state, loginType, agentid); + return await _authorizeGenerator.GenerateOAuth2LoginAsync(corpId, redirectUri, state, loginType); } } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageAppService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageAppService.cs index b4552c38a..69bf0f06b 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageAppService.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageAppService.cs @@ -3,7 +3,7 @@ using LINGYUN.Abp.WeChat.Common.Crypto.Models; using LINGYUN.Abp.WeChat.Common.Messages; using LINGYUN.Abp.WeChat.Work.Settings; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; +using System.Linq; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Application.Services; @@ -13,33 +13,40 @@ namespace LINGYUN.Abp.WeChat.Work.Message; public class WeChatWorkMessageAppService : ApplicationService, IWeChatWorkMessageAppService { private readonly IWeChatCryptoService _cryptoService; - private readonly WeChatWorkOptions _options; private readonly IDistributedEventBus _distributedEventBus; private readonly IMessageResolver _messageResolver; public WeChatWorkMessageAppService( IMessageResolver messageResolver, IWeChatCryptoService cryptoService, - IDistributedEventBus distributedEventBus, - IOptionsMonitor options) + IDistributedEventBus distributedEventBus) { _cryptoService = cryptoService; _messageResolver = messageResolver; _distributedEventBus = distributedEventBus; - _options = options.CurrentValue; } - public async virtual Task Handle(string agentId, MessageValidationInput input) + public async virtual Task Handle(MessageValidationInput input) { - var corpId = await SettingProvider.GetOrNullAsync(WeChatWorkSettingNames.Connection.CorpId); + var allSettings = await SettingProvider.GetAllAsync( + new[] { + WeChatWorkSettingNames.Connection.CorpId, + WeChatWorkSettingNames.Connection.Token, + WeChatWorkSettingNames.Connection.EncodingAESKey, + } ); + + var corpId = allSettings.FirstOrDefault(x => x.Name == WeChatWorkSettingNames.Connection.CorpId)?.Value; + var token = allSettings.FirstOrDefault(x => x.Name == WeChatWorkSettingNames.Connection.Token)?.Value; + var aesKey = allSettings.FirstOrDefault(x => x.Name == WeChatWorkSettingNames.Connection.EncodingAESKey)?.Value; + Check.NotNullOrEmpty(corpId, nameof(corpId)); + Check.NotNullOrEmpty(token, nameof(token)); + Check.NotNullOrEmpty(aesKey, nameof(aesKey)); - var applicationConfiguration = _options.Applications.GetConfiguration(agentId); - var cryptoConfiguration = applicationConfiguration.GetCryptoConfiguration("Message"); var echoData = new WeChatCryptoEchoData( input.EchoStr, corpId, - cryptoConfiguration.Token, - cryptoConfiguration.EncodingAESKey, + token, + aesKey, input.Msg_Signature, input.TimeStamp.ToString(), input.Nonce); @@ -49,18 +56,27 @@ public class WeChatWorkMessageAppService : ApplicationService, IWeChatWorkMessag return echoStr; } - public async virtual Task Handle(string agentId, MessageHandleInput input) + public async virtual Task Handle(MessageHandleInput input) { - var corpId = await SettingProvider.GetOrNullAsync(WeChatWorkSettingNames.Connection.CorpId); - Check.NotNullOrEmpty(corpId, nameof(corpId)); + var allSettings = await SettingProvider.GetAllAsync( + new[] { + WeChatWorkSettingNames.Connection.CorpId, + WeChatWorkSettingNames.Connection.Token, + WeChatWorkSettingNames.Connection.EncodingAESKey, + }); - var applicationConfiguration = _options.Applications.GetConfiguration(agentId); - var cryptoConfiguration = applicationConfiguration.GetCryptoConfiguration("Message"); + var corpId = allSettings.FirstOrDefault(x => x.Name == WeChatWorkSettingNames.Connection.CorpId)?.Value; + var token = allSettings.FirstOrDefault(x => x.Name == WeChatWorkSettingNames.Connection.Token)?.Value; + var aesKey = allSettings.FirstOrDefault(x => x.Name == WeChatWorkSettingNames.Connection.EncodingAESKey)?.Value; + + Check.NotNullOrEmpty(corpId, nameof(corpId)); + Check.NotNullOrEmpty(token, nameof(token)); + Check.NotNullOrEmpty(aesKey, nameof(aesKey)); var messageData = new MessageResolveData( corpId, - cryptoConfiguration.Token, - cryptoConfiguration.EncodingAESKey, + token, + aesKey, input.Msg_Signature, input.TimeStamp, input.Nonce, diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/FodyWeavers.xml b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/FodyWeavers.xsd b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/LINGYUN.Abp.WeChat.Work.AspNetCore.csproj b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/LINGYUN.Abp.WeChat.Work.AspNetCore.csproj new file mode 100644 index 000000000..fc5375e1a --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/LINGYUN.Abp.WeChat.Work.AspNetCore.csproj @@ -0,0 +1,24 @@ + + + + + + + net9.0 + LINGYUN.Abp.WeChat.Work.AspNetCore + LINGYUN.Abp.WeChat.Work.AspNetCore + false + false + false + + + + + + + + + + + + diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/LINGYUN/Abp/WeChat/Work/AspNetCore/AbpWeChatWorkAspNetCoreModule.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/LINGYUN/Abp/WeChat/Work/AspNetCore/AbpWeChatWorkAspNetCoreModule.cs new file mode 100644 index 000000000..4a091d6d3 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/LINGYUN/Abp/WeChat/Work/AspNetCore/AbpWeChatWorkAspNetCoreModule.cs @@ -0,0 +1,11 @@ +using Volo.Abp.AspNetCore; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.WeChat.Work.AspNetCore; + +[DependsOn( + typeof(AbpWeChatWorkModule), + typeof(AbpAspNetCoreModule))] +public class AbpWeChatWorkAspNetCoreModule : AbpModule +{ +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChat/Work/WeChatWorkOAuthConsts.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChat/Work/WeChatWorkOAuthConsts.cs new file mode 100644 index 000000000..d4b3c84be --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChat/Work/WeChatWorkOAuthConsts.cs @@ -0,0 +1,40 @@ +using LINGYUN.Abp.WeChat.Work; + +namespace Microsoft.AspNetCore.Authentication.WeChat.Work; + +public static class WeChatWorkOAuthConsts +{ + /// + /// 微信个人信息标识 + /// + public static string ProfileKey => AbpWeChatWorkGlobalConsts.ProfileKey; + /// + /// 微信提供者标识 + /// + public static string ProviderKey => AbpWeChatWorkGlobalConsts.ProviderName; + /// + /// 微信提供者显示名称 + /// + public static string DisplayName => AbpWeChatWorkGlobalConsts.DisplayName; + /// + /// 回调地址 + /// + public static string CallbackPath { get; set; } = "/signin-wxwork"; + /// + /// 微信客户端内的网页登录 + /// + public const string AuthorizationEndpoint = "https://login.work.weixin.qq.com/wwlogin/sso/login"; + /// + /// 用户允许授权后通过返回的code换取access_token地址 + /// + public const string TokenEndpoint = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"; + + /// + /// 使用access_token获取用户个人信息地址 + /// + public const string UserInformationEndpoint = "https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo"; + + public const string UserInfoScope = "snsapi_privateinfo"; + + public const string LoginScope = "snsapi_base"; +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChat/Work/WeChatWorkOAuthHandler.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChat/Work/WeChatWorkOAuthHandler.cs new file mode 100644 index 000000000..85318336e --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChat/Work/WeChatWorkOAuthHandler.cs @@ -0,0 +1,329 @@ +using LINGYUN.Abp.WeChat.Work.Settings; +using LINGYUN.Abp.WeChat.Work.Token; +using Microsoft.AspNetCore.Authentication.OAuth; +using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net.Http; +using System.Security.Claims; +using System.Text; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Settings; + +namespace Microsoft.AspNetCore.Authentication.WeChat.Work; + +public class WeChatWorkOAuthHandler : OAuthHandler +{ + protected ISettingProvider SettingProvider { get; } + public WeChatWorkOAuthHandler( + ISettingProvider settingProvider, + IWeChatWorkTokenProvider wechatWorkTokenProvider, + IOptionsMonitor options, + ILoggerFactory logger, + UrlEncoder encoder) + : base(options, logger, encoder) + { + SettingProvider = settingProvider; + } + + /// + /// 重写应用配置 + /// + /// + protected async override Task InitializeHandlerAsync() + { + var settings = await SettingProvider.GetAllAsync( + new[] { + WeChatWorkSettingNames.Connection.CorpId, + WeChatWorkSettingNames.Connection.AgentId, + WeChatWorkSettingNames.Connection.Secret, + }); + + var corpId = settings.FirstOrDefault(x => x.Name == WeChatWorkSettingNames.Connection.CorpId)?.Value; + var agentId = settings.FirstOrDefault(x => x.Name == WeChatWorkSettingNames.Connection.AgentId)?.Value; + var secret = settings.FirstOrDefault(x => x.Name == WeChatWorkSettingNames.Connection.Secret)?.Value; + + Check.NotNullOrEmpty(corpId, nameof(corpId)); + Check.NotNullOrEmpty(agentId, nameof(agentId)); + Check.NotNullOrEmpty(secret, nameof(secret)); + + // 用配置项重写 + Options.CorpId = corpId; + Options.ClientId = agentId; + Options.ClientSecret = secret; + + Options.TimeProvider ??= TimeProvider.System; + + await base.InitializeHandlerAsync(); + } + + /// + /// 第一步:构建用户授权地址 + /// + protected override string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri) + { + var isWeChatBrewserRequest = IsWeChatBrowser(); + + var scope = isWeChatBrewserRequest + ? WeChatWorkOAuthConsts.UserInfoScope + : WeChatWorkOAuthConsts.LoginScope; + + var parameters = new Dictionary + { + { "appid", Options.CorpId }, + { "redirect_uri", redirectUri }, + { "response_type", "code" }, + { "scope", scope }, + { "agentid", Options.ClientId }, + { "lang", "zh" }, + }; + + var state = Options.StateDataFormat.Protect(properties); + + parameters["state"] = state; ; + + return $"{QueryHelpers.AddQueryString(Options.AuthorizationEndpoint, parameters)}"; + } + + /// + /// 第二步:code换取access_token + /// + protected async override Task ExchangeCodeAsync(OAuthCodeExchangeContext context) + { + var parameters = new Dictionary() + { + { "corpid", Options.CorpId }, + { "corpsecret", Options.ClientSecret }, + }; + + var address = QueryHelpers.AddQueryString(Options.TokenEndpoint, parameters); + + var response = await Backchannel.GetAsync(address); + if (!response.IsSuccessStatusCode) + { + Logger.LogError("An error occurred while retrieving an access token: the remote server " + + "returned a {Status} response with the following payload: {Headers} {Body}.", + /* Status: */ response.StatusCode, + /* Headers: */ response.Headers.ToString(), + /* Body: */ await response.Content.ReadAsStringAsync()); + + return OAuthTokenResponse.Failed(new Exception("An error occurred while retrieving an access token.")); + } + + var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync()); + if (payload.GetRootInt32("errcode") != 0) + { + Logger.LogError("An error occurred while retrieving an access token: the remote server " + + "returned a {Status} response with the following payload: {Headers} {Body}.", + /* Status: */ response.StatusCode, + /* Headers: */ response.Headers.ToString(), + /* Body: */ await response.Content.ReadAsStringAsync()); + + return OAuthTokenResponse.Failed(new Exception("An error occurred while retrieving an access token.")); + } + return OAuthTokenResponse.Success(payload); + } + + /// + /// 第三步:构建用户票据 + /// + /// + /// + /// + /// + /// + protected async virtual Task CreateTicketAsync(string code, ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens) + { + var address = QueryHelpers.AddQueryString(Options.UserInformationEndpoint, new Dictionary + { + ["access_token"] = tokens.AccessToken, + ["code"] = code + }); + + var response = await Backchannel.GetAsync(address); + if (!response.IsSuccessStatusCode) + { + Logger.LogError("An error occurred while retrieving the user profile: the remote server " + + "returned a {Status} response with the following payload: {Headers} {Body}.", + /* Status: */ response.StatusCode, + /* Headers: */ response.Headers.ToString(), + /* Body: */ await response.Content.ReadAsStringAsync()); + + throw new HttpRequestException("An error occurred while retrieving user information."); + } + + var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync()); + if (payload.GetRootInt32("errcode") != 0) + { + Logger.LogError("An error occurred while retrieving the user profile: the remote server " + + "returned a {Status} response with the following payload: {Headers} {Body}.", + /* Status: */ response.StatusCode, + /* Headers: */ response.Headers.ToString(), + /* Body: */ await response.Content.ReadAsStringAsync()); + + throw new HttpRequestException("An error occurred while retrieving user information."); + } + + var context = new OAuthCreatingTicketContext( + new ClaimsPrincipal(identity), + properties, + Context, + Scheme, + Options, + Backchannel, + tokens, + payload.RootElement); + + context.RunClaimActions(); + + await Events.CreatingTicket(context); + + return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name); + } + + protected async override Task HandleRemoteAuthenticateAsync() + { + var query = Request.Query; + + var state = query["state"]; + + var properties = Options.StateDataFormat.Unprotect(state); + + if (properties == null) + { + return HandleRequestResult.Fail("The oauth state was missing or invalid."); + } + + // OAuth2 10.12 CSRF + if (!ValidateCorrelationId(properties)) + { + return HandleRequestResult.Fail("Correlation failed.", properties); + } + + var error = query["error"]; + if (!StringValues.IsNullOrEmpty(error)) + { + // Note: access_denied errors are special protocol errors indicating the user didn't + // approve the authorization demand requested by the remote authorization server. + // Since it's a frequent scenario (that is not caused by incorrect configuration), + // denied errors are handled differently using HandleAccessDeniedErrorAsync(). + // Visit https://tools.ietf.org/html/rfc6749#section-4.1.2.1 for more information. + var errorDescription = query["error_description"]; + var errorUri = query["error_uri"]; + if (StringValues.Equals(error, "access_denied")) + { + var result = await HandleAccessDeniedErrorAsync(properties); + if (!result.None) + { + return result; + } + var deniedEx = new Exception("Access was denied by the resource owner or by the remote server."); + deniedEx.Data["error"] = error.ToString(); + deniedEx.Data["error_description"] = errorDescription.ToString(); + deniedEx.Data["error_uri"] = errorUri.ToString(); + + return HandleRequestResult.Fail(deniedEx, properties); + } + + var failureMessage = new StringBuilder(); + failureMessage.Append(error); + if (!StringValues.IsNullOrEmpty(errorDescription)) + { + failureMessage.Append(";Description=").Append(errorDescription); + } + if (!StringValues.IsNullOrEmpty(errorUri)) + { + failureMessage.Append(";Uri=").Append(errorUri); + } + + var ex = new Exception(failureMessage.ToString()); + ex.Data["error"] = error.ToString(); + ex.Data["error_description"] = errorDescription.ToString(); + ex.Data["error_uri"] = errorUri.ToString(); + + return HandleRequestResult.Fail(ex, properties); + } + + var code = query["code"]; + + if (StringValues.IsNullOrEmpty(code)) + { + return HandleRequestResult.Fail("Code was not found.", properties); + } + + var codeExchangeContext = new OAuthCodeExchangeContext(properties, code, BuildRedirectUri(Options.CallbackPath)); + using var tokens = await ExchangeCodeAsync(codeExchangeContext); + + if (tokens.Error != null) + { + return HandleRequestResult.Fail(tokens.Error, properties); + } + + if (string.IsNullOrEmpty(tokens.AccessToken)) + { + return HandleRequestResult.Fail("Failed to retrieve access token.", properties); + } + + var identity = new ClaimsIdentity(ClaimsIssuer); + + if (Options.SaveTokens) + { + var authTokens = new List(); + + authTokens.Add(new AuthenticationToken { Name = "access_token", Value = tokens.AccessToken }); + if (!string.IsNullOrEmpty(tokens.RefreshToken)) + { + authTokens.Add(new AuthenticationToken { Name = "refresh_token", Value = tokens.RefreshToken }); + } + + if (!string.IsNullOrEmpty(tokens.TokenType)) + { + authTokens.Add(new AuthenticationToken { Name = "token_type", Value = tokens.TokenType }); + } + + if (!string.IsNullOrEmpty(tokens.ExpiresIn)) + { + int value; + if (int.TryParse(tokens.ExpiresIn, NumberStyles.Integer, CultureInfo.InvariantCulture, out value)) + { + // https://www.w3.org/TR/xmlschema-2/#dateTime + // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx + var expiresAt = Options.TimeProvider.GetUtcNow() + TimeSpan.FromSeconds(value); + authTokens.Add(new AuthenticationToken + { + Name = "expires_at", + Value = expiresAt.ToString("o", CultureInfo.InvariantCulture) + }); + } + } + + properties.StoreTokens(authTokens); + } + + var ticket = await CreateTicketAsync(code, identity, properties, tokens); + if (ticket != null) + { + return HandleRequestResult.Success(ticket); + } + else + { + return HandleRequestResult.Fail("Failed to retrieve user information from remote server.", properties); + } + } + + protected virtual bool IsWeChatBrowser() + { + var userAgent = Request.Headers[HeaderNames.UserAgent].ToString(); + + return userAgent.Contains("micromessenger", StringComparison.InvariantCultureIgnoreCase); + } +} \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChat/Work/WeChatWorkOAuthOptions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChat/Work/WeChatWorkOAuthOptions.cs new file mode 100644 index 000000000..0a80820c1 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChat/Work/WeChatWorkOAuthOptions.cs @@ -0,0 +1,43 @@ +using LINGYUN.Abp.WeChat.Work.Security.Claims; +using Microsoft.AspNetCore.Authentication.OAuth; +using Microsoft.AspNetCore.Http; +using System.Security.Claims; +using Volo.Abp.Security.Claims; + +namespace Microsoft.AspNetCore.Authentication.WeChat.Work; + +public class WeChatWorkOAuthOptions : OAuthOptions +{ + /// + /// 企业Id + /// + public string CorpId { get; set; } + public WeChatWorkOAuthOptions() + { + // 用于防止初始化错误,会在OAuthHandler.InitializeHandlerAsync中进行重写 + CorpId = "CorpId"; + ClientId = "ClientId"; + ClientSecret = "ClientSecret"; + + CallbackPath = new PathString(WeChatWorkOAuthConsts.CallbackPath); + + AuthorizationEndpoint = WeChatWorkOAuthConsts.AuthorizationEndpoint; + TokenEndpoint = WeChatWorkOAuthConsts.TokenEndpoint; + UserInformationEndpoint = WeChatWorkOAuthConsts.UserInformationEndpoint; + + Scope.Add(WeChatWorkOAuthConsts.LoginScope); + Scope.Add(WeChatWorkOAuthConsts.UserInfoScope); + + ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "userid"); + ClaimActions.MapJsonKey(ClaimTypes.Name, "userid"); + ClaimActions.MapJsonKey("sub", "userid"); + + // 把自定义的身份标识写进令牌 + ClaimActions.MapJsonKey(AbpWeChatWorkClaimTypes.UserId, "userid"); + ClaimActions.MapJsonKey(AbpWeChatWorkClaimTypes.QrCode, "qr_code"); + ClaimActions.MapJsonKey(AbpWeChatWorkClaimTypes.BizMail, "biz_mail"); + ClaimActions.MapJsonKey(AbpWeChatWorkClaimTypes.Address, "address"); + ClaimActions.MapJsonKey(AbpClaimTypes.PhoneNumber, "mobile"); + ClaimActions.MapJsonKey(AbpClaimTypes.Email, "email"); + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChatWorkAuthenticationExtensions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChatWorkAuthenticationExtensions.cs new file mode 100644 index 000000000..9b332c0bb --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/Microsoft/AspNetCore/Authentication/WeChatWorkAuthenticationExtensions.cs @@ -0,0 +1,63 @@ +using LINGYUN.Abp.WeChat.Work; +using Microsoft.AspNetCore.Authentication.WeChat.Work; +using Microsoft.Extensions.DependencyInjection; +using System; + +namespace Microsoft.AspNetCore.Authentication; + +public static class WeChatWorkAuthenticationExtensions +{ + /// + /// + public static AuthenticationBuilder AddWeChatWork( + this AuthenticationBuilder builder) + { + return builder + .AddWeChatWork( + AbpWeChatWorkGlobalConsts.AuthenticationScheme, + AbpWeChatWorkGlobalConsts.DisplayName, + options => { }); + } + + /// + /// + public static AuthenticationBuilder AddWeChatWork( + this AuthenticationBuilder builder, + Action configureOptions) + { + return builder + .AddWeChatWork( + AbpWeChatWorkGlobalConsts.AuthenticationScheme, + AbpWeChatWorkGlobalConsts.DisplayName, + configureOptions); + } + + /// + /// + public static AuthenticationBuilder AddWeChatWork( + this AuthenticationBuilder builder, + string authenticationScheme, + Action configureOptions) + { + return builder + .AddWeChatWork( + authenticationScheme, + AbpWeChatWorkGlobalConsts.DisplayName, + configureOptions); + } + + /// + /// + public static AuthenticationBuilder AddWeChatWork( + this AuthenticationBuilder builder, + string authenticationScheme, + string displayName, + Action configureOptions) + { + return builder + .AddOAuth( + authenticationScheme, + displayName, + configureOptions); + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/System/BytesExtensions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/System/BytesExtensions.cs new file mode 100644 index 000000000..d1bad7915 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/System/BytesExtensions.cs @@ -0,0 +1,16 @@ +using System.Security.Cryptography; + +namespace System +{ + internal static class BytesExtensions + { + public static byte[] Sha1(this byte[] data) + { + using (var sha = SHA1.Create()) + { + var hashBytes = sha.ComputeHash(data); + return hashBytes; + } + } + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/System/StringExtensions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/System/StringExtensions.cs new file mode 100644 index 000000000..a8eb40c27 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/System/StringExtensions.cs @@ -0,0 +1,17 @@ +using System.Security.Cryptography; +using System.Text; + +namespace System +{ + internal static class StringExtensions + { + public static byte[] Sha1(this string str) + { + using (var sha = SHA1.Create()) + { + var hashBytes = sha.ComputeHash(Encoding.ASCII.GetBytes(str)); + return hashBytes; + } + } + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/System/Text/Json/JsonElementExtensions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/System/Text/Json/JsonElementExtensions.cs new file mode 100644 index 000000000..653a868ac --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.AspNetCore/System/Text/Json/JsonElementExtensions.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; + +namespace System.Text.Json +{ + internal static class JsonElementExtensions + { + public static IEnumerable GetRootStrings(this JsonDocument json, string key) + { + return json.RootElement.GetStrings(key); + } + + public static IEnumerable GetStrings(this JsonElement json, string key) + { + var result = new List(); + + if (json.TryGetProperty(key, out JsonElement property) && property.ValueKind == JsonValueKind.Array) + { + foreach (var jsonProp in property.EnumerateArray()) + { + result.Add(jsonProp.GetString()); + } + } + + return result; + } + + public static string GetRootString(this JsonDocument json, string key, string defaultValue = "") + { + if (json.RootElement.TryGetProperty(key, out JsonElement property)) + { + return property.GetString(); + } + return defaultValue; + } + + public static string GetString(this JsonElement json, string key, string defaultValue = "") + { + if (json.TryGetProperty(key, out JsonElement property)) + { + return property.GetString(); + } + return defaultValue; + } + + public static int GetRootInt32(this JsonDocument json, string key, int defaultValue = 0) + { + if (json.RootElement.TryGetProperty(key, out JsonElement property) && property.TryGetInt32(out int value)) + { + return value; + } + return defaultValue; + } + + public static int GetInt32(this JsonElement json, string key, int defaultValue = 0) + { + if (json.TryGetProperty(key, out JsonElement property) && property.TryGetInt32(out int value)) + { + return value; + } + return defaultValue; + } + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.HttpApi/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeController.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.HttpApi/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeController.cs index a47ebaa34..c32f652fe 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.HttpApi/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeController.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.HttpApi/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeController.cs @@ -42,12 +42,11 @@ public class WeChatWorkAuthorizeController : AbpControllerBase, IWeChatWorkAutho [HttpGet] [Route("oauth2")] public virtual Task GenerateOAuth2AuthorizeAsync( - [FromQuery(Name = "agent_id")] string agentid, [FromQuery(Name = "redirect_uri")] string redirectUri, [FromQuery(Name = "response_type")] string responseType = "code", [FromQuery] string scope = "snsapi_base") { - return _service.GenerateOAuth2AuthorizeAsync(agentid, redirectUri, responseType, scope); + return _service.GenerateOAuth2AuthorizeAsync(redirectUri, responseType, scope); } /// @@ -64,12 +63,11 @@ public class WeChatWorkAuthorizeController : AbpControllerBase, IWeChatWorkAutho [HttpGet] [Route("oauth2/authorize")] public async virtual Task OAuth2AuthorizeAsync( - [FromQuery(Name = "agent_id")] string agentid, [FromQuery(Name = "redirect_uri")] string redirectUri, [FromQuery(Name = "response_type")] string responseType = "code", [FromQuery] string scope = "snsapi_base") { - var url = await _service.GenerateOAuth2AuthorizeAsync(agentid, redirectUri, responseType, scope); + var url = await _service.GenerateOAuth2AuthorizeAsync(redirectUri, responseType, scope); return Redirect(url); } @@ -88,10 +86,9 @@ public class WeChatWorkAuthorizeController : AbpControllerBase, IWeChatWorkAutho [Route("oauth2/login")] public virtual Task GenerateOAuth2LoginAsync( [FromQuery(Name = "redirect_uri")] string redirectUri, - [FromQuery(Name = "login_type")] string loginType = "ServiceApp", - [FromQuery(Name = "agent_id")] string agentid = "") + [FromQuery(Name = "login_type")] string loginType = "ServiceApp") { - return _service.GenerateOAuth2LoginAsync(redirectUri, loginType, agentid); + return _service.GenerateOAuth2LoginAsync(redirectUri, loginType); } /// @@ -108,10 +105,9 @@ public class WeChatWorkAuthorizeController : AbpControllerBase, IWeChatWorkAutho [Route("oauth2/login/sso")] public async virtual Task OAuth2LoginAsync( [FromQuery(Name = "redirect_uri")] string redirectUri, - [FromQuery(Name = "login_type")] string loginType = "ServiceApp", - [FromQuery(Name = "agent_id")] string agentid = "") + [FromQuery(Name = "login_type")] string loginType = "ServiceApp") { - var url = await _service.GenerateOAuth2LoginAsync(redirectUri, loginType, agentid); + var url = await _service.GenerateOAuth2LoginAsync(redirectUri, loginType); return Redirect(url); } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.HttpApi/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageController.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.HttpApi/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageController.cs index 2ca95877b..a1e7a3589 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.HttpApi/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageController.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.HttpApi/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageController.cs @@ -36,10 +36,9 @@ public class WeChatWorkMessageController : AbpControllerBase, IWeChatWorkMessage /// 企业微信服务器传递的验证消息参数 /// [HttpGet] - [Route("{agentId}")] - public virtual Task Handle([FromRoute] string agentId, [FromQuery] MessageValidationInput input) + public virtual Task Handle([FromQuery] MessageValidationInput input) { - return _service.Handle(agentId, input); + return _service.Handle(input); } /// @@ -50,14 +49,13 @@ public class WeChatWorkMessageController : AbpControllerBase, IWeChatWorkMessage /// 企业微信服务器传递的消息参数 /// [HttpPost] - [Route("{agentId}")] - public async virtual Task Handle([FromRoute] string agentId, [FromQuery] MessageHandleInput input) + public async virtual Task Handle([FromQuery] MessageHandleInput input) { using var reader = new StreamReader(Request.Body, Encoding.UTF8); var content = await reader.ReadToEndAsync(); input.Data = content; - return await _service.Handle(agentId, input); + return await _service.Handle(input); } } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkGlobalConsts.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkGlobalConsts.cs index d5b5ba2dd..39315c00e 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkGlobalConsts.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkGlobalConsts.cs @@ -5,11 +5,11 @@ public class AbpWeChatWorkGlobalConsts /// /// 企业微信对应的Provider名称 /// - public static string ProviderName { get; set; } = "WeChat.Work"; + public static string ProviderName { get; set; } = "WeChat.WeCom"; /// /// 企业微信授权类型 /// - public static string GrantType { get; set; } = "wx-work"; + public static string GrantType { get; set; } = "wecom"; /// /// 企业微信授权名称 /// diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkModule.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkModule.cs index bdf880dc1..fa7c3c2c3 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkModule.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkModule.cs @@ -24,9 +24,6 @@ public class AbpWeChatWorkModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { - var configuration = context.Services.GetConfiguration(); - Configure(configuration.GetSection("WeChat:Work")); - Configure(options => { options.FileSets.AddEmbedded(); diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/IWeChatWorkAuthorizeGenerator.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/IWeChatWorkAuthorizeGenerator.cs index 5e84a2cec..1b009c805 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/IWeChatWorkAuthorizeGenerator.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/IWeChatWorkAuthorizeGenerator.cs @@ -9,14 +9,12 @@ public interface IWeChatWorkAuthorizeGenerator /// /// 参考:https://developer.work.weixin.qq.com/document/path/91022 /// - /// /// /// /// /// /// Task GenerateOAuth2AuthorizeAsync( - string agentid, string redirectUri, string state, string responseType = "code", @@ -24,7 +22,6 @@ public interface IWeChatWorkAuthorizeGenerator /// /// 构建网页登录链接 /// - /// /// /// /// @@ -32,7 +29,6 @@ public interface IWeChatWorkAuthorizeGenerator /// /// Task GenerateOAuth2LoginAsync( - string appid, string redirectUri, string state, string loginType = "ServiceApp", diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/IWeChatWorkUserFinder.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/IWeChatWorkUserFinder.cs index 9339095b9..cb81fefdc 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/IWeChatWorkUserFinder.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/IWeChatWorkUserFinder.cs @@ -9,12 +9,10 @@ namespace LINGYUN.Abp.WeChat.Work.Authorize; public interface IWeChatWorkUserFinder { Task GetUserInfoAsync( - string agentId, string code, CancellationToken cancellationToken = default); Task GetUserDetailAsync( - string agentId, string userTicket, CancellationToken cancellationToken = default); } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeGenerator.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeGenerator.cs index 820bc85e1..bf684ed89 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeGenerator.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeGenerator.cs @@ -27,15 +27,16 @@ public class WeChatWorkAuthorizeGenerator : IWeChatWorkAuthorizeGenerator, ISing } public async virtual Task GenerateOAuth2AuthorizeAsync( - string agentid, string redirectUri, string state, string responseType = "code", string scope = "snsapi_base") { var corpId = await SettingProvider.GetOrNullAsync(WeChatWorkSettingNames.Connection.CorpId); + var agentId = await SettingProvider.GetOrNullAsync(WeChatWorkSettingNames.Connection.AgentId); Check.NotNullOrEmpty(corpId, nameof(corpId)); + Check.NotNullOrEmpty(agentId, nameof(agentId)); var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.OAuthClient); @@ -49,20 +50,23 @@ public class WeChatWorkAuthorizeGenerator : IWeChatWorkAuthorizeGenerator, ISing .AppendFormat("&response_type={0}", responseType) .AppendFormat("&scope={0}", scope) .AppendFormat("&state={0}", state) - .AppendFormat("&agentid={0}", agentid) + .AppendFormat("&agentid={0}", agentId) .Append("#wechat_redirect"); return generatedUrlBuilder.ToString(); } - public virtual Task GenerateOAuth2LoginAsync( + public async virtual Task GenerateOAuth2LoginAsync( string appid, string redirectUri, string state, string loginType = "ServiceApp", - string agentid = "", string lang = "zh") { + var agentId = await SettingProvider.GetOrNullAsync(WeChatWorkSettingNames.Connection.AgentId); + + Check.NotNullOrEmpty(agentId, nameof(agentId)); + var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.LoginClient); var generatedUrlBuilder = new StringBuilder(); @@ -72,11 +76,11 @@ public class WeChatWorkAuthorizeGenerator : IWeChatWorkAuthorizeGenerator, ISing .Append("wwlogin/sso/login") .AppendFormat("?login_type={0}", loginType) .AppendFormat("&appid={0}", appid) - .AppendFormat("&agentid={0}", agentid) + .AppendFormat("&agentid={0}", agentId) .AppendFormat("&redirect_uri={0}", HttpUtility.UrlEncode(redirectUri)) .AppendFormat("&state={0}", state) .AppendFormat("&lang={0}", lang); - return Task.FromResult(generatedUrlBuilder.ToString()); + return generatedUrlBuilder.ToString(); } } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkUserFinder.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkUserFinder.cs index d1c1d016c..cd0eafd78 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkUserFinder.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkUserFinder.cs @@ -26,11 +26,10 @@ public class WeChatWorkUserFinder : IWeChatWorkUserFinder, ISingletonDependency } public async virtual Task GetUserInfoAsync( - string agentId, string code, CancellationToken cancellationToken = default) { - var token = await WeChatWorkTokenProvider.GetTokenAsync(agentId, cancellationToken); + var token = await WeChatWorkTokenProvider.GetTokenAsync(cancellationToken); var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient); using var response = await client.GetUserInfoAsync(token.AccessToken, code, cancellationToken); @@ -40,11 +39,10 @@ public class WeChatWorkUserFinder : IWeChatWorkUserFinder, ISingletonDependency } public async virtual Task GetUserDetailAsync( - string agentId, string userTicket, CancellationToken cancellationToken = default) { - var token = await WeChatWorkTokenProvider.GetTokenAsync(agentId, cancellationToken); + var token = await WeChatWorkTokenProvider.GetTokenAsync(cancellationToken); var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient); var request = new WeChatWorkUserDetailRequest(userTicket); diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/WeChatWorkAppChatManager.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/WeChatWorkAppChatManager.cs index 5830aa134..8e970f284 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/WeChatWorkAppChatManager.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/WeChatWorkAppChatManager.cs @@ -28,7 +28,7 @@ public class WeChatWorkAppChatManager : IWeChatWorkAppChatManager, ISingletonDep WeChatWorkAppChatCreateRequest request, CancellationToken cancellationToken = default) { - var token = await WeChatWorkTokenProvider.GetTokenAsync(request.AgentId, cancellationToken); + var token = await WeChatWorkTokenProvider.GetTokenAsync(cancellationToken); var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient); using var response = await client.CreateAppChatAsync(token.AccessToken, request, cancellationToken); @@ -40,7 +40,7 @@ public class WeChatWorkAppChatManager : IWeChatWorkAppChatManager, ISingletonDep string chatId, CancellationToken cancellationToken = default) { - var token = await WeChatWorkTokenProvider.GetTokenAsync(agentId, cancellationToken); + var token = await WeChatWorkTokenProvider.GetTokenAsync(cancellationToken); var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient); using var response = await client.GetAppChatAsync(token.AccessToken, agentId, cancellationToken); @@ -51,7 +51,7 @@ public class WeChatWorkAppChatManager : IWeChatWorkAppChatManager, ISingletonDep WeChatWorkAppChatUpdateRequest request, CancellationToken cancellationToken = default) { - var token = await WeChatWorkTokenProvider.GetTokenAsync(request.AgentId, cancellationToken); + var token = await WeChatWorkTokenProvider.GetTokenAsync(cancellationToken); var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient); using var response = await client.UpdateAppChatAsync(token.AccessToken, request, cancellationToken); diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/en.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/en.json index 2bf6fc5dd..e6aa37ae7 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/en.json +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/en.json @@ -22,8 +22,16 @@ "Description:WeChatWork": "企业微信应用集成", "DisplayName:Connection": "连接参数", "Description:Connection": "企业微信连接参数", - "DisplayName:WeChatWork.Connection.CorpId": "Corp Id", - "Description:WeChatWork.Connection.CorpId": "Each enterprise has a unique corpid, to obtain this information, you can view \"Enterprise ID\" under \"My Enterprise\" - \"Enterprise Information\" in the management background (requires administrator permissions).", + "DisplayName:WeChatWork.Connection.CorpId": "企业Id", + "Description:WeChatWork.Connection.CorpId": "每个企业都拥有唯一的corpid,获取此信息可在管理后台“我的企业”-“企业信息”下查看“企业ID”(需要有管理员权限)", + "DisplayName:WeChatWork.Connection.AgentId": "应用Id", + "Description:WeChatWork.Connection.AgentId": "每个应用都有唯一的agentid。在管理后台->“应用管理”->“应用”,点进某个应用,即可看到agentid", + "DisplayName:WeChatWork.Connection.Secret": "访问密钥", + "Description:WeChatWork.Connection.Secret": "secret是企业应用里面用于保障数据安全的“钥匙”,每一个应用都有一个独立的访问密钥,为了保证数据的安全,secret务必不能泄漏,在管理后台->“应用管理”->“应用”->“自建”,点进某个应用,即可看到", + "DisplayName:WeChatWork.Connection.Token": "Token", + "Description:WeChatWork.Connection.Token": "用于计算签名,详见: https://developer.work.weixin.qq.com/document/path/90930", + "DisplayName:WeChatWork.Connection.EncodingAESKey": "EncodingAESKey", + "Description:WeChatWork.Connection.EncodingAESKey": "用于消息加密,详见: https://developer.work.weixin.qq.com/document/path/90930", "DisplayName:WeChatWork.EnabledQuickLogin": "Enabled Quick Login", "Description:WeChatWork.EnabledQuickLogin": "Users can log in directly by scanning the code obtained when they are not registered.", "WeChatWork:100400": "处理企业微信服务器消息失败,请检查应用签名配置!", diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/zh-Hans.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/zh-Hans.json index 50f6208e8..e9dff106a 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/zh-Hans.json +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/zh-Hans.json @@ -24,6 +24,14 @@ "Description:Connection": "企业微信连接参数", "DisplayName:WeChatWork.Connection.CorpId": "企业Id", "Description:WeChatWork.Connection.CorpId": "每个企业都拥有唯一的corpid,获取此信息可在管理后台“我的企业”-“企业信息”下查看“企业ID”(需要有管理员权限)", + "DisplayName:WeChatWork.Connection.AgentId": "应用Id", + "Description:WeChatWork.Connection.AgentId": "每个应用都有唯一的agentid。在管理后台->“应用管理”->“应用”,点进某个应用,即可看到agentid", + "DisplayName:WeChatWork.Connection.Secret": "访问密钥", + "Description:WeChatWork.Connection.Secret": "secret是企业应用里面用于保障数据安全的“钥匙”,每一个应用都有一个独立的访问密钥,为了保证数据的安全,secret务必不能泄漏,在管理后台->“应用管理”->“应用”->“自建”,点进某个应用,即可看到", + "DisplayName:WeChatWork.Connection.Token": "Token", + "Description:WeChatWork.Connection.Token": "用于计算签名,详见: https://developer.work.weixin.qq.com/document/path/90930", + "DisplayName:WeChatWork.Connection.EncodingAESKey": "EncodingAESKey", + "Description:WeChatWork.Connection.EncodingAESKey": "用于消息加密,详见: https://developer.work.weixin.qq.com/document/path/90930", "DisplayName:WeChatWork.EnabledQuickLogin": "启用快捷登录", "Description:WeChatWork.EnabledQuickLogin": "用户可在未注册时通过扫码得到的code直接登录", "WeChatWork:100400": "处理企业微信服务器消息失败,请检查应用签名配置!", diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/IWeChatWorkMediaProvider.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/IWeChatWorkMediaProvider.cs index 8770d3d1d..bd14b3779 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/IWeChatWorkMediaProvider.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/IWeChatWorkMediaProvider.cs @@ -18,13 +18,11 @@ public interface IWeChatWorkMediaProvider /// /// API: /// - /// 应用标识 /// 媒体文件类型 /// 待上传文件 /// /// Task UploadAsync( - string agentId, string type, IRemoteStreamContent media, CancellationToken cancellationToken = default); @@ -34,13 +32,11 @@ public interface IWeChatWorkMediaProvider /// /// API: /// - /// 应用标识 /// 媒体文件id /// /// /// Task GetAsync( - string agentId, string mediaId, CancellationToken cancellationToken = default); /// @@ -49,12 +45,10 @@ public interface IWeChatWorkMediaProvider /// /// API: /// - /// 应用标识 /// 待上传图片 /// /// Task UploadImageAsync( - string agentId, IRemoteStreamContent image, CancellationToken cancellationToken = default); } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/WeChatWorkMediaProvider.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/WeChatWorkMediaProvider.cs index 7b9b3587c..6a01a9d4f 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/WeChatWorkMediaProvider.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/WeChatWorkMediaProvider.cs @@ -23,11 +23,10 @@ public class WeChatWorkMediaProvider : IWeChatWorkMediaProvider, ISingletonDepen } public async virtual Task GetAsync( - string agentId, string mediaId, CancellationToken cancellationToken = default) { - var token = await WeChatWorkTokenProvider.GetTokenAsync(agentId, cancellationToken); + var token = await WeChatWorkTokenProvider.GetTokenAsync(cancellationToken); var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient); using var response = await client.GetMediaAsync( @@ -75,12 +74,11 @@ public class WeChatWorkMediaProvider : IWeChatWorkMediaProvider, ISingletonDepen } public async virtual Task UploadAsync( - string agentId, string type, IRemoteStreamContent media, CancellationToken cancellationToken = default) { - var token = await WeChatWorkTokenProvider.GetTokenAsync(agentId, cancellationToken); + var token = await WeChatWorkTokenProvider.GetTokenAsync(cancellationToken); var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient); var request = new WeChatWorkMediaRequest( @@ -95,11 +93,10 @@ public class WeChatWorkMediaProvider : IWeChatWorkMediaProvider, ISingletonDepen } public async virtual Task UploadImageAsync( - string agentId, IRemoteStreamContent image, CancellationToken cancellationToken = default) { - var token = await WeChatWorkTokenProvider.GetTokenAsync(agentId, cancellationToken); + var token = await WeChatWorkTokenProvider.GetTokenAsync(cancellationToken); var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient); var request = new WeChatWorkMediaRequest( token.AccessToken, diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/IWeChatWorkMessageManager.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/IWeChatWorkMessageManager.cs index e85edb5e6..dada5f1ea 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/IWeChatWorkMessageManager.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/IWeChatWorkMessageManager.cs @@ -13,10 +13,9 @@ public interface IWeChatWorkMessageManager /// /// 参考:https://developer.work.weixin.qq.com/document/path/94867 /// - /// 应用标识 /// 消息ID。从应用发送消息接口 处获得。 /// /// - Task ReCallMessageAsync(string agentId, string messageId, CancellationToken cancellationToken = default); + Task ReCallMessageAsync( string messageId, CancellationToken cancellationToken = default); } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageManager.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageManager.cs index 69ccb34da..9e2a420fc 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageManager.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageManager.cs @@ -26,9 +26,9 @@ public class WeChatWorkMessageManager : IWeChatWorkMessageManager, ISingletonDep Logger = NullLogger.Instance; } - public async virtual Task ReCallMessageAsync(string agentId, string messageId, CancellationToken cancellationToken = default) + public async virtual Task ReCallMessageAsync(string messageId, CancellationToken cancellationToken = default) { - var token = await WeChatWorkTokenProvider.GetTokenAsync(agentId, cancellationToken); + var token = await WeChatWorkTokenProvider.GetTokenAsync(cancellationToken); var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient); var request = new WeChatWorkMessageReCallRequest( diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageSender.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageSender.cs index b9f80ba9c..af0c56981 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageSender.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageSender.cs @@ -38,7 +38,7 @@ public class WeChatWorkMessageSender : IWeChatWorkMessageSender, ISingletonDepen LimitPolicy.Days)] public async virtual Task SendAsync(WeChatWorkMessage message, CancellationToken cancellationToken = default) { - var token = await WeChatWorkTokenProvider.GetTokenAsync(message.AgentId, cancellationToken); + var token = await WeChatWorkTokenProvider.GetTokenAsync(cancellationToken); var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient); var request = new WeChatWorkMessageRequest( @@ -64,7 +64,7 @@ public class WeChatWorkMessageSender : IWeChatWorkMessageSender, ISingletonDepen LimitPolicy.Minute)] public async virtual Task SendAsync(WeChatWorkAppChatMessage message, CancellationToken cancellationToken = default) { - var token = await WeChatWorkTokenProvider.GetTokenAsync(message.AgentId, cancellationToken); + var token = await WeChatWorkTokenProvider.GetTokenAsync(cancellationToken); var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient); var request = new WeChatWorkMessageRequest( diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/NumberToStringConverter.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/NumberToStringConverter.cs new file mode 100644 index 000000000..dcba8ef12 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/NumberToStringConverter.cs @@ -0,0 +1,26 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work; + +internal class NumberToStringConverter : JsonConverter +{ + public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Number) + { + return reader.GetInt32().ToString(); + } + if (reader.TokenType == JsonTokenType.String) + { + return reader.GetString(); + } + throw new JsonException("Unexpected token type"); + } + + public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) + { + writer.WriteStringValue(value); + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Claims/AbpWeChatWorkClaimTypes.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Claims/AbpWeChatWorkClaimTypes.cs index ec550581b..0dbcc3538 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Claims/AbpWeChatWorkClaimTypes.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Claims/AbpWeChatWorkClaimTypes.cs @@ -2,7 +2,19 @@ public static class AbpWeChatWorkClaimTypes { /// - /// 用户的唯一标识 + /// 唯一标识 /// - public static string UserId { get; set; } = "wecom-uid"; // 可变更 + public static string UserId { get; set; } = "userid"; + /// + /// 二维码名片 + /// + public static string QrCode { get; set; } = "qr_code"; + /// + /// 企业邮箱 + /// + public static string BizMail { get; set; } = "biz_mail"; + /// + /// 地址 + /// + public static string Address { get; set; } = "address"; } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoConfiguration.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoConfiguration.cs deleted file mode 100644 index 8b0f90a4d..000000000 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoConfiguration.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; - -namespace LINGYUN.Abp.WeChat.Work.Security; -/// -/// 企业微信加解密配置 -/// -public class WeChatWorkCryptoConfiguration : Dictionary -{ - /// - /// 用于生成签名的Token - /// - public string Token { - get => this.GetOrDefault(nameof(Token)); - set => this[nameof(Token)] = value; - } - - /// - /// 用于消息加密的密钥 - /// - public string EncodingAESKey { - get => this.GetOrDefault(nameof(EncodingAESKey)); - set => this[nameof(EncodingAESKey)] = value; - } - - public WeChatWorkCryptoConfiguration() - { - - } - - public WeChatWorkCryptoConfiguration(string token, string encodingAESKey) - { - this[nameof(Token)] = token; - this[nameof(EncodingAESKey)] = encodingAESKey; - } -} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoConfigurationDictionary.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoConfigurationDictionary.cs deleted file mode 100644 index 5bc33ad5b..000000000 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoConfigurationDictionary.cs +++ /dev/null @@ -1,12 +0,0 @@ -using JetBrains.Annotations; -using System.Collections.Generic; - -namespace LINGYUN.Abp.WeChat.Work.Security; -public class WeChatWorkCryptoConfigurationDictionary : Dictionary -{ - [CanBeNull] - public WeChatWorkCryptoConfiguration GetCryptoConfigurationOrNull(string feture) - { - return this.GetOrDefault(feture); - } -} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Settings/WeChatWorkSettingDefinitionProvider.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Settings/WeChatWorkSettingDefinitionProvider.cs index 489653086..33181b4e6 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Settings/WeChatWorkSettingDefinitionProvider.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Settings/WeChatWorkSettingDefinitionProvider.cs @@ -40,6 +40,47 @@ public class WeChatWorkSettingDefinitionProvider : SettingDefinitionProvider ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, TenantSettingValueProvider.ProviderName), + + new SettingDefinition( + WeChatWorkSettingNames.Connection.AgentId, + displayName: L("DisplayName:WeChatWork.Connection.AgentId"), + description: L("Description:WeChatWork.Connection.AgentId"), + isEncrypted: true) + .WithProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName), + new SettingDefinition( + WeChatWorkSettingNames.Connection.Secret, + displayName: L("DisplayName:WeChatWork.Connection.Secret"), + description: L("Description:WeChatWork.Connection.Secret"), + isEncrypted: true) + .WithProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName), + new SettingDefinition( + WeChatWorkSettingNames.Connection.Token, + displayName: L("DisplayName:WeChatWork.Connection.Token"), + description: L("Description:WeChatWork.Connection.Token"), + isEncrypted: true) + .WithProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName), + new SettingDefinition( + WeChatWorkSettingNames.Connection.EncodingAESKey, + displayName: L("DisplayName:WeChatWork.Connection.EncodingAESKey"), + description: L("Description:WeChatWork.Connection.EncodingAESKey"), + isEncrypted: true) + .WithProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName), }; } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Settings/WeChatWorkSettingNames.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Settings/WeChatWorkSettingNames.cs index d5f75f798..82ce8e4eb 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Settings/WeChatWorkSettingNames.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Settings/WeChatWorkSettingNames.cs @@ -12,7 +12,25 @@ public static class WeChatWorkSettingNames public static class Connection { public const string Prefix = WeChatWorkSettingNames.Prefix + ".Connection"; - + /// + /// 企业Id + /// public static string CorpId = Prefix + ".CorpId"; + /// + /// 应用Id + /// + public static string AgentId = Prefix + ".AgentId"; + /// + /// 应用密钥 + /// + public static string Secret = Prefix + ".Secret"; + /// + /// Token + /// + public static string Token = Prefix + ".Token"; + /// + /// EncodingAESKey + /// + public static string EncodingAESKey = Prefix + ".EncodingAESKey"; } } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/IWeChatWorkTokenProvider.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/IWeChatWorkTokenProvider.cs index 6952b22cf..09e0c3b15 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/IWeChatWorkTokenProvider.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/IWeChatWorkTokenProvider.cs @@ -17,7 +17,7 @@ public interface IWeChatWorkTokenProvider /// 应用标识 /// /// - Task GetTokenAsync(string agentId, CancellationToken cancellationToken = default); + Task GetTokenAsync(CancellationToken cancellationToken = default); /// /// 获取应用Token /// @@ -26,7 +26,8 @@ public interface IWeChatWorkTokenProvider /// /// 企业标识 /// 应用标识 + /// 应用密钥 /// /// - Task GetTokenAsync(string corpId, string agentId, CancellationToken cancellationToken = default); + Task GetTokenAsync(string corpId, string agentId, string secret, CancellationToken cancellationToken = default); } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/Models/WeChatWorkTokenResponse.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/Models/WeChatWorkTokenResponse.cs index 0abc409ff..3f4be9126 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/Models/WeChatWorkTokenResponse.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/Models/WeChatWorkTokenResponse.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace LINGYUN.Abp.WeChat.Work.Token.Models; @@ -11,11 +12,14 @@ public class WeChatWorkTokenResponse : WeChatWorkResponse /// 访问令牌 /// [JsonProperty("access_token")] + [JsonPropertyName("access_token")] public string AccessToken { get; set; } /// /// 过期时间,单位(s) /// [JsonProperty("expires_in")] + [JsonPropertyName("expires_in")] + [System.Text.Json.Serialization.JsonConverter(typeof(NumberToStringConverter))] public int ExpiresIn { get; set; } public WeChatWorkToken ToWeChatWorkToken() diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/WeChatWorkTokenProvider.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/WeChatWorkTokenProvider.cs index 709cf19d9..93f47ad4f 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/WeChatWorkTokenProvider.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/WeChatWorkTokenProvider.cs @@ -1,10 +1,8 @@ using LINGYUN.Abp.WeChat.Work.Settings; using LINGYUN.Abp.WeChat.Work.Token.Models; using Microsoft.Extensions.Caching.Distributed; -using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; using System; using System.Net.Http; using System.Threading; @@ -21,38 +19,35 @@ public class WeChatWorkTokenProvider : IWeChatWorkTokenProvider, ISingletonDepen public ILogger Logger { get; set; } protected ISettingProvider SettingProvider { get; } protected IHttpClientFactory HttpClientFactory { get; } - protected IMemoryCache MemoryCache { get; } protected IDistributedCache WeChatWorkTokenCache { get; } - protected WeChatWorkOptions WeChatWorkOptions { get; } public WeChatWorkTokenProvider( ISettingProvider settingProvider, IHttpClientFactory httpClientFactory, - IMemoryCache memoryCache, - IDistributedCache cache, - IOptionsMonitor weChatWorkOptions) + IDistributedCache cache) { HttpClientFactory = httpClientFactory; SettingProvider = settingProvider; - MemoryCache = memoryCache; WeChatWorkTokenCache = cache; - WeChatWorkOptions = weChatWorkOptions.CurrentValue; Logger = NullLogger.Instance; } - public async virtual Task GetTokenAsync(string agentId, CancellationToken cancellationToken = default) + public async virtual Task GetTokenAsync(CancellationToken cancellationToken = default) { var corpId = await SettingProvider.GetOrNullAsync(WeChatWorkSettingNames.Connection.CorpId); + var agentId = await SettingProvider.GetOrNullAsync(WeChatWorkSettingNames.Connection.AgentId); + var secret = await SettingProvider.GetOrNullAsync(WeChatWorkSettingNames.Connection.Secret); - return await GetTokenAsync(corpId, agentId, cancellationToken); + return await GetTokenAsync(corpId, agentId, secret, cancellationToken); } public async virtual Task GetTokenAsync( string corpId, string agentId, + string secret, CancellationToken cancellationToken = default) { - return (await GetCacheItemAsync("WeChatWorkToken", corpId, agentId, cancellationToken)).Token; + return (await GetCacheItemAsync("WeChatWorkToken", corpId, agentId, secret, cancellationToken)).Token; } /// /// 获取缓存中的Token配置 @@ -60,55 +55,23 @@ public class WeChatWorkTokenProvider : IWeChatWorkTokenProvider, ISingletonDepen /// /// /// + /// /// /// protected async virtual Task GetCacheItemAsync( string provider, string corpId, - string agentId, + string agentId, + string secret, CancellationToken cancellationToken = default) { Check.NotNullOrEmpty(corpId, nameof(corpId)); Check.NotNullOrEmpty(agentId, nameof(agentId)); + Check.NotNullOrEmpty(secret, nameof(secret)); var cacheKey = WeChatWorkTokenCacheItem.CalculateCacheKey(provider, corpId, agentId); - return await GetOrRefreshMemoryCacheAsync(cacheKey, provider, corpId, agentId); - } - /// - /// 获取或刷新内存缓存中的Token配置 - /// - /// - /// - /// - /// - /// - /// - protected async virtual Task GetOrRefreshMemoryCacheAsync( - string cacheKey, - string provider, - string corpId, - string agentId, - CancellationToken cancellationToken = default) - { - if (MemoryCache.TryGetValue(cacheKey, out var cacheItem)) - { - return cacheItem; - } - - cacheItem = await GetOrRefreshDistributedCacheAsync(cacheKey, provider, corpId, agentId); - var cacheOptions = new MemoryCacheEntryOptions - { - AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(cacheItem.Token.ExpiresIn - 120), - }; - cacheOptions.RegisterPostEvictionCallback(async (key, value, reason, state) => - { - if (reason == EvictionReason.Expired) - { - await GetOrRefreshDistributedCacheAsync(cacheKey, provider, corpId, agentId); - } - }); - return MemoryCache.Set(cacheKey, cacheItem, cacheOptions); + return await GetCacheItemAsync(cacheKey, provider, corpId, agentId, secret); } /// /// 获取或刷新分布式缓存中的Token配置 @@ -117,13 +80,15 @@ public class WeChatWorkTokenProvider : IWeChatWorkTokenProvider, ISingletonDepen /// /// /// + /// /// /// - protected async virtual Task GetOrRefreshDistributedCacheAsync( + protected async virtual Task GetCacheItemAsync( string cacheKey, string provider, string corpId, string agentId, + string secret, CancellationToken cancellationToken = default) { var cacheItem = await WeChatWorkTokenCache.GetAsync(cacheKey, token: cancellationToken); @@ -137,12 +102,11 @@ public class WeChatWorkTokenProvider : IWeChatWorkTokenProvider, ISingletonDepen Logger.LogDebug($"Not found WeChatWorkToken in the cache, getting from the httpClient: {cacheKey}"); var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient); - var applicationConfiguration = WeChatWorkOptions.Applications.GetConfiguration(agentId); var request = new WeChatWorkTokenRequest { CorpId = corpId, - CorpSecret = applicationConfiguration.Secret, + CorpSecret = secret, }; using var response = await client.GetTokenAsync(request, cancellationToken); diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkApplicationConfiguration.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkApplicationConfiguration.cs deleted file mode 100644 index 9e2a73106..000000000 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkApplicationConfiguration.cs +++ /dev/null @@ -1,43 +0,0 @@ -using JetBrains.Annotations; -using LINGYUN.Abp.WeChat.Work.Security; - -namespace LINGYUN.Abp.WeChat.Work; -/// -/// 企业微信应用配置 -/// -public class WeChatWorkApplicationConfiguration -{ - /// - /// 应用的标识 - /// - public string AgentId { get; set; } - /// - /// 应用的凭证密钥 - /// - public string Secret { get; set; } - /// - /// 应用加密配置 - /// - public WeChatWorkCryptoConfigurationDictionary CryptoKeys { get; set; } - - public WeChatWorkApplicationConfiguration() - { - CryptoKeys = new WeChatWorkCryptoConfigurationDictionary(); - } - - public WeChatWorkApplicationConfiguration(string agentId, string secret) - { - AgentId = agentId; - Secret = secret; - CryptoKeys = new WeChatWorkCryptoConfigurationDictionary(); - } - - [NotNull] - public WeChatWorkCryptoConfiguration GetCryptoConfiguration(string feture) - { - return CryptoKeys.GetCryptoConfigurationOrNull(feture) - ?? throw new AbpWeChatWorkException("WeChatWork:101404", $"WeChat Work crypto was not found configuration with feture '{feture}' .") - .WithData("AgentId", AgentId) - .WithData("Feture", feture); - } -} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkApplicationConfigurationDictionary.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkApplicationConfigurationDictionary.cs deleted file mode 100644 index 5847d6b00..000000000 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkApplicationConfigurationDictionary.cs +++ /dev/null @@ -1,14 +0,0 @@ -using JetBrains.Annotations; -using System.Collections.Generic; - -namespace LINGYUN.Abp.WeChat.Work; -public class WeChatWorkApplicationConfigurationDictionary : Dictionary -{ - [NotNull] - public WeChatWorkApplicationConfiguration GetConfiguration(string agentId) - { - return this.GetOrDefault(agentId) - ?? throw new AbpWeChatWorkException("WeChatWork:100404", $"WeChat Work application was not found configuration with agent '{agentId}' .") - .WithData("AgentId", agentId); - } -} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkOptions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkOptions.cs deleted file mode 100644 index 5355b6201..000000000 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkOptions.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace LINGYUN.Abp.WeChat.Work; - -public class WeChatWorkOptions -{ - public WeChatWorkApplicationConfigurationDictionary Applications { get; set; } - - public WeChatWorkOptions() - { - Applications = new WeChatWorkApplicationConfigurationDictionary(); - } -} diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/DataSeeder/ClientDataSeederContributor.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/DataSeeder/ClientDataSeederContributor.cs index d3cfdd062..f0293b42e 100644 --- a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/DataSeeder/ClientDataSeederContributor.cs +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/DataSeeder/ClientDataSeederContributor.cs @@ -1,19 +1,11 @@ -using LINGYUN.Abp.IdentityServer.IdentityResources; -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using OpenIddict.Abstractions; using System; -using System.Collections.Generic; using System.Globalization; -using System.Linq; using System.Threading.Tasks; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; -using Volo.Abp.Guids; -using Volo.Abp.IdentityServer.ApiResources; -using Volo.Abp.IdentityServer.ApiScopes; -using Volo.Abp.IdentityServer.Clients; -using Volo.Abp.IdentityServer.IdentityResources; using Volo.Abp.MultiTenancy; using Volo.Abp.PermissionManagement; @@ -24,13 +16,6 @@ public class ClientDataSeederContributor : IDataSeedContributor, ITransientDepen private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictScopeManager _scopeManager; - private readonly IClientRepository _clientRepository; - private readonly IApiResourceRepository _apiResourceRepository; - private readonly IApiScopeRepository _apiScopeRepository; - private readonly ICustomIdentityResourceDataSeeder _customIdentityResourceDataSeeder; - private readonly IIdentityResourceDataSeeder _identityResourceDataSeeder; - - private readonly IGuidGenerator _guidGenerator; private readonly IPermissionDataSeeder _permissionDataSeeder; private readonly IConfiguration _configuration; private readonly ICurrentTenant _currentTenant; @@ -38,24 +23,12 @@ public class ClientDataSeederContributor : IDataSeedContributor, ITransientDepen public ClientDataSeederContributor( IOpenIddictApplicationManager applicationManager, IOpenIddictScopeManager scopeManager, - IClientRepository clientRepository, - IApiResourceRepository apiResourceRepository, - IApiScopeRepository apiScopeRepository, - ICustomIdentityResourceDataSeeder customIdentityResourceDataSeeder, - IIdentityResourceDataSeeder identityResourceDataSeeder, - IGuidGenerator guidGenerator, IPermissionDataSeeder permissionDataSeeder, IConfiguration configuration, ICurrentTenant currentTenant) { _applicationManager = applicationManager; _scopeManager = scopeManager; - _clientRepository = clientRepository; - _apiResourceRepository = apiResourceRepository; - _apiScopeRepository = apiScopeRepository; - _customIdentityResourceDataSeeder = customIdentityResourceDataSeeder; - _identityResourceDataSeeder = identityResourceDataSeeder; - _guidGenerator = guidGenerator; _permissionDataSeeder = permissionDataSeeder; _configuration = configuration; _currentTenant = currentTenant; @@ -65,13 +38,7 @@ public class ClientDataSeederContributor : IDataSeedContributor, ITransientDepen { using (_currentTenant.Change(context.TenantId)) { - if (_configuration.GetValue("AuthServer:UseOpenIddict")) - { - await SeedOpenIddictAsync(); - return; - } - - await SeedIdentityServerAsync(); + await SeedOpenIddictAsync(); } } @@ -231,239 +198,4 @@ public class ClientDataSeederContributor : IDataSeedContributor, ITransientDepen } #endregion - - #region IdentityServer - - private async Task SeedIdentityServerAsync() - { - await _identityResourceDataSeeder.CreateStandardResourcesAsync(); - await _customIdentityResourceDataSeeder.CreateCustomResourcesAsync(); - await CreateApiResourcesAsync(); - await CreateApiScopesAsync(); - await CreateClientsAsync(); - } - - private async Task CreateApiScopesAsync() - { - await CreateApiScopeAsync("lingyun-abp-application"); - } - - private async Task CreateApiResourcesAsync() - { - var commonApiUserClaims = new[] - { - "email", - "email_verified", - "name", - "phone_number", - "phone_number_verified", - "role" - }; - - await CreateApiResourceAsync("lingyun-abp-application", commonApiUserClaims); - } - - private async Task CreateApiResourceAsync(string name, IEnumerable claims, IEnumerable secrets = null) - { - var apiResource = await _apiResourceRepository.FindByNameAsync(name); - if (apiResource == null) - { - apiResource = await _apiResourceRepository.InsertAsync( - new ApiResource( - _guidGenerator.Create(), - name, - name + " API" - ), - autoSave: true - ); - } - - foreach (var claim in claims) - { - if (apiResource.FindClaim(claim) == null) - { - apiResource.AddUserClaim(claim); - } - } - if (secrets != null) - { - foreach (var secret in secrets) - { - if (apiResource.FindSecret(secret) == null) - { - apiResource.AddSecret(secret); - } - } - } - - return await _apiResourceRepository.UpdateAsync(apiResource); - } - - private async Task CreateApiScopeAsync(string name) - { - var apiScope = await _apiScopeRepository.FindByNameAsync(name); - if (apiScope == null) - { - apiScope = await _apiScopeRepository.InsertAsync( - new ApiScope( - _guidGenerator.Create(), - name, - name + " API" - ), - autoSave: true - ); - } - - return apiScope; - } - - private async Task CreateClientsAsync() - { - - string commonSecret = IdentityServer4.Models.HashExtensions.Sha256("1q2w3e*"); - - var commonScopes = new[] - { - "email", - "openid", - "profile", - "role", - "phone", - "address", - "offline_access" // 加上刷新, - - }; - - var configurationSection = _configuration.GetSection("IdentityServer:Clients"); - - var vueClientId = configurationSection["VueAdmin:ClientId"]; - if (!vueClientId.IsNullOrWhiteSpace()) - { - var vueClientPermissions = new string[1] - { - "AbpIdentity.UserLookup" - }; - var vueClientRootUrl = configurationSection["VueAdmin:RootUrl"].EnsureEndsWith('/'); - await CreateClientAsync( - vueClientId, - commonScopes.Union(new[] { "lingyun-abp-application" }), - new[] { "password", "client_credentials", "implicit", "phone_verify", "wx-mp" }, - commonSecret, - redirectUri: $"{vueClientRootUrl}signin-oidc", - postLogoutRedirectUri: $"{vueClientRootUrl}signout-callback-oidc", - corsOrigins: configurationSection["CorsOrigins"], - permissions: vueClientPermissions - ); - } - - // InternalService 内部服务间通讯客户端,必要的话需要在前端指定它拥有所有权限,当前项目仅预置用户查询权限 - var internalServiceClientId = configurationSection["InternalService:ClientId"]; - if (!internalServiceClientId.IsNullOrWhiteSpace()) - { - var internalServicePermissions = new string[2] - { - "AbpIdentity.UserLookup","AbpIdentity.Users" - }; - await CreateClientAsync( - internalServiceClientId, - commonScopes.Union(new[] { "lingyun-abp-application" }), - new[] { "client_credentials" }, - commonSecret, - permissions: internalServicePermissions - ); - } - } - - private async Task CreateClientAsync( - string name, - IEnumerable scopes, - IEnumerable grantTypes, - string secret, - string redirectUri = null, - string postLogoutRedirectUri = null, - IEnumerable permissions = null, - string corsOrigins = null) - { - var client = await _clientRepository.FindByClientIdAsync(name); - if (client == null) - { - client = await _clientRepository.InsertAsync( - new Client( - _guidGenerator.Create(), - name - ) - { - ClientName = name, - ProtocolType = "oidc", - Description = name, - AlwaysIncludeUserClaimsInIdToken = true, - AllowOfflineAccess = true, - AbsoluteRefreshTokenLifetime = 10800, //3 hours - AccessTokenLifetime = 7200, //2 hours - AuthorizationCodeLifetime = 300, - IdentityTokenLifetime = 300, - RequireConsent = false - }, - autoSave: true - ); - } - - foreach (var scope in scopes) - { - if (client.FindScope(scope) == null) - { - client.AddScope(scope); - } - } - - foreach (var grantType in grantTypes) - { - if (client.FindGrantType(grantType) == null) - { - client.AddGrantType(grantType); - } - } - - if (client.FindSecret(secret) == null) - { - client.AddSecret(secret); - } - - if (redirectUri != null) - { - if (client.FindRedirectUri(redirectUri) == null) - { - client.AddRedirectUri(redirectUri); - } - } - - if (postLogoutRedirectUri != null) - { - if (client.FindPostLogoutRedirectUri(postLogoutRedirectUri) == null) - { - client.AddPostLogoutRedirectUri(postLogoutRedirectUri); - } - } - - if (corsOrigins != null) - { - var corsOriginsSplit = corsOrigins.Split(";"); - foreach (var corsOrigin in corsOriginsSplit) - { - if (client.FindCorsOrigin(corsOrigin) == null) - { - client.AddCorsOrigin(corsOrigin); - } - } - } - - if (permissions != null) - { - await _permissionDataSeeder.SeedAsync(ClientPermissionValueProvider.ProviderName, name, permissions); - } - - return await _clientRepository.UpdateAsync(client); - } - - #endregion } diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/LY.MicroService.Applications.Single.EntityFrameworkCore.csproj b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/LY.MicroService.Applications.Single.EntityFrameworkCore.csproj index a9216ee68..1a45aa139 100644 --- a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/LY.MicroService.Applications.Single.EntityFrameworkCore.csproj +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/LY.MicroService.Applications.Single.EntityFrameworkCore.csproj @@ -35,7 +35,6 @@ - diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsDbContext.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsDbContext.cs index e5c3f1afa..b0823dce9 100644 --- a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsDbContext.cs +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsDbContext.cs @@ -15,7 +15,6 @@ using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.FeatureManagement.EntityFrameworkCore; using Volo.Abp.Identity.EntityFrameworkCore; -using Volo.Abp.IdentityServer.EntityFrameworkCore; using Volo.Abp.OpenIddict.EntityFrameworkCore; using Volo.Abp.PermissionManagement.EntityFrameworkCore; using Volo.Abp.SettingManagement.EntityFrameworkCore; @@ -37,7 +36,6 @@ public class SingleMigrationsDbContext : AbpDbContext modelBuilder.ConfigureAuditLogging(); modelBuilder.ConfigureIdentity(); - modelBuilder.ConfigureIdentityServer(); modelBuilder.ConfigureOpenIddict(); modelBuilder.ConfigureSaas(); modelBuilder.ConfigureFeatureManagement(); diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsEntityFrameworkCoreModule.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsEntityFrameworkCoreModule.cs index 1c947b759..432e9da66 100644 --- a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsEntityFrameworkCoreModule.cs +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsEntityFrameworkCoreModule.cs @@ -2,7 +2,6 @@ using LINGYUN.Abp.AuditLogging.EntityFrameworkCore; using LINGYUN.Abp.Data.DbMigrator; using LINGYUN.Abp.Gdpr.EntityFrameworkCore; using LINGYUN.Abp.Identity.EntityFrameworkCore; -using LINGYUN.Abp.IdentityServer.EntityFrameworkCore; using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; using LINGYUN.Abp.MessageService.EntityFrameworkCore; using LINGYUN.Abp.Notifications.EntityFrameworkCore; @@ -32,7 +31,6 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore; typeof(PlatformEntityFrameworkCoreModule), typeof(AbpLocalizationManagementEntityFrameworkCoreModule), typeof(AbpIdentityEntityFrameworkCoreModule), - typeof(AbpIdentityServerEntityFrameworkCoreModule), typeof(AbpOpenIddictEntityFrameworkCoreModule), typeof(AbpTextTemplatingEntityFrameworkCoreModule), typeof(WebhooksManagementEntityFrameworkCoreModule), diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Areas/Account/Controllers/Models/QrCodeUserInfoResult.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Areas/Account/Controllers/Models/QrCodeUserInfoResult.cs index 8a9c4150b..48e0678ad 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Areas/Account/Controllers/Models/QrCodeUserInfoResult.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Areas/Account/Controllers/Models/QrCodeUserInfoResult.cs @@ -1,7 +1,10 @@ -namespace LINGYUN.Abp.Account.Web.Areas.Account.Controllers.Models; +using System; + +namespace LINGYUN.Abp.Account.Web.Areas.Account.Controllers.Models; public class QrCodeUserInfoResult : QrCodeInfoResult { + public Guid? TenantId { get; set; } public string UserId { get; set; } public string UserName { get; set; } public string Picture { get; set; } diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Areas/Account/Controllers/QrCodeLoginController.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Areas/Account/Controllers/QrCodeLoginController.cs index 0da0ec8b6..1e106fe38 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Areas/Account/Controllers/QrCodeLoginController.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Areas/Account/Controllers/QrCodeLoginController.cs @@ -58,6 +58,7 @@ public class QrCodeLoginController : AbpControllerBase Picture = qrCodeInfo.Picture, UserId = qrCodeInfo.UserId, UserName = qrCodeInfo.UserName, + TenantId = qrCodeInfo.TenantId }; } @@ -66,22 +67,26 @@ public class QrCodeLoginController : AbpControllerBase [Authorize] public async Task ScanCodeAsync(string key) { - var currentUser = await _userManager.GetByIdAsync(CurrentUser.GetId()); + using (CurrentTenant.Change(CurrentUser.TenantId)) + { + var currentUser = await _userManager.GetByIdAsync(CurrentUser.GetId()); - var userName = CurrentUser.FindClaim(AbpClaimTypes.Name)?.Value ?? currentUser.UserName; - var userId = await _userManager.GetUserIdAsync(currentUser); + var userName = CurrentUser.FindClaim(AbpClaimTypes.Name)?.Value ?? currentUser.UserName; + var userId = await _userManager.GetUserIdAsync(currentUser); - var qrCodeInfo = await _qrCodeLoginProvider.ScanCodeAsync(key, - new QrCodeScanParams(userId, userName, currentUser.TenantId)); + var qrCodeInfo = await _qrCodeLoginProvider.ScanCodeAsync(key, + new QrCodeScanParams(userId, userName, currentUser.TenantId)); - return new QrCodeUserInfoResult - { - Key = qrCodeInfo.Key, - Status = qrCodeInfo.Status, - Picture = qrCodeInfo.Picture, - UserId = qrCodeInfo.UserId, - UserName = qrCodeInfo.UserName - }; + return new QrCodeUserInfoResult + { + Key = qrCodeInfo.Key, + Status = qrCodeInfo.Status, + Picture = qrCodeInfo.Picture, + UserId = qrCodeInfo.UserId, + UserName = qrCodeInfo.UserName, + TenantId = qrCodeInfo.TenantId + }; + } } [HttpPost] @@ -89,15 +94,19 @@ public class QrCodeLoginController : AbpControllerBase [Authorize] public async Task ConfirmCodeAsync(string key) { - var qrCodeInfo = await _qrCodeLoginProvider.ConfirmCodeAsync(key); - - return new QrCodeUserInfoResult + using (CurrentTenant.Change(CurrentUser.TenantId)) { - Key = qrCodeInfo.Key, - Status = qrCodeInfo.Status, - Picture = qrCodeInfo.Picture, - UserId = qrCodeInfo.UserId, - UserName = qrCodeInfo.UserName - }; + var qrCodeInfo = await _qrCodeLoginProvider.ConfirmCodeAsync(key); + + return new QrCodeUserInfoResult + { + Key = qrCodeInfo.Key, + Status = qrCodeInfo.Status, + Picture = qrCodeInfo.Picture, + UserId = qrCodeInfo.UserId, + UserName = qrCodeInfo.UserName, + TenantId = qrCodeInfo.TenantId + }; + } } } diff --git a/aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN/Abp/Gdpr/Identity/AbpGdprIdentityUserAccountProvider.cs b/aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN/Abp/Gdpr/Identity/AbpGdprIdentityUserAccountProvider.cs index d8de4a61c..55f586f3e 100644 --- a/aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN/Abp/Gdpr/Identity/AbpGdprIdentityUserAccountProvider.cs +++ b/aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN/Abp/Gdpr/Identity/AbpGdprIdentityUserAccountProvider.cs @@ -20,6 +20,11 @@ public class AbpGdprIdentityUserAccountProvider : GdprUserAccountProviderBase var identityUser = await identityUserManager.GetByIdAsync(context.UserId); - (await identityUserManager.DeleteAsync(identityUser)).CheckErrors(); + // 默认管理员账号保留 + // TODO: 保留统一维护的地方? + if (identityUser.UserName == "admin") + { + (await identityUserManager.DeleteAsync(identityUser)).CheckErrors(); + } } } diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeCacheItem.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeCacheItem.cs index cd8714285..5d6e90b4a 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeCacheItem.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeCacheItem.cs @@ -30,6 +30,7 @@ public class QrCodeCacheItem UserId = UserId, UserName = UserName, Picture = Picture, + TenantId = TenantId, }; qrCodeInfo.SetToken(Token); qrCodeInfo.SetStatus(Status); diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeInfo.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeInfo.cs index 2040b46c6..80632573b 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeInfo.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeInfo.cs @@ -8,6 +8,7 @@ public class QrCodeInfo public string Token { get; private set; } public QrCodeStatus Status { get; private set; } public string UserId { get; set; } + public Guid? TenantId { get; set; } public string UserName { get; set; } public string Picture { get; set; } diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat.Work/LINGYUN/Abp/IdentityServer/WeChat/Work/WeChatWorkGrantValidator.cs b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat.Work/LINGYUN/Abp/IdentityServer/WeChat/Work/WeChatWorkGrantValidator.cs index b0c369914..e973db875 100644 --- a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat.Work/LINGYUN/Abp/IdentityServer/WeChat/Work/WeChatWorkGrantValidator.cs +++ b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat.Work/LINGYUN/Abp/IdentityServer/WeChat/Work/WeChatWorkGrantValidator.cs @@ -73,18 +73,17 @@ public class WeChatWorkGrantValidator : IExtensionGrantValidator return; } - var agentId = raw.Get(AbpWeChatWorkGlobalConsts.AgentId); var code = raw.Get(AbpWeChatWorkGlobalConsts.Code); - if (agentId.IsNullOrWhiteSpace() || code.IsNullOrWhiteSpace()) + if (code.IsNullOrWhiteSpace()) { - Logger.LogInformation("Invalid grant type: agentId or code not found"); + Logger.LogInformation("Invalid grant type: code not found"); context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, WeChatWorkLocalizer["InvalidGrant:AgentIdOrCodeNotFound"]); return; } try { - var userInfo = await WeChatWorkUserFinder.GetUserInfoAsync(agentId, code); + var userInfo = await WeChatWorkUserFinder.GetUserInfoAsync(code); var currentUser = await UserManager.FindByLoginAsync(AbpWeChatWorkGlobalConsts.ProviderName, userInfo.UserId); if (currentUser == null) diff --git a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.WeChat.Work/LINGYUN/Abp/OpenIddict/WeChat/Work/WeChatWorkTokenExtensionGrant.cs b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.WeChat.Work/LINGYUN/Abp/OpenIddict/WeChat/Work/WeChatWorkTokenExtensionGrant.cs index 0c9edc875..d68931405 100644 --- a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.WeChat.Work/LINGYUN/Abp/OpenIddict/WeChat/Work/WeChatWorkTokenExtensionGrant.cs +++ b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.WeChat.Work/LINGYUN/Abp/OpenIddict/WeChat/Work/WeChatWorkTokenExtensionGrant.cs @@ -44,11 +44,10 @@ public class WeChatWorkTokenExtensionGrant : ITokenExtensionGrant var logger = GetRequiredService>(context); var localizer = GetRequiredService>(context); - var agentId = context.Request.GetParameter(AbpWeChatWorkGlobalConsts.AgentId)?.ToString(); var code = context.Request.GetParameter(AbpWeChatWorkGlobalConsts.Code)?.ToString(); - if (agentId.IsNullOrWhiteSpace() || code.IsNullOrWhiteSpace()) + if (code.IsNullOrWhiteSpace()) { - logger.LogWarning("Invalid grant type: agentId or code not found"); + logger.LogWarning("Invalid grant type: code not found"); var properties = new AuthenticationProperties(new Dictionary { @@ -63,7 +62,7 @@ public class WeChatWorkTokenExtensionGrant : ITokenExtensionGrant try { - var userInfo = await userFinder.GetUserInfoAsync(agentId, code); + var userInfo = await userFinder.GetUserInfoAsync(code); var userManager = GetRequiredService(context); var currentUser = await userManager.FindByLoginAsync(AbpWeChatWorkGlobalConsts.ProviderName, userInfo.UserId); diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.WeChat.Work/LINGYUN/Abp/Notifications/WeChat/Work/WeChatWorkNotificationPublishProvider.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.WeChat.Work/LINGYUN/Abp/Notifications/WeChat/Work/WeChatWorkNotificationPublishProvider.cs index c51456dc1..ad009be86 100644 --- a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.WeChat.Work/LINGYUN/Abp/Notifications/WeChat/Work/WeChatWorkNotificationPublishProvider.cs +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.WeChat.Work/LINGYUN/Abp/Notifications/WeChat/Work/WeChatWorkNotificationPublishProvider.cs @@ -1,12 +1,10 @@ using LINGYUN.Abp.RealTime.Localization; -using LINGYUN.Abp.WeChat.Work; using LINGYUN.Abp.WeChat.Work.Authorize; using LINGYUN.Abp.WeChat.Work.Features; using LINGYUN.Abp.WeChat.Work.Messages; using LINGYUN.Abp.WeChat.Work.Messages.Models; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Linq; @@ -25,21 +23,18 @@ public class WeChatWorkNotificationPublishProvider : NotificationPublishProvider protected IWeChatWorkMessageSender WeChatWorkMessageSender { get; } protected IWeChatWorkInternalUserFinder WeChatWorkInternalUserFinder { get; } protected INotificationDefinitionManager NotificationDefinitionManager { get; } - protected WeChatWorkOptions WeChatWorkOptions { get; } public WeChatWorkNotificationPublishProvider( IFeatureChecker featureChecker, IStringLocalizerFactory localizerFactory, IWeChatWorkMessageSender weChatWorkMessageSender, IWeChatWorkInternalUserFinder weChatWorkInternalUserFinder, - INotificationDefinitionManager notificationDefinitionManager, - IOptionsMonitor weChatWorkOptions) + INotificationDefinitionManager notificationDefinitionManager) { FeatureChecker = featureChecker; LocalizerFactory = localizerFactory; WeChatWorkMessageSender = weChatWorkMessageSender; WeChatWorkInternalUserFinder = weChatWorkInternalUserFinder; NotificationDefinitionManager = notificationDefinitionManager; - WeChatWorkOptions = weChatWorkOptions.CurrentValue; } protected async override Task CanPublishAsync(NotificationInfo notification, CancellationToken cancellationToken = default) @@ -69,18 +64,6 @@ public class WeChatWorkNotificationPublishProvider : NotificationPublishProvider { return; } - // 发送到所有应用 - if (agentId.Contains("@all")) - { - foreach (var application in WeChatWorkOptions.Applications) - { - sendToAgentIds.Add(application.Key); - } - } - else - { - sendToAgentIds.AddRange(agentId.Split(';')); - } var title = ""; var message = ""; @@ -112,27 +95,24 @@ public class WeChatWorkNotificationPublishProvider : NotificationPublishProvider } } - foreach (var sendToAgentId in sendToAgentIds) - { - var findUserList = await WeChatWorkInternalUserFinder - .FindUserIdentifierListAsync(sendToAgentId, identifiers.Select(id => id.UserId)); - - if (!findUserList.Any()) - { - continue; - } + var findUserList = await WeChatWorkInternalUserFinder + .FindUserIdentifierListAsync(agentId, identifiers.Select(id => id.UserId)); - await PublishToAgentAsync( - sendToAgentId, - notification, - findUserList.JoinAsString("|"), - title, - message, - description, - toParty, - toTag, - cancellationToken); + if (!findUserList.Any()) + { + return; } + + await PublishToAgentAsync( + agentId, + notification, + findUserList.JoinAsString("|"), + title, + message, + description, + toParty, + toTag, + cancellationToken); } protected async virtual Task PublishToAgentAsync( diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/Authentication/AbpCookieAuthenticationHandler.cs b/aspnet-core/services/LY.MicroService.Applications.Single/Authentication/AbpCookieAuthenticationHandler.cs deleted file mode 100644 index 08a17beff..000000000 --- a/aspnet-core/services/LY.MicroService.Applications.Single/Authentication/AbpCookieAuthenticationHandler.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.Extensions.Options; -using Microsoft.Net.Http.Headers; -using System.Text.Encodings.Web; -using Volo.Abp.Http; - -namespace LY.MicroService.Applications.Single.Authentication; - -public class AbpCookieAuthenticationHandler : CookieAuthenticationHandler -{ - public AbpCookieAuthenticationHandler( - IOptionsMonitor options, - ILoggerFactory logger, - UrlEncoder encoder) : base(options, logger, encoder) - { - } - - public AbpCookieAuthenticationHandler( - IOptionsMonitor options, - ILoggerFactory logger, - UrlEncoder encoder, - ISystemClock clock) : base(options, logger, encoder, clock) - { - } - - protected const string XRequestFromHeader = "X-Request-From"; - protected const string DontRedirectRequestFromHeader = "vben"; - protected override Task InitializeEventsAsync() - { - var events = new CookieAuthenticationEvents - { - OnRedirectToLogin = ctx => - { - if (string.Equals(ctx.Request.Headers[XRequestFromHeader], DontRedirectRequestFromHeader, StringComparison.Ordinal)) - { - // ctx.Response.Headers.Location = ctx.RedirectUri; - ctx.Response.StatusCode = 401; - } - else - { - ctx.Response.Redirect(ctx.RedirectUri); - } - return Task.CompletedTask; - }, - OnRedirectToAccessDenied = ctx => - { - if (string.Equals(ctx.Request.Headers[XRequestFromHeader], DontRedirectRequestFromHeader, StringComparison.Ordinal)) - { - // ctx.Response.Headers.Location = ctx.RedirectUri; - ctx.Response.StatusCode = 401; - } - else - { - ctx.Response.Redirect(ctx.RedirectUri); - } - return Task.CompletedTask; - }, - OnRedirectToLogout = ctx => - { - if (string.Equals(ctx.Request.Headers[XRequestFromHeader], DontRedirectRequestFromHeader, StringComparison.Ordinal)) - { - // ctx.Response.Headers.Location = ctx.RedirectUri; - ctx.Response.StatusCode = 401; - } - else - { - ctx.Response.Redirect(ctx.RedirectUri); - } - return Task.CompletedTask; - }, - OnRedirectToReturnUrl = ctx => - { - if (string.Equals(ctx.Request.Headers[XRequestFromHeader], DontRedirectRequestFromHeader, StringComparison.Ordinal)) - { - // ctx.Response.Headers.Location = ctx.RedirectUri; - ctx.Response.StatusCode = 401; - } - else - { - ctx.Response.Redirect(ctx.RedirectUri); - } - return Task.CompletedTask; - } - }; - - Events = events; - - return Task.CompletedTask; - } -} diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/DataSeeder/DataSeederWorker.cs b/aspnet-core/services/LY.MicroService.Applications.Single/DataSeeder/DataSeederWorker.cs deleted file mode 100644 index d50c8cf41..000000000 --- a/aspnet-core/services/LY.MicroService.Applications.Single/DataSeeder/DataSeederWorker.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace LY.MicroService.Applications.Single.DataSeeder; - -public class DataSeederWorker : BackgroundService -{ - protected IDataSeeder DataSeeder { get; } - - public DataSeederWorker(IDataSeeder dataSeeder) - { - DataSeeder = dataSeeder; - } - - protected async override Task ExecuteAsync(CancellationToken stoppingToken) - { - await DataSeeder.SeedAsync(); - } -} diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/GlobalUsings.cs b/aspnet-core/services/LY.MicroService.Applications.Single/GlobalUsings.cs index 83d2db4ac..9db31b28f 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/GlobalUsings.cs +++ b/aspnet-core/services/LY.MicroService.Applications.Single/GlobalUsings.cs @@ -2,6 +2,7 @@ global using Elsa; global using Elsa.Options; global using LINGYUN.Abp.Account; +global using LINGYUN.Abp.Account.Web.OpenIddict; global using LINGYUN.Abp.Aliyun.Localization; global using LINGYUN.Abp.Aliyun.SettingManagement; global using LINGYUN.Abp.AspNetCore.HttpOverrides; @@ -42,6 +43,10 @@ global using LINGYUN.Abp.ExceptionHandling.Emailing; global using LINGYUN.Abp.Exporter.MiniExcel; global using LINGYUN.Abp.Features.LimitValidation; global using LINGYUN.Abp.Features.LimitValidation.Redis.Client; +global using LINGYUN.Abp.Gdpr; +global using LINGYUN.Abp.Gdpr.EntityFrameworkCore; +global using LINGYUN.Abp.Gdpr.Identity; +global using LINGYUN.Abp.Gdpr.Web; global using LINGYUN.Abp.Http.Client.Wrapper; global using LINGYUN.Abp.Idempotent; global using LINGYUN.Abp.Identity; @@ -52,7 +57,6 @@ global using LINGYUN.Abp.Identity.OrganizaztionUnits; global using LINGYUN.Abp.Identity.Session; global using LINGYUN.Abp.Identity.Session.AspNetCore; global using LINGYUN.Abp.Identity.WeChat; -global using LINGYUN.Abp.IdentityServer.IdentityResources; global using LINGYUN.Abp.IdGenerator; global using LINGYUN.Abp.IM.SignalR; global using LINGYUN.Abp.IP2Region; @@ -74,6 +78,7 @@ global using LINGYUN.Abp.OpenIddict.AspNetCore.Session; global using LINGYUN.Abp.OpenIddict.LinkUser; global using LINGYUN.Abp.OpenIddict.Permissions; global using LINGYUN.Abp.OpenIddict.Portal; +global using LINGYUN.Abp.OpenIddict.QrCode; global using LINGYUN.Abp.OpenIddict.Sms; global using LINGYUN.Abp.OpenIddict.WeChat; global using LINGYUN.Abp.OpenIddict.WeChat.Work; @@ -111,6 +116,7 @@ global using LINGYUN.Abp.WeChat.Official; global using LINGYUN.Abp.WeChat.Official.Handlers; global using LINGYUN.Abp.WeChat.SettingManagement; global using LINGYUN.Abp.WeChat.Work; +global using LINGYUN.Abp.WeChat.Work.AspNetCore; global using LINGYUN.Abp.WeChat.Work.Handlers; global using LINGYUN.Abp.Wrapper; global using LINGYUN.Platform; @@ -119,20 +125,16 @@ global using LINGYUN.Platform.HttpApi; global using LINGYUN.Platform.Localization; global using LINGYUN.Platform.Settings.VueVbenAdmin; global using LINGYUN.Platform.Theme.VueVbenAdmin; -global using LY.MicroService.Applications.Single.Authentication; global using LY.MicroService.Applications.Single.EntityFrameworkCore.MySql; -global using LY.MicroService.Applications.Single.IdentityResources; global using LY.MicroService.Applications.Single.Messages; global using Medallion.Threading; global using Medallion.Threading.Redis; -global using Microsoft.AspNetCore.Authentication.Cookies; global using Microsoft.AspNetCore.Authentication.JwtBearer; global using Microsoft.AspNetCore.Cors; global using Microsoft.AspNetCore.DataProtection; global using Microsoft.AspNetCore.Identity; global using Microsoft.AspNetCore.Server.Kestrel.Core; global using Microsoft.Extensions.Caching.StackExchangeRedis; -global using Microsoft.Extensions.DependencyInjection.Extensions; global using Microsoft.IdentityModel.Logging; global using Microsoft.OpenApi.Models; global using MiniExcelLibs.Attributes; @@ -166,8 +168,6 @@ global using Volo.Abp.Features; global using Volo.Abp.GlobalFeatures; global using Volo.Abp.Http.Client; global using Volo.Abp.Identity.Localization; -global using Volo.Abp.IdentityServer; -global using Volo.Abp.IdentityServer.Localization; global using Volo.Abp.Imaging; global using Volo.Abp.Json; global using Volo.Abp.Json.SystemTextJson; diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/IdentityResources/CustomIdentityResources.cs b/aspnet-core/services/LY.MicroService.Applications.Single/IdentityResources/CustomIdentityResources.cs deleted file mode 100644 index 7742fb2e1..000000000 --- a/aspnet-core/services/LY.MicroService.Applications.Single/IdentityResources/CustomIdentityResources.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace LY.MicroService.Applications.Single.IdentityResources; - -public class CustomIdentityResources -{ - public class AvatarUrl : IdentityServer4.Models.IdentityResource - { - public AvatarUrl() - { - Name = IdentityConsts.ClaimType.Avatar.Name; - DisplayName = IdentityConsts.ClaimType.Avatar.DisplayName; - Description = IdentityConsts.ClaimType.Avatar.Description; - Emphasize = true; - UserClaims = new string[] { IdentityConsts.ClaimType.Avatar.Name }; - } - } -} diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj index 3e8e3b41f..d70f703a7 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj +++ b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj @@ -37,7 +37,6 @@ - @@ -50,13 +49,11 @@ - - @@ -115,6 +112,7 @@ + @@ -160,7 +158,6 @@ - @@ -170,15 +167,6 @@ - - - - - - - - - diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs index 853fbf9e3..2c72d40d4 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs @@ -1,5 +1,7 @@ using LINGYUN.Abp.Identity.QrCode; -using LY.MicroService.Applications.Single.DataSeeder; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Extensions.DependencyInjection; +using OpenIddict.Validation.AspNetCore; using VoloAbpExceptionHandlingOptions = Volo.Abp.AspNetCore.ExceptionHandling.AbpExceptionHandlingOptions; namespace LY.MicroService.Applications.Single; @@ -97,38 +99,23 @@ public partial class MicroServiceApplicationsSingleModule { var certificate = new X509Certificate2(cerPath, cerConfig["Password"]); - if (configuration.GetValue("AuthServer:UseOpenIddict")) + PreConfigure(options => { - PreConfigure(options => - { - //https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html - options.AddDevelopmentEncryptionAndSigningCertificate = false; - }); - - PreConfigure(builder => - { - builder.AddSigningCertificate(certificate); - builder.AddEncryptionCertificate(certificate); - - builder.UseDataProtection(); + //https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); - // 禁用https - builder.UseAspNetCore() - .DisableTransportSecurityRequirement(); - }); - } - else + PreConfigure(builder => { - PreConfigure(options => - { - options.AddDeveloperSigningCredential = false; - }); + builder.AddSigningCertificate(certificate); + builder.AddEncryptionCertificate(certificate); - PreConfigure(builder => - { - builder.AddSigningCredential(certificate); - }); - } + builder.UseDataProtection(); + + // 禁用https + builder.UseAspNetCore() + .DisableTransportSecurityRequirement(); + }); } } else @@ -516,14 +503,6 @@ public partial class MicroServiceApplicationsSingleModule }); } - private void ConfigureDataSeeder() - { - Configure(options => - { - options.Resources.Add(new CustomIdentityResources.AvatarUrl()); - }); - } - private void ConfigureExceptionHandling() { // 自定义需要处理的异常 @@ -669,6 +648,8 @@ public partial class MicroServiceApplicationsSingleModule Configure(options => { options.IsDynamicClaimsEnabled = true; + + options.DynamicClaims.AddIfNotContains(AbpClaimTypes.Picture); }); Configure(options => { @@ -716,8 +697,7 @@ public partial class MicroServiceApplicationsSingleModule typeof(TencentCloudResource), typeof(WeChatResource), typeof(PlatformResource), - typeof(AbpOpenIddictResource), - typeof(AbpIdentityServerResource)); + typeof(AbpOpenIddictResource)); }); Configure(options => @@ -745,6 +725,8 @@ public partial class MicroServiceApplicationsSingleModule options.IsEnabled = true; // options.IsWrapUnauthorizedEnabled = true; options.IgnoreNamespaces.Add("Elsa"); + // 微信消息不能包装 + options.IgnoreNamespaces.Add("LINGYUN.Abp.WeChat"); }); } @@ -799,11 +781,6 @@ public partial class MicroServiceApplicationsSingleModule // 用于消息中心短信集中发送 services.Replace(ServiceLifetime.Transient); services.AddKeyedSingleton("DefaultSmsSender"); - - if (isDevelopment) - { - services.AddHostedService(); - } } private void ConfigureUrls(IConfiguration configuration) @@ -829,29 +806,57 @@ public partial class MicroServiceApplicationsSingleModule options.AutoValidate = false; }); + services.ForwardIdentityAuthenticationForBearer(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme); services.AddAuthentication() - .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => + .AddAbpJwtBearer(options => + { + configuration.GetSection("AuthServer").Bind(options); + + options.Events ??= new JwtBearerEvents(); + options.Events.OnMessageReceived = context => { - options.ExpireTimeSpan = TimeSpan.FromDays(365); - }) - .AddAbpJwtBearer(options => + var accessToken = context.Request.Query["access_token"]; + var path = context.HttpContext.Request.Path; + if (!string.IsNullOrEmpty(accessToken) && + (path.StartsWithSegments("/api/files"))) + { + context.Token = accessToken; + } + return Task.CompletedTask; + }; + }) + .AddWeChatWork(options => + { + options.SignInScheme = IdentityConstants.ExternalScheme; + }); + + services.ConfigureApplicationCookie(options => + { + options.Events.OnRedirectToLogin = (ctx) => + { + if (ctx.Request.Path.Value.StartsWith("/api") || + ctx.Request.Path.Value.StartsWith("/connect")) { - configuration.GetSection("AuthServer").Bind(options); + ctx.Response.Clear(); + ctx.Response.StatusCode = 401; + return Task.FromResult(0); + } - options.Events ??= new JwtBearerEvents(); - options.Events.OnMessageReceived = context => - { - var accessToken = context.Request.Query["access_token"]; - var path = context.HttpContext.Request.Path; - if (!string.IsNullOrEmpty(accessToken) && - (path.StartsWithSegments("/api/files"))) - { - context.Token = accessToken; - } - return Task.CompletedTask; - }; - }); + string authorization = ctx.Request.Headers.Authorization; + if (!authorization.IsNullOrWhiteSpace() && + authorization.StartsWith("Bearer ", StringComparison.InvariantCultureIgnoreCase)) + { + ctx.Response.Clear(); + ctx.Response.ContentType = "application/json"; + ctx.Response.StatusCode = StatusCodes.Status401Unauthorized; + return Task.CompletedTask; + } + + ctx.Response.Redirect(ctx.RedirectUri); + return Task.CompletedTask; + }; + }); if (!isDevelopment) { @@ -863,8 +868,6 @@ public partial class MicroServiceApplicationsSingleModule } services.AddSameSiteCookiePolicy(); - // 处理cookie中过时的ajax请求判断 - services.Replace(ServiceDescriptor.Scoped()); } private void ConfigureCors(IServiceCollection services, IConfiguration configuration) diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs index 6d2b1242f..747ee1943 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs +++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs @@ -1,10 +1,3 @@ -using LINGYUN.Abp.Account.Web.OpenIddict; -using LINGYUN.Abp.Gdpr; -using LINGYUN.Abp.Gdpr.EntityFrameworkCore; -using LINGYUN.Abp.Gdpr.Identity; -using LINGYUN.Abp.Gdpr.Web; -using LINGYUN.Abp.OpenIddict.QrCode; - namespace LY.MicroService.Applications.Single; [DependsOn( @@ -101,11 +94,6 @@ namespace LY.MicroService.Applications.Single; // 通知模块 实体框架 typeof(AbpNotificationsEntityFrameworkCoreModule), - //typeof(AbpIdentityServerSessionModule), - //typeof(AbpIdentityServerApplicationModule), - //typeof(AbpIdentityServerHttpApiModule), - //typeof(AbpIdentityServerEntityFrameworkCoreModule), - // OpenIddict扩展模块 自定义身份标识 typeof(LINGYUN.Abp.OpenIddict.AspNetCore.AbpOpenIddictAspNetCoreModule), // OpenIddict扩展模块 会话 @@ -339,6 +327,8 @@ namespace LY.MicroService.Applications.Single; typeof(AbpWeChatOfficialHandlersModule), // 微信模块 企业微信 事件处理 typeof(AbpWeChatWorkHandlersModule), + // 认证模块 企业微信 + typeof(AbpWeChatWorkAspNetCoreModule), // 微信模块 设置管理 typeof(AbpWeChatSettingManagementModule), @@ -401,7 +391,6 @@ public partial class MicroServiceApplicationsSingleModule : AbpModule ConfigureAuditing(); ConfigureIdempotent(); ConfigureMvcUiTheme(); - ConfigureDataSeeder(); ConfigureLocalization(); ConfigureKestrelServer(); ConfigureBackgroundTasks(); diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/Program.cs b/aspnet-core/services/LY.MicroService.Applications.Single/Program.cs index 62b31be1b..67689a4a4 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/Program.cs +++ b/aspnet-core/services/LY.MicroService.Applications.Single/Program.cs @@ -51,22 +51,24 @@ var app = builder.Build(); await app.InitializeApplicationAsync(); +app.UseMapRequestLocalization(); + +app.UseCookiePolicy(); app.UseForwardedHeaders(); +app.UseAbpSecurityHeaders(); if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // app.UseAbpExceptionHandling(); -app.UseCookiePolicy(); -app.UseMapRequestLocalization(); app.UseCorrelationId(); app.MapAbpStaticAssets(); app.UseRouting(); app.UseCors(); app.UseAuthentication(); +app.UseAbpOpenIddictValidation(); app.UseMultiTenancy(); app.UseUnitOfWork(); -app.UseAbpOpenIddictValidation(); app.UseAbpSession(); app.UseDynamicClaims(); app.UseAuthorization(); diff --git a/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs b/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs index de373b90b..93e15132d 100644 --- a/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs @@ -9,22 +9,24 @@ using LINGYUN.Abp.OpenIddict.WeChat; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; using LINGYUN.Abp.WeChat.Work; -using LY.MicroService.AuthServer.Authentication; using Medallion.Threading; using Medallion.Threading.Redis; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.Extensions.DependencyInjection; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Caching.StackExchangeRedis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.IdentityModel.Logging; +using OpenIddict.Validation.AspNetCore; using OpenTelemetry.Metrics; using OpenTelemetry.Resources; using OpenTelemetry.Trace; @@ -426,6 +428,8 @@ public partial class AuthServerModule } private void ConfigureSecurity(IServiceCollection services, IConfiguration configuration, bool isDevelopment = false) { + services.ForwardIdentityAuthenticationForBearer(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme); + services .AddAuthentication() .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => @@ -435,6 +439,10 @@ public partial class AuthServerModule .AddJwtBearer(options => { configuration.GetSection("AuthServer").Bind(options); + }) + .AddWeChatWork(options => + { + options.SignInScheme = IdentityConstants.ExternalScheme; }); if (!isDevelopment) @@ -446,8 +454,6 @@ public partial class AuthServerModule .PersistKeysToStackExchangeRedis(redis, "LINGYUN.Abp.Application:DataProtection:Protection-Keys"); } services.AddSameSiteCookiePolicy(); - // 处理cookie中过时的ajax请求判断 - services.Replace(ServiceDescriptor.Scoped()); } private void ConfigureMultiTenancy(IConfiguration configuration) { diff --git a/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.cs b/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.cs index 39e3158b7..dec785ecd 100644 --- a/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.cs +++ b/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.cs @@ -24,6 +24,7 @@ using LINGYUN.Abp.OpenIddict.WeChat.Work; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; using LINGYUN.Abp.Sms.Platform; +using LINGYUN.Abp.WeChat.Work.AspNetCore; using LY.MicroService.AuthServer.EntityFrameworkCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -60,6 +61,7 @@ namespace LY.MicroService.AuthServer; typeof(AbpOpenIddictLinkUserModule), typeof(AbpOpenIddictPortalModule), typeof(AbpOpenIddictWeChatWorkModule), + typeof(AbpWeChatWorkAspNetCoreModule), // 实现企业微信登录 typeof(AbpAuthenticationQQModule), typeof(AbpAuthenticationWeChatModule), typeof(AbpIdentityOrganizaztionUnitsModule), diff --git a/aspnet-core/services/LY.MicroService.AuthServer/Authentication/AbpCookieAuthenticationHandler.cs b/aspnet-core/services/LY.MicroService.AuthServer/Authentication/AbpCookieAuthenticationHandler.cs deleted file mode 100644 index 57b7ffbb8..000000000 --- a/aspnet-core/services/LY.MicroService.AuthServer/Authentication/AbpCookieAuthenticationHandler.cs +++ /dev/null @@ -1,89 +0,0 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System.Text.Encodings.Web; -using System.Threading.Tasks; -using Volo.Abp.Http; - -namespace LY.MicroService.AuthServer.Authentication; - -public class AbpCookieAuthenticationHandler : CookieAuthenticationHandler -{ - public AbpCookieAuthenticationHandler( - IOptionsMonitor options, - ILoggerFactory logger, - UrlEncoder encoder) : base(options, logger, encoder) - { - } - - public AbpCookieAuthenticationHandler( - IOptionsMonitor options, - ILoggerFactory logger, - UrlEncoder encoder, - ISystemClock clock) : base(options, logger, encoder, clock) - { - } - protected override Task InitializeEventsAsync() - { - var events = new CookieAuthenticationEvents - { - OnRedirectToLogin = ctx => - { - if (ctx.Request.CanAccept(MimeTypes.Application.Json)) - { - ctx.Response.Headers.Location = ctx.RedirectUri; - ctx.Response.StatusCode = 401; - } - else - { - ctx.Response.Redirect(ctx.RedirectUri); - } - return Task.CompletedTask; - }, - OnRedirectToAccessDenied = ctx => - { - if (ctx.Request.CanAccept(MimeTypes.Application.Json)) - { - ctx.Response.Headers.Location = ctx.RedirectUri; - ctx.Response.StatusCode = 403; - } - else - { - ctx.Response.Redirect(ctx.RedirectUri); - } - return Task.CompletedTask; - }, - OnRedirectToLogout = ctx => - { - if (ctx.Request.CanAccept(MimeTypes.Application.Json)) - { - ctx.Response.Headers.Location = ctx.RedirectUri; - } - else - { - ctx.Response.Redirect(ctx.RedirectUri); - } - return Task.CompletedTask; - }, - OnRedirectToReturnUrl = ctx => - { - if (ctx.Request.CanAccept(MimeTypes.Application.Json)) - { - ctx.Response.Headers.Location = ctx.RedirectUri; - } - else - { - ctx.Response.Redirect(ctx.RedirectUri); - } - return Task.CompletedTask; - } - }; - - Events = events; - - return Task.CompletedTask; - } -} - diff --git a/aspnet-core/services/LY.MicroService.AuthServer/LY.MicroService.AuthServer.csproj b/aspnet-core/services/LY.MicroService.AuthServer/LY.MicroService.AuthServer.csproj index 3ab2efbe9..dea6b14be 100644 --- a/aspnet-core/services/LY.MicroService.AuthServer/LY.MicroService.AuthServer.csproj +++ b/aspnet-core/services/LY.MicroService.AuthServer/LY.MicroService.AuthServer.csproj @@ -65,6 +65,7 @@ +