Browse Source

support wechat quick login.

pull/292/head
cKey 4 years ago
parent
commit
4968b1a4e8
  1. 7
      aspnet-core/LINGYUN.MicroService.IdentityServer.sln
  2. 7
      aspnet-core/LINGYUN.MicroService.Messages.sln
  3. 1
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN.Abp.IdentityServer.WeChat.csproj
  4. 4
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/AbpIdentityServerWeChatModule.cs
  5. 2
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/MiniProgram/WeChatMiniProgramGrantValidator.cs
  6. 2
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/Official/WeChatOfficialGrantValidator.cs
  7. 2
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/Official/WeChatOfficialOAuthConsts.cs
  8. 31
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/WeChatGrantValidator.cs
  9. 28
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN.Abp.IdentityServer.WeChatValidator.csproj
  10. 57
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/AbpIdentityServerWeChatValidatorModule.cs
  11. 62
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/AspNetIdentity/AbpWeChatProfileService.cs
  12. 9
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/IWeChatResourceDataSeeder.cs
  13. 10
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/Localization/WeChatValidator/en.json
  14. 10
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/Localization/WeChatValidator/zh-Hans.json
  15. 85
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatResourceDataSeeder.cs
  16. 74
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatSignatureMiddleware.cs
  17. 16
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatSignatureOptions.cs
  18. 111
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatValidator/WeChatTokenGrantValidator.cs
  19. 16
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatValidator/WeChatValidatorConsts.cs
  20. 316
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/Microsoft/AspNetCore/Authentication/WeChat/WeChatAuthenticationHandler.cs
  21. 54
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/Microsoft/AspNetCore/Authentication/WeChat/WeChatAuthenticationOptions.cs
  22. 18
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/Microsoft/AspNetCore/Authentication/WeChat/WeChatAuthenticationStateCacheItem.cs
  23. 64
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/Microsoft/AspNetCore/Authentication/WeChatAuthenticationExtensions.cs
  24. 22
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/Microsoft/AspNetCore/Builder/IdentityServerApplicationBuilderExtensions.cs
  25. 17
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/README.md
  26. 16
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/System/BytesExtensions.cs
  27. 17
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/System/StringExtensions.cs
  28. 63
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Text/Json/JsonElementExtensions.cs
  29. 19
      aspnet-core/modules/wechat/LINGYUN.Abp.Identity.WeChat/LINGYUN.Abp.Identity.WeChat.csproj
  30. 13
      aspnet-core/modules/wechat/LINGYUN.Abp.Identity.WeChat/LINGYUN/Abp/Identity/WeChat/AbpIdentityWeChatModule.cs
  31. 17
      aspnet-core/modules/wechat/LINGYUN.Abp.Identity.WeChat/LINGYUN/Abp/Identity/WeChat/OpenId/UserWeChatOpenIdFinder.cs
  32. 14
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application.Contracts/LINGYUN.Abp.WeChat.Application.Contracts.csproj
  33. 11
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application.Contracts/LINGYUN/Abp/WeChat/AbpWeChatApplicationContractsModule.cs
  34. 21
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application.Contracts/LINGYUN/Abp/WeChat/Crypto/Dto/Gender.cs
  35. 9
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application.Contracts/LINGYUN/Abp/WeChat/Crypto/Dto/GetUserInfoInput.cs
  36. 37
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application.Contracts/LINGYUN/Abp/WeChat/Crypto/Dto/UserInfoDto.cs
  37. 10
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application.Contracts/LINGYUN/Abp/WeChat/Crypto/ICryptoAppService.cs
  38. 7
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application.Contracts/LINGYUN/Abp/WeChat/WeChatRemoteServiceConsts.cs
  39. 19
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application/LINGYUN.Abp.WeChat.Application.csproj
  40. 14
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application/LINGYUN/Abp/WeChat/AbpWeChatApplicationModule.cs
  41. 42
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application/LINGYUN/Abp/WeChat/Crypto/CryptoAppService.cs
  42. 14
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application/LINGYUN/Abp/WeChat/WeChatApplicationServiceBase.cs
  43. 14
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.HttpApi/LINGYUN.Abp.WeChat.HttpApi.csproj
  44. 12
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.HttpApi/LINGYUN/Abp/WeChat/AbpWeChatHttpApiModule.cs
  45. 29
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.HttpApi/LINGYUN/Abp/WeChat/Crypto/CryptoController.cs
  46. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/AbpWeChatMiniProgramConsts.cs
  47. 4
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/AbpWeChatMiniProgramModule.cs
  48. 12
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Messages/SubscribeMessager.cs
  49. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialConsts.cs
  50. 8
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.SettingManagement/LINGYUN/Abp/WeChat/SettingManagement/WeChatSettingAppService.cs
  51. 4
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/AbpWeChatModule.cs
  52. 7
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Crypto/IWeChatCryptoService.cs
  53. 36
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Crypto/WeChatCryptoService.cs
  54. 5
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Localization/Resources/en.json
  55. 5
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Localization/Resources/zh-Hans.json
  56. 8
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/OpenId/IWeChatOpenIdFinder.cs
  57. 10
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/OpenId/WeChatOpenIdCacheItem.cs
  58. 32
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/OpenId/WeChatOpenIdFinder.cs
  59. 28
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Settings/WeChatSettingDefinitionProvider.cs
  60. 5
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Settings/WeChatSettingNames.cs
  61. 8
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Token/WeChatTokenProvider.cs
  62. 4
      aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/AbpMessageServiceHttpApiHostModule.cs
  63. 2
      aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj

7
aspnet-core/LINGYUN.MicroService.IdentityServer.sln

@ -59,6 +59,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "theming", "theming", "{1D7C
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Components.WebAssembly.AntDesign", "theming\Volo.Abp.AspNetCore.Components.WebAssembly.AntDesign\Volo.Abp.AspNetCore.Components.WebAssembly.AntDesign.csproj", "{596BB67C-7765-4481-9C8B-EAE0D9726B75}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Identity.WeChat", "modules\wechat\LINGYUN.Abp.Identity.WeChat\LINGYUN.Abp.Identity.WeChat.csproj", "{46C3E5D2-7738-4C0F-AC51-C61A024CAF23}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -141,6 +143,10 @@ Global
{596BB67C-7765-4481-9C8B-EAE0D9726B75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{596BB67C-7765-4481-9C8B-EAE0D9726B75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{596BB67C-7765-4481-9C8B-EAE0D9726B75}.Release|Any CPU.Build.0 = Release|Any CPU
{46C3E5D2-7738-4C0F-AC51-C61A024CAF23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{46C3E5D2-7738-4C0F-AC51-C61A024CAF23}.Debug|Any CPU.Build.0 = Debug|Any CPU
{46C3E5D2-7738-4C0F-AC51-C61A024CAF23}.Release|Any CPU.ActiveCfg = Release|Any CPU
{46C3E5D2-7738-4C0F-AC51-C61A024CAF23}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -171,6 +177,7 @@ Global
{D63C0CA8-554D-43F2-8DB4-8B464E4C1CDA} = {98887A8F-7040-4FA1-842F-A4C77A61ED09}
{79CAF2CA-E9E1-48A5-A21F-3786383C12E0} = {98887A8F-7040-4FA1-842F-A4C77A61ED09}
{596BB67C-7765-4481-9C8B-EAE0D9726B75} = {1D7CE7E0-37AB-477B-919B-B1EB2899A17E}
{46C3E5D2-7738-4C0F-AC51-C61A024CAF23} = {AF8AECC8-0F42-4FC5-B3C0-00987BA8279F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FCB77471-9ECB-4666-A316-1D6A6285A468}

7
aspnet-core/LINGYUN.MicroService.Messages.sln

@ -81,6 +81,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.BackgroundWorke
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.EventBus.CAP", "modules\common\LINGYUN.Abp.EventBus.CAP\LINGYUN.Abp.EventBus.CAP.csproj", "{C49B50D4-5D63-47E6-82F7-E742181CF9DE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Identity.WeChat", "modules\wechat\LINGYUN.Abp.Identity.WeChat\LINGYUN.Abp.Identity.WeChat.csproj", "{DC71289C-18A7-4E4B-A653-E66941EB19AE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -219,6 +221,10 @@ Global
{C49B50D4-5D63-47E6-82F7-E742181CF9DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C49B50D4-5D63-47E6-82F7-E742181CF9DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C49B50D4-5D63-47E6-82F7-E742181CF9DE}.Release|Any CPU.Build.0 = Release|Any CPU
{DC71289C-18A7-4E4B-A653-E66941EB19AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DC71289C-18A7-4E4B-A653-E66941EB19AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DC71289C-18A7-4E4B-A653-E66941EB19AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC71289C-18A7-4E4B-A653-E66941EB19AE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -260,6 +266,7 @@ Global
{05DCBA6B-480A-4D2F-9855-F66F5B7F3A48} = {C00828FB-E7D5-4086-BA50-02022594AB73}
{32D4DB5D-74D1-4166-85EA-B2D8F14B8058} = {C00828FB-E7D5-4086-BA50-02022594AB73}
{C49B50D4-5D63-47E6-82F7-E742181CF9DE} = {C00828FB-E7D5-4086-BA50-02022594AB73}
{DC71289C-18A7-4E4B-A653-E66941EB19AE} = {78164C5C-63B9-4FB6-ACC9-6496E236C946}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6238659A-7267-49B9-A499-8746BDEED6B8}

1
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN.Abp.IdentityServer.WeChat.csproj

@ -17,6 +17,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\wechat\LINGYUN.Abp.Identity.WeChat\LINGYUN.Abp.Identity.WeChat.csproj" />
<ProjectReference Include="..\..\wechat\LINGYUN.Abp.WeChat.MiniProgram\LINGYUN.Abp.WeChat.MiniProgram.csproj" />
<ProjectReference Include="..\..\wechat\LINGYUN.Abp.WeChat.Official\LINGYUN.Abp.WeChat.Official.csproj" />
</ItemGroup>

4
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/AbpIdentityServerWeChatModule.cs

@ -1,4 +1,5 @@
using LINGYUN.Abp.IdentityServer.WeChat.MiniProgram;
using LINGYUN.Abp.Identity.WeChat;
using LINGYUN.Abp.IdentityServer.WeChat.MiniProgram;
using LINGYUN.Abp.IdentityServer.WeChat.Official;
using LINGYUN.Abp.WeChat.MiniProgram;
using LINGYUN.Abp.WeChat.Official;
@ -15,6 +16,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChat
[DependsOn(
typeof(AbpWeChatOfficialModule),
typeof(AbpWeChatMiniProgramModule),
typeof(AbpIdentityWeChatModule),
typeof(AbpIdentityServerDomainModule))]
public class AbpIdentityServerWeChatModule : AbpModule
{

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

@ -18,7 +18,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChat.MiniProgram
{
public override string GrantType => AbpWeChatMiniProgramConsts.GrantType;
public override string LoginProviderKey => AbpWeChatMiniProgramConsts.ProviderKey;
public override string LoginProvider => AbpWeChatMiniProgramConsts.ProviderName;
public override string AuthenticationMethod => AbpWeChatMiniProgramConsts.AuthenticationMethod;

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

@ -17,7 +17,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChat.Official
{
public override string GrantType => AbpWeChatOfficialConsts.GrantType;
public override string LoginProviderKey => AbpWeChatOfficialConsts.ProviderKey;
public override string LoginProvider => AbpWeChatOfficialConsts.ProviderName;
public override string AuthenticationMethod => AbpWeChatOfficialConsts.AuthenticationMethod;

2
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/Official/WeChatOfficialOAuthConsts.cs

@ -15,7 +15,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChat.Official
/// <summary>
/// 微信提供者标识
/// </summary>
public static string ProviderKey => AbpWeChatOfficialConsts.ProviderKey;
public static string ProviderKey => AbpWeChatOfficialConsts.ProviderName;
/// <summary>
/// 微信提供者显示名称
/// </summary>

31
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/WeChatGrantValidator.cs

@ -7,6 +7,7 @@ using IdentityServer4.Validation;
using LINGYUN.Abp.WeChat;
using LINGYUN.Abp.WeChat.OpenId;
using LINGYUN.Abp.WeChat.Security.Claims;
using LINGYUN.Abp.WeChat.Settings;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
@ -15,9 +16,14 @@ using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.Identity;
using Volo.Abp.IdentityServer.Localization;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Security.Claims;
using Volo.Abp.Settings;
using Volo.Abp.Uow;
using IdentityResource = Volo.Abp.Identity.Localization.IdentityResource;
using IdentityUser = Volo.Abp.Identity.IdentityUser;
@ -26,10 +32,12 @@ namespace LINGYUN.Abp.IdentityServer.WeChat
public abstract class WeChatGrantValidator : IExtensionGrantValidator
{
public abstract string GrantType { get; }
public abstract string LoginProviderKey { get; }
public abstract string LoginProvider { get; }
public abstract string AuthenticationMethod { get; }
public ILogger Logger { protected get; set; }
public IAbpLazyServiceProvider ServiceProvider { protected get; set; }
protected IEventService EventService { get; }
protected IWeChatOpenIdFinder WeChatOpenIdFinder { get; }
protected IIdentityUserRepository UserRepository { get; }
@ -57,6 +65,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChat
protected abstract Task<WeChatOpenId> FindOpenIdAsync(string code);
[UnitOfWork]
public async Task ValidateAsync(ExtensionGrantValidationContext context)
{
var raw = context.Request.Raw;
@ -77,13 +86,31 @@ namespace LINGYUN.Abp.IdentityServer.WeChat
}
var wechatOpenId = await FindOpenIdAsync(wechatCode);
var currentUser = await UserManager.FindByLoginAsync(LoginProviderKey, wechatOpenId.OpenId);
var currentUser = await UserManager.FindByLoginAsync(LoginProvider, wechatOpenId.OpenId);
if (currentUser == null)
{
var settingProvider = ServiceProvider.LazyGetRequiredService<ISettingProvider>();
// TODO 检查启用用户注册是否有必要引用账户模块
if (! await settingProvider.IsTrueAsync("Abp.Account.IsSelfRegistrationEnabled") ||
! await settingProvider.IsTrueAsync(WeChatSettingNames.EnabledQuickLogin))
{
Logger.LogWarning("Invalid grant type: wechat openid not register", wechatOpenId.OpenId);
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, IdentityServerLocalizer["InvalidGrant:WeChatNotRegister"]);
return;
}
var guiGenerator = ServiceProvider.LazyGetRequiredService<IGuidGenerator>();
var currentTenant = ServiceProvider.LazyGetRequiredService<ICurrentTenant>();
var userName = "wxid-" + wechatOpenId.OpenId.ToMd5().ToLower();
var userEmail = $"{userName}@{currentTenant.Name ?? "default"}.io";
currentUser = new IdentityUser(guiGenerator.Create(), userName, userEmail, currentTenant.Id);
(await UserManager.CreateAsync(currentUser)).CheckErrors();
(await UserManager.AddLoginAsync(
currentUser,
new UserLoginInfo(
LoginProvider,
wechatOpenId.OpenId,
LoginProvider))).CheckErrors();
}
if (await UserManager.IsLockedOutAsync(currentUser))
{

28
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN.Abp.IdentityServer.WeChatValidator.csproj

@ -1,28 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<None Remove="LINGYUN\Abp\IdentityServer\Localization\WeChatValidator\en.json" />
<None Remove="LINGYUN\Abp\IdentityServer\Localization\WeChatValidator\zh-Hans.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="LINGYUN\Abp\IdentityServer\Localization\WeChatValidator\en.json" />
<EmbeddedResource Include="LINGYUN\Abp\IdentityServer\Localization\WeChatValidator\zh-Hans.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.IdentityServer.Domain" Version="4.4.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Microsoft\DependencyInjection\" />
</ItemGroup>
</Project>

57
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/AbpIdentityServerWeChatValidatorModule.cs

@ -1,57 +0,0 @@
using LINGYUN.Abp.IdentityServer.AspNetIdentity;
using LINGYUN.Abp.IdentityServer.WeChatValidator;
using LINGYUN.Abp.WeChat.Authorization;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.IdentityServer;
using Volo.Abp.IdentityServer.Localization;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.IdentityServer
{
[DependsOn(
typeof(AbpWeChatAuthorizationModule),
typeof(AbpIdentityServerDomainModule))]
public class AbpIdentityServerWeChatValidatorModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
PreConfigure<IIdentityServerBuilder>(builder =>
{
builder.AddProfileService<AbpWeChatProfileServicee>();
builder.AddExtensionGrantValidator<WeChatTokenGrantValidator>();
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<WeChatSignatureOptions>(configuration.GetSection("WeChat:Signature"));
context.Services
.AddAuthentication()
.AddWeChat(options => // 加入微信认证登录
{
configuration.GetSection("WeChat:Auth")?.Bind(options);
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpIdentityServerWeChatValidatorModule>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<AbpIdentityServerResource>()
.AddVirtualJson("/LINGYUN/Abp/IdentityServer/Localization/WeChatValidator");
});
}
}
}

62
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/AspNetIdentity/AbpWeChatProfileService.cs

@ -1,62 +0,0 @@
using IdentityServer4.AspNetIdentity;
using IdentityServer4.Models;
using LINGYUN.Abp.WeChat.Authorization;
using Microsoft.AspNetCore.Identity;
using System.Linq;
using System.Security.Principal;
using System.Threading.Tasks;
using Volo.Abp.Identity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Security.Claims;
using Volo.Abp.Uow;
using IdentityUser = Volo.Abp.Identity.IdentityUser;
namespace LINGYUN.Abp.IdentityServer.AspNetIdentity
{
public class AbpWeChatProfileServicee : ProfileService<IdentityUser>
{
protected ICurrentTenant CurrentTenant { get; }
public AbpWeChatProfileServicee(
IdentityUserManager userManager,
IUserClaimsPrincipalFactory<IdentityUser> claimsFactory,
ICurrentTenant currentTenant)
: base(userManager, claimsFactory)
{
CurrentTenant = currentTenant;
}
[UnitOfWork]
public override async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
using (CurrentTenant.Change(context.Subject.FindTenantId()))
{
await base.GetProfileDataAsync(context);
// TODO: 可以从令牌获取openid, 安全性呢?
TryAddWeChatClaim(context, AbpWeChatClaimTypes.OpenId);
TryAddWeChatClaim(context, AbpWeChatClaimTypes.UnionId);
}
}
[UnitOfWork]
public override async Task IsActiveAsync(IsActiveContext context)
{
using (CurrentTenant.Change(context.Subject.FindTenantId()))
{
await base.IsActiveAsync(context);
}
}
protected virtual void TryAddWeChatClaim(ProfileDataRequestContext context, string weChatClaimType)
{
if (context.RequestedClaimTypes.Any(rc => rc.Contains(weChatClaimType)))
{
var weChatClaim = context.Subject.FindFirst(weChatClaimType);
if (weChatClaim != null)
{
context.IssuedClaims.Add(weChatClaim);
}
}
}
}
}

9
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/IWeChatResourceDataSeeder.cs

@ -1,9 +0,0 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.IdentityServer
{
public interface IWeChatResourceDataSeeder
{
Task CreateStandardResourcesAsync();
}
}

10
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/Localization/WeChatValidator/en.json

@ -1,10 +0,0 @@
{
"culture": "en",
"texts": {
"SelfRegistrationDisabledMessage": "Self-registration is disabled for this application. Please contact the application administrator to register a new user.",
"InvalidGrant:GrantTypeInvalid": "The type of authorization that is not allowed!",
"InvalidGrant:WeChatTokenInvalid": "WeChat authentication failed!",
"InvalidGrant:WeChatCodeNotFound": "The code obtained when WeChat is logged in is empty or does not exist!",
"InvalidGrant:WeChatNotRegister": "User WeChat account not registed!"
}
}

10
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/Localization/WeChatValidator/zh-Hans.json

@ -1,10 +0,0 @@
{
"culture": "zh-Hans",
"texts": {
"SelfRegistrationDisabledMessage": "应用程序未开放注册,请联系管理员添加新用户.",
"InvalidGrant:GrantTypeInvalid": "不被允许的授权类型!",
"InvalidGrant:WeChatTokenInvalid": "微信认证失败!",
"InvalidGrant:WeChatCodeNotFound": "微信登录时获取的 code 为空或不存在!",
"InvalidGrant:WeChatNotRegister": "用户微信账号未绑定!"
}
}

85
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatResourceDataSeeder.cs

@ -1,85 +0,0 @@
using LINGYUN.Abp.WeChat.Authorization;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.Identity;
using Volo.Abp.IdentityServer.IdentityResources;
namespace LINGYUN.Abp.IdentityServer
{
public class WeChatResourceDataSeeder : IWeChatResourceDataSeeder, ITransientDependency
{
protected IIdentityClaimTypeRepository ClaimTypeRepository { get; }
protected IIdentityResourceRepository IdentityResourceRepository { get; }
protected IGuidGenerator GuidGenerator { get; }
public WeChatResourceDataSeeder(
IIdentityResourceRepository identityResourceRepository,
IGuidGenerator guidGenerator,
IIdentityClaimTypeRepository claimTypeRepository)
{
IdentityResourceRepository = identityResourceRepository;
GuidGenerator = guidGenerator;
ClaimTypeRepository = claimTypeRepository;
}
public virtual async Task CreateStandardResourcesAsync()
{
var wechatClaimTypes = new string[]
{
AbpWeChatClaimTypes.AvatarUrl,
AbpWeChatClaimTypes.City,
AbpWeChatClaimTypes.Country,
AbpWeChatClaimTypes.NickName,
AbpWeChatClaimTypes.OpenId,
AbpWeChatClaimTypes.Privilege,
AbpWeChatClaimTypes.Province,
AbpWeChatClaimTypes.Sex,
AbpWeChatClaimTypes.UnionId
};
var wechatResource = new IdentityServer4.Models.IdentityResource(
AbpWeChatAuthorizationConsts.ProfileKey,
AbpWeChatAuthorizationConsts.DisplayName,
wechatClaimTypes);
foreach (var claimType in wechatClaimTypes)
{
await AddClaimTypeIfNotExistsAsync(claimType);
}
await AddIdentityResourceIfNotExistsAsync(wechatResource);
}
protected virtual async Task AddIdentityResourceIfNotExistsAsync(IdentityServer4.Models.IdentityResource resource)
{
if (await IdentityResourceRepository.CheckNameExistAsync(resource.Name))
{
return;
}
await IdentityResourceRepository.InsertAsync(
new IdentityResource(
GuidGenerator.Create(),
resource
)
);
}
protected virtual async Task AddClaimTypeIfNotExistsAsync(string claimType)
{
if (await ClaimTypeRepository.AnyAsync(claimType))
{
return;
}
await ClaimTypeRepository.InsertAsync(
new IdentityClaimType(
GuidGenerator.Create(),
claimType,
isStatic: true
)
);
}
}
}

74
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatSignatureMiddleware.cs

@ -1,74 +0,0 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using System;
using System.Collections;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.IdentityServer
{
public class WeChatSignatureMiddleware : IMiddleware, ITransientDependency
{
protected WeChatSignatureOptions Options { get; }
public WeChatSignatureMiddleware(IOptions<WeChatSignatureOptions> options)
{
Options = options.Value;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
if (context.Request.Path.HasValue)
{
var requestPath = context.Request.Path.Value;
// 访问地址是否与定义的地址匹配
if (requestPath.Equals(Options.RequestPath))
{
var timestamp = context.Request.Query["timestamp"];
var nonce = context.Request.Query["nonce"];
var signature = context.Request.Query["signature"];
var echostr = context.Request.Query["echostr"];
// 验证消息合法性
var check = CheckWeChatSignature(Options.Token, timestamp, nonce, signature);
if (check)
{
// 验证通过需要把微信服务器传递的字符原封不动传回
await context.Response.WriteAsync(echostr);
return;
}
// 微信消息验证不通过
throw new AbpException("Invalid wechat signature");
}
}
// 不属于微信的消息进入下一个中间件
await next(context);
}
protected bool CheckWeChatSignature(string token, string timestamp, string nonce, string signature)
{
var al = new ArrayList
{
token,
timestamp,
nonce
};
// step1 排序
al.Sort();
string signatureStr = string.Empty;
// step2 拼接
for (int i = 0; i < al.Count; i++)
{
signatureStr += al[i];
}
// step3 SHA1加密
byte[] bytes_out = signatureStr.Sha1();
string result = BitConverter.ToString(bytes_out).Replace("-", "");
// step4 比对
if (result.Equals(signature, StringComparison.CurrentCultureIgnoreCase))
{
return true;
}
return false;
}
}
}

16
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatSignatureOptions.cs

@ -1,16 +0,0 @@
namespace LINGYUN.Abp.IdentityServer
{
public class WeChatSignatureOptions
{
/// <summary>
/// 微信服务器请求路径
/// 填写在微信开发者中心配置的地址
/// </summary>
public string RequestPath { get; set; }
/// <summary>
/// 微信服务器请求token
/// 填写在微信开发者中心配置的token
/// </summary>
public string Token { get; set; }
}
}

111
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatValidator/WeChatTokenGrantValidator.cs

@ -1,111 +0,0 @@
using IdentityModel;
using IdentityServer4.Events;
using IdentityServer4.Models;
using IdentityServer4.Services;
using IdentityServer4.Validation;
using LINGYUN.Abp.WeChat.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using Volo.Abp.Identity;
using Volo.Abp.IdentityServer.Localization;
using Volo.Abp.Security.Claims;
using IdentityUser = Volo.Abp.Identity.IdentityUser;
namespace LINGYUN.Abp.IdentityServer.WeChatValidator
{
public class WeChatTokenGrantValidator : IExtensionGrantValidator
{
protected ILogger<WeChatTokenGrantValidator> Logger { get; }
protected AbpWeChatAuthorizationOptions Options { get; }
protected IHttpClientFactory HttpClientFactory{ get; }
protected IEventService EventService { get; }
protected IWeChatOpenIdFinder WeChatOpenIdFinder { get; }
protected IIdentityUserRepository UserRepository { get; }
protected UserManager<IdentityUser> UserManager { get; }
protected SignInManager<IdentityUser> SignInManager { get; }
protected IStringLocalizer<AbpIdentityServerResource> Localizer { get; }
protected PhoneNumberTokenProvider<IdentityUser> PhoneNumberTokenProvider { get; }
public WeChatTokenGrantValidator(
IEventService eventService,
IWeChatOpenIdFinder weChatOpenIdFinder,
IHttpClientFactory httpClientFactory,
UserManager<IdentityUser> userManager,
IIdentityUserRepository userRepository,
SignInManager<IdentityUser> signInManager,
IStringLocalizer<AbpIdentityServerResource> stringLocalizer,
PhoneNumberTokenProvider<IdentityUser> phoneNumberTokenProvider,
IOptions<AbpWeChatAuthorizationOptions> options,
ILogger<WeChatTokenGrantValidator> logger)
{
Logger = logger;
Options = options.Value;
EventService = eventService;
UserManager = userManager;
SignInManager = signInManager;
Localizer = stringLocalizer;
UserRepository = userRepository;
WeChatOpenIdFinder = weChatOpenIdFinder;
HttpClientFactory = httpClientFactory;
PhoneNumberTokenProvider = phoneNumberTokenProvider;
}
public string GrantType => WeChatValidatorConsts.WeChatValidatorGrantTypeName;
public async Task ValidateAsync(ExtensionGrantValidationContext context)
{
var raw = context.Request.Raw;
var credential = raw.Get(OidcConstants.TokenRequest.GrantType);
if (credential == null || !credential.Equals(GrantType))
{
Logger.LogWarning("Invalid grant type: not allowed");
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant,
Localizer["InvalidGrant:GrantTypeInvalid"]);
return;
}
// TODO: 统一命名规范, 微信认证传递的 code 改为 WeChatOpenIdConsts.WeCahtCodeKey
var wechatCode = raw.Get(WeChatValidatorConsts.WeChatValidatorTokenName);
if (wechatCode.IsNullOrWhiteSpace() || wechatCode.IsNullOrWhiteSpace())
{
Logger.LogWarning("Invalid grant type: wechat code not found");
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant,
Localizer["InvalidGrant:WeChatCodeNotFound"]);
return;
}
var wechatOpenId = await WeChatOpenIdFinder.FindAsync(wechatCode);
var currentUser = await UserManager.FindByLoginAsync(AbpWeChatAuthorizationConsts.ProviderKey, wechatOpenId.OpenId);
if(currentUser == null)
{
Logger.LogWarning("Invalid grant type: wechat openid: {0} not register", wechatOpenId.OpenId);
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant,
Localizer["InvalidGrant:WeChatNotRegister"]);
return;
}
var sub = await UserManager.GetUserIdAsync(currentUser);
var additionalClaims = new List<Claim>();
if (currentUser.TenantId.HasValue)
{
additionalClaims.Add(new Claim(AbpClaimTypes.TenantId, currentUser.TenantId?.ToString()));
}
additionalClaims.Add(new Claim(AbpWeChatClaimTypes.OpenId, wechatOpenId.OpenId));
if (!wechatOpenId.UnionId.IsNullOrWhiteSpace())
{
additionalClaims.Add(new Claim(AbpWeChatClaimTypes.UnionId, wechatOpenId.UnionId));
}
await EventService.RaiseAsync(new UserLoginSuccessEvent(currentUser.UserName, wechatOpenId.OpenId, null));
context.Result = new GrantValidationResult(sub,
WeChatValidatorConsts.AuthenticationMethods.BasedWeChatAuthentication, additionalClaims.ToArray());
}
}
}

16
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatValidator/WeChatValidatorConsts.cs

@ -1,16 +0,0 @@
namespace LINGYUN.Abp.IdentityServer.WeChatValidator
{
public class WeChatValidatorConsts
{
public const string WeChatValidatorClientName = "WeChatValidator";
public const string WeChatValidatorGrantTypeName = "wechat";
public const string WeChatValidatorTokenName = "code";
public class AuthenticationMethods
{
public const string BasedWeChatAuthentication = "wca";
}
}
}

316
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/Microsoft/AspNetCore/Authentication/WeChat/WeChatAuthenticationHandler.cs

@ -1,316 +0,0 @@
using LINGYUN.Abp.WeChat.Authorization;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Caching.Distributed;
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.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.Caching;
namespace Microsoft.AspNetCore.Authentication.WeChat
{
public class WeChatAuthenticationHandler : OAuthHandler<WeChatAuthenticationOptions>
{
protected IDistributedCache<WeChatAuthenticationStateCacheItem> Cache { get; }
public WeChatAuthenticationHandler(
IDistributedCache<WeChatAuthenticationStateCacheItem> cache,
IOptionsMonitor<WeChatAuthenticationOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock)
: base(options, logger, encoder, clock)
{
Cache = cache;
}
protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
{
var address = QueryHelpers.AddQueryString(Options.UserInformationEndpoint, new Dictionary<string, string>
{
["access_token"] = tokens.AccessToken,
["openid"] = tokens.Response.GetRootString("openid")
});
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 (!string.IsNullOrEmpty(payload.GetRootString("errcode")))
{
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);
// TODO: 此处通过唯一的 CorrelationId, 将 properties生成的State缓存删除
var state = Request.Query["state"];
var stateCacheKey = WeChatAuthenticationStateCacheItem.CalculateCacheKey(state, null);
await Cache.RemoveAsync(stateCacheKey, token: Context.RequestAborted);
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
}
/// <summary>
/// code换取access_token
/// </summary>
protected override async Task<OAuthTokenResponse> ExchangeCodeAsync(OAuthCodeExchangeContext context)
{
var address = QueryHelpers.AddQueryString(Options.TokenEndpoint, new Dictionary<string, string>()
{
["appid"] = Options.ClientId,
["secret"] = Options.ClientSecret,
["code"] = context.Code,
["grant_type"] = "authorization_code"
});
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 (!string.IsNullOrEmpty(payload.GetRootString("errcode")))
{
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 override async Task HandleChallengeAsync(AuthenticationProperties properties)
{
await base.HandleChallengeAsync(properties);
// TODO: 此处已经生成唯一的 CorrelationId, 可以借此将 properties生成State之后再进行缓存
var state = properties.Items[".xsrf"];
var stateToken = Options.StateDataFormat.Protect(properties);
var stateCacheKey = WeChatAuthenticationStateCacheItem.CalculateCacheKey(state, null);
await Cache
.SetAsync(
stateCacheKey,
new WeChatAuthenticationStateCacheItem(stateToken),
new DistributedCacheEntryOptions
{
AbsoluteExpiration = Clock.UtcNow.AddMinutes(2) // TODO: 设定2分钟过期?
},
token: Context.RequestAborted);
}
/// <summary>
/// 构建用户授权地址
/// </summary>
protected override string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
{
var state = properties.Items[".xsrf"];
var isWeChatBrewserRequest = IsWeChatBrowser();
var scope = isWeChatBrewserRequest
? AbpWeChatAuthorizationConsts.UserInfoScope
: FormatScope();
var endPoint = isWeChatBrewserRequest
? Options.AuthorizationEndpoint
: AbpWeChatAuthorizationConsts.QrConnectEndpoint;
var challengeUrl = QueryHelpers.AddQueryString(endPoint, new Dictionary<string, string>
{
["appid"] = Options.ClientId,
["redirect_uri"] = redirectUri,
["response_type"] = "code"
});
challengeUrl += $"&scope={scope}&state={state}";
return challengeUrl;
}
protected override async Task<HandleRequestResult> HandleRemoteAuthenticateAsync()
{
var query = Request.Query;
// TODO: 此处借用唯一的 CorrelationId, 将 properties生成的State缓存取出,进行解密
var state = query["state"];
var stateCacheKey = WeChatAuthenticationStateCacheItem.CalculateCacheKey(state, null);
var stateCacheItem = await Cache.GetAsync(stateCacheKey, token: Context.RequestAborted);
var properties = Options.StateDataFormat.Unprotect(stateCacheItem.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<AuthenticationToken>();
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 = Clock.UtcNow + TimeSpan.FromSeconds(value);
authTokens.Add(new AuthenticationToken
{
Name = "expires_at",
Value = expiresAt.ToString("o", CultureInfo.InvariantCulture)
});
}
}
properties.StoreTokens(authTokens);
}
var ticket = await CreateTicketAsync(identity, properties, tokens);
if (ticket != null)
{
return HandleRequestResult.Success(ticket);
}
else
{
return HandleRequestResult.Fail("Failed to retrieve user information from remote server.", properties);
}
}
protected override string FormatScope()
{
return string.Join(",", Options.Scope);
}
protected virtual bool IsWeChatBrowser()
{
var userAgent = Request.Headers[HeaderNames.UserAgent].ToString();
return userAgent.Contains("micromessenger", StringComparison.InvariantCultureIgnoreCase);
}
}
}

54
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/Microsoft/AspNetCore/Authentication/WeChat/WeChatAuthenticationOptions.cs

@ -1,54 +0,0 @@
using LINGYUN.Abp.WeChat.Authorization;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;
using System.Text.Json;
namespace Microsoft.AspNetCore.Authentication.WeChat
{
public class WeChatAuthenticationOptions : OAuthOptions
{
public string AppId
{
get => ClientId;
set => ClientId = value;
}
public string AppSecret
{
get => ClientSecret;
set => ClientSecret = value;
}
public WeChatAuthenticationOptions()
{
ClaimsIssuer = AbpWeChatAuthorizationConsts.ProviderKey;
CallbackPath = new PathString(AbpWeChatAuthorizationConsts.CallbackPath);
AuthorizationEndpoint = AbpWeChatAuthorizationConsts.AuthorizationEndpoint;
TokenEndpoint = AbpWeChatAuthorizationConsts.TokenEndpoint;
UserInformationEndpoint = AbpWeChatAuthorizationConsts.UserInformationEndpoint;
Scope.Add(AbpWeChatAuthorizationConsts.LoginScope);
Scope.Add(AbpWeChatAuthorizationConsts.UserInfoScope);
// 这个原始的属性一定要写进去,框架与UserLogin.ProviderKey进行关联判断是否绑定微信
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "openid");
ClaimActions.MapJsonKey(ClaimTypes.Name, "nickname");
// 把自定义的身份标识写进令牌
ClaimActions.MapJsonKey(AbpWeChatClaimTypes.OpenId, "openid");
ClaimActions.MapJsonKey(AbpWeChatClaimTypes.UnionId, "unionid"); // TODO: 可用作tenant对比?
ClaimActions.MapJsonKey(AbpWeChatClaimTypes.NickName, "nickname");
ClaimActions.MapJsonKey(AbpWeChatClaimTypes.Sex, "sex", ClaimValueTypes.Integer);
ClaimActions.MapJsonKey(AbpWeChatClaimTypes.Country, "country");
ClaimActions.MapJsonKey(AbpWeChatClaimTypes.Province, "province");
ClaimActions.MapJsonKey(AbpWeChatClaimTypes.City, "city");
ClaimActions.MapJsonKey(AbpWeChatClaimTypes.AvatarUrl, "headimgurl");
ClaimActions.MapCustomJson(AbpWeChatClaimTypes.Privilege, user =>
{
return string.Join(",", user.GetStrings("privilege"));
});
}
}
}

18
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/Microsoft/AspNetCore/Authentication/WeChat/WeChatAuthenticationStateCacheItem.cs

@ -1,18 +0,0 @@
namespace Microsoft.AspNetCore.Authentication.WeChat
{
public class WeChatAuthenticationStateCacheItem
{
public string State { get; set; }
public WeChatAuthenticationStateCacheItem() { }
public WeChatAuthenticationStateCacheItem(string state)
{
State = state;
}
public static string CalculateCacheKey(string correlationId, string purpose)
{
return $"ci:{correlationId};p:{purpose ?? "null"}";
}
}
}

64
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/Microsoft/AspNetCore/Authentication/WeChatAuthenticationExtensions.cs

@ -1,64 +0,0 @@
using LINGYUN.Abp.WeChat.Authorization;
using Microsoft.AspNetCore.Authentication.WeChat;
using Microsoft.Extensions.DependencyInjection;
using System;
namespace Microsoft.AspNetCore.Authentication
{
public static class WeChatAuthenticationExtensions
{
/// <summary>
/// </summary>
public static AuthenticationBuilder AddWeChat(
this AuthenticationBuilder builder)
{
return builder
.AddWeChat(
AbpWeChatAuthorizationConsts.AuthenticationScheme,
AbpWeChatAuthorizationConsts.DisplayName,
options => { });
}
/// <summary>
/// </summary>
public static AuthenticationBuilder AddWeChat(
this AuthenticationBuilder builder,
Action<WeChatAuthenticationOptions> configureOptions)
{
return builder
.AddWeChat(
AbpWeChatAuthorizationConsts.AuthenticationScheme,
AbpWeChatAuthorizationConsts.DisplayName,
configureOptions);
}
/// <summary>
/// </summary>
public static AuthenticationBuilder AddWeChat(
this AuthenticationBuilder builder,
string authenticationScheme,
Action<WeChatAuthenticationOptions> configureOptions)
{
return builder
.AddWeChat(
authenticationScheme,
AbpWeChatAuthorizationConsts.DisplayName,
configureOptions);
}
/// <summary>
/// </summary>
public static AuthenticationBuilder AddWeChat(
this AuthenticationBuilder builder,
string authenticationScheme,
string displayName,
Action<WeChatAuthenticationOptions> configureOptions)
{
return builder
.AddOAuth<WeChatAuthenticationOptions, WeChatAuthenticationHandler>(
authenticationScheme,
displayName,
configureOptions);
}
}
}

22
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/Microsoft/AspNetCore/Builder/IdentityServerApplicationBuilderExtensions.cs

@ -1,22 +0,0 @@
using LINGYUN.Abp.IdentityServer;
namespace Microsoft.AspNetCore.Builder
{
public static class IdentityServerApplicationBuilderExtensions
{
/// <summary>
/// 启用中间件可以处理微信服务器消息
/// 用于验证消息是否来自于微信服务器
/// </summary>
/// <param name="builder"></param>
/// <remarks>
/// 也可以用Controller的形式来实现
/// </remarks>
/// <returns></returns>
public static IApplicationBuilder UseWeChatSignature(this IApplicationBuilder builder)
{
builder.UseMiddleware<WeChatSignatureMiddleware>();
return builder;
}
}
}

17
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/README.md

@ -1,17 +0,0 @@
# LINGYUN.Abp.IdentityServer.WeChatValidator
废弃模块,模块层次不清晰,微信有多端平台,不同平台授权规则不一致
#### 注意
## 配置使用
```csharp
[DependsOn(typeof(AbpIdentityServerWeChatValidatorModule))]
public class YouProjectModule : AbpModule
{
// other
}

16
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/System/BytesExtensions.cs

@ -1,16 +0,0 @@
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;
}
}
}
}

17
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/System/StringExtensions.cs

@ -1,17 +0,0 @@
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;
}
}
}
}

63
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Text/Json/JsonElementExtensions.cs

@ -1,63 +0,0 @@
using System.Collections.Generic;
namespace System.Text.Json
{
internal static class JsonElementExtensions
{
public static IEnumerable<string> GetRootStrings(this JsonDocument json, string key)
{
return json.RootElement.GetStrings(key);
}
public static IEnumerable<string> GetStrings(this JsonElement json, string key)
{
var result = new List<string>();
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;
}
}
}

19
aspnet-core/modules/wechat/LINGYUN.Abp.Identity.WeChat/LINGYUN.Abp.Identity.WeChat.csproj

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Identity.Domain" Version="4.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.WeChat\LINGYUN.Abp.WeChat.csproj" />
</ItemGroup>
</Project>

13
aspnet-core/modules/wechat/LINGYUN.Abp.Identity.WeChat/LINGYUN/Abp/Identity/WeChat/AbpIdentityWeChatModule.cs

@ -0,0 +1,13 @@
using LINGYUN.Abp.WeChat;
using Volo.Abp.Identity;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Identity.WeChat
{
[DependsOn(
typeof(AbpWeChatModule),
typeof(AbpIdentityDomainModule))]
public class AbpIdentityWeChatModule : AbpModule
{
}
}

17
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/WeChat/Authorization/UserWeChatOpenIdFinder.cs → aspnet-core/modules/wechat/LINGYUN.Abp.Identity.WeChat/LINGYUN/Abp/Identity/WeChat/OpenId/UserWeChatOpenIdFinder.cs

@ -1,11 +1,12 @@
using Microsoft.Extensions.DependencyInjection;
using LINGYUN.Abp.WeChat.OpenId;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Identity;
namespace LINGYUN.Abp.WeChat.Authorization
namespace LINGYUN.Abp.Identity.WeChat.OpenId
{
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
[ExposeServices(typeof(IUserWeChatOpenIdFinder))]
@ -19,25 +20,25 @@ namespace LINGYUN.Abp.WeChat.Authorization
UserManager = userManager;
}
public virtual async Task<string> FindByUserIdAsync(Guid userId)
public virtual async Task<string> FindByUserIdAsync(Guid userId, string provider)
{
var user = await UserManager.FindByIdAsync(userId.ToString());
return GetUserOpenIdOrNull(user);
return GetUserOpenIdOrNull(user, provider);
}
public virtual async Task<string> FindByUserNameAsync(string userName)
public virtual async Task<string> FindByUserNameAsync(string userName, string provider)
{
var user = await UserManager.FindByNameAsync(userName);
return GetUserOpenIdOrNull(user);
return GetUserOpenIdOrNull(user, provider);
}
protected string GetUserOpenIdOrNull(IdentityUser user)
protected string GetUserOpenIdOrNull(IdentityUser user, string provider)
{
// 微信扩展登录后openid存储在Login中
var userLogin = user?.Logins
.Where(login => login.LoginProvider == AbpWeChatAuthorizationConsts.ProviderKey)
.Where(login => login.LoginProvider == provider)
.FirstOrDefault();
return userLogin?.ProviderKey;

14
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application.Contracts/LINGYUN.Abp.WeChat.Application.Contracts.csproj

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="4.4.0" />
</ItemGroup>
</Project>

11
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application.Contracts/LINGYUN/Abp/WeChat/AbpWeChatApplicationContractsModule.cs

@ -0,0 +1,11 @@
using Volo.Abp.Application;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.WeChat
{
[DependsOn(
typeof(AbpDddApplicationContractsModule))]
public class AbpWeChatApplicationContractsModule : AbpModule
{
}
}

21
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application.Contracts/LINGYUN/Abp/WeChat/Crypto/Dto/Gender.cs

@ -0,0 +1,21 @@
namespace LINGYUN.Abp.WeChat.Crypto
{
/// <summary>
/// 性别
/// </summary>
public enum Gender
{
/// <summary>
/// 未知
/// </summary>
None = 0,
/// <summary>
/// 男性
/// </summary>
Man = 1,
/// <summary>
/// 女性
/// </summary>
Women = 2
}
}

9
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application.Contracts/LINGYUN/Abp/WeChat/Crypto/Dto/GetUserInfoInput.cs

@ -0,0 +1,9 @@
namespace LINGYUN.Abp.WeChat.Crypto
{
public class GetUserInfoInput
{
public string EncryptedData { get; set; }
public string IV { get; set; }
public string Code { get; set; }
}
}

37
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application.Contracts/LINGYUN/Abp/WeChat/Crypto/Dto/UserInfoDto.cs

@ -0,0 +1,37 @@
namespace LINGYUN.Abp.WeChat.Crypto
{
public class UserInfoDto
{
/// <summary>
/// 用户昵称
/// </summary>
public string NickName { get; set; }
/// <summary>
/// 用户头像图片的 URL。
/// URL 最后一个数值代表正方形头像大小(有 0、46、64、96、132 数值可选,0 代表 640x640 的正方形头像,46 表示 46x46 的正方形头像,剩余数值以此类推。默认132),
/// 用户没有头像时该项为空。
/// 若用户更换头像,原有头像 URL 将失效。
/// </summary>
public string AvatarUrl { get; set; }
/// <summary>
/// 性别
/// </summary>
public Gender Gender { get; set; }
/// <summary>
/// 用户所在国家
/// </summary>
public string Country { get; set; }
/// <summary>
/// 用户所在省份
/// </summary>
public string Province { get; set; }
/// <summary>
/// 用户所在城市
/// </summary>
public string City { get; set; }
/// <summary>
/// 显示 country,province,city 所用的语言
/// </summary>
public string Language { get; set; }
}
}

10
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application.Contracts/LINGYUN/Abp/WeChat/Crypto/ICryptoAppService.cs

@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.WeChat.Crypto
{
public interface ICryptoAppService : IApplicationService
{
Task<UserInfoDto> GetUserInfoAsync(GetUserInfoInput input);
}
}

7
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application.Contracts/LINGYUN/Abp/WeChat/WeChatRemoteServiceConsts.cs

@ -0,0 +1,7 @@
namespace LINGYUN.Abp.WeChat
{
public static class WeChatRemoteServiceConsts
{
public const string RemoteServiceName = "AbpWeChat";
}
}

19
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application/LINGYUN.Abp.WeChat.Application.csproj

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Ddd.Application" Version="4.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.WeChat.Application.Contracts\LINGYUN.Abp.WeChat.Application.Contracts.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.WeChat.MiniProgram\LINGYUN.Abp.WeChat.MiniProgram.csproj" />
</ItemGroup>
</Project>

14
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application/LINGYUN/Abp/WeChat/AbpWeChatApplicationModule.cs

@ -0,0 +1,14 @@
using LINGYUN.Abp.WeChat.MiniProgram;
using Volo.Abp.Application;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.WeChat
{
[DependsOn(
typeof(AbpWeChatMiniProgramModule),
typeof(AbpWeChatApplicationContractsModule),
typeof(AbpDddApplicationModule))]
public class AbpWeChatApplicationModule : AbpModule
{
}
}

42
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application/LINGYUN/Abp/WeChat/Crypto/CryptoAppService.cs

@ -0,0 +1,42 @@
using LINGYUN.Abp.WeChat.MiniProgram;
using LINGYUN.Abp.WeChat.OpenId;
using Microsoft.AspNetCore.Authorization;
using System;
using System.Threading.Tasks;
using Volo.Abp.Json;
namespace LINGYUN.Abp.WeChat.Crypto
{
[Authorize]
public class CryptoAppService : WeChatApplicationServiceBase, ICryptoAppService
{
protected IJsonSerializer JsonSerializer { get; }
protected IWeChatOpenIdFinder OpenIdFinder { get; }
protected IWeChatCryptoService WeChatCryptoService { get; }
protected AbpWeChatMiniProgramOptionsFactory MiniProgramOptionsFactory { get; }
public CryptoAppService(
IJsonSerializer jsonSerializer,
IWeChatOpenIdFinder openIdFinder,
IWeChatCryptoService weChatCryptoService,
AbpWeChatMiniProgramOptionsFactory miniProgramOptionsFactory)
{
JsonSerializer = jsonSerializer;
OpenIdFinder = openIdFinder;
WeChatCryptoService = weChatCryptoService;
MiniProgramOptionsFactory = miniProgramOptionsFactory;
}
public virtual async Task<UserInfoDto> GetUserInfoAsync(GetUserInfoInput input)
{
var options = await MiniProgramOptionsFactory.CreateAsync();
WeChatOpenId weChatOpenId = input.Code.IsNullOrWhiteSpace()
? await OpenIdFinder.FindAsync(options.AppId)
: await OpenIdFinder.FindAsync(input.Code, options.AppId, options.AppSecret);
var decryptedData = WeChatCryptoService.Decrypt(input.EncryptedData, input.IV, weChatOpenId.SessionKey);
return JsonSerializer.Deserialize<UserInfoDto>(decryptedData);
}
}
}

14
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Application/LINGYUN/Abp/WeChat/WeChatApplicationServiceBase.cs

@ -0,0 +1,14 @@
using LINGYUN.Abp.WeChat.Localization;
using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.WeChat
{
public abstract class WeChatApplicationServiceBase : ApplicationService
{
protected WeChatApplicationServiceBase()
{
LocalizationResource = typeof(WeChatResource);
ObjectMapperContext = typeof(AbpWeChatApplicationModule);
}
}
}

14
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.HttpApi/LINGYUN.Abp.WeChat.HttpApi.csproj

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="4.4.0" />
</ItemGroup>
</Project>

12
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.HttpApi/LINGYUN/Abp/WeChat/AbpWeChatHttpApiModule.cs

@ -0,0 +1,12 @@
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.WeChat
{
[DependsOn(
typeof(AbpWeChatApplicationContractsModule),
typeof(AbpAspNetCoreMvcModule))]
public class AbpWeChatHttpApiModule : AbpModule
{
}
}

29
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.HttpApi/LINGYUN/Abp/WeChat/Crypto/CryptoController.cs

@ -0,0 +1,29 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
namespace LINGYUN.Abp.WeChat.Crypto
{
[RemoteService(Name = WeChatRemoteServiceConsts.RemoteServiceName)]
[Area("account")]
[ApiVersion("1.0")]
[Route("api/wechat")]
public class CryptoController : AbpController, ICryptoAppService
{
private readonly ICryptoAppService _service;
public CryptoController(
ICryptoAppService service)
{
_service = service;
}
[HttpGet]
[Route("getUserInfo")]
public virtual async Task<UserInfoDto> GetUserInfoAsync(GetUserInfoInput input)
{
return await _service.GetUserInfoAsync(input);
}
}
}

2
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/AbpWeChatMiniProgramConsts.cs

@ -5,7 +5,7 @@
/// <summary>
/// 微信小程序对应的Provider名称
/// </summary>
public static string ProviderKey { get; set; } = "WeChat.MiniProgram";
public static string ProviderName { get; set; } = "WeChat.MiniProgram";
/// <summary>
/// 微信小程序授权类型

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

@ -3,14 +3,12 @@ using Microsoft.Extensions.DependencyInjection;
using System;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Settings;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.WeChat.MiniProgram
{
[DependsOn(
typeof(AbpWeChatModule),
typeof(AbpSettingsModule))]
typeof(AbpWeChatModule))]
public class AbpWeChatMiniProgramModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)

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

@ -2,7 +2,7 @@
using LINGYUN.Abp.WeChat.Token;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
@ -11,7 +11,6 @@ using System.Threading;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
namespace LINGYUN.Abp.WeChat.MiniProgram.Messages
{
@ -19,18 +18,15 @@ namespace LINGYUN.Abp.WeChat.MiniProgram.Messages
{
public ILogger<SubscribeMessager> Logger { get; set; }
protected IHttpClientFactory HttpClientFactory { get; }
protected IJsonSerializer JsonSerializer { get; }
protected AbpWeChatMiniProgramOptionsFactory MiniProgramOptionsFactory { get; }
protected IWeChatTokenProvider WeChatTokenProvider { get; }
protected IUserWeChatOpenIdFinder UserWeChatOpenIdFinder { get; }
public SubscribeMessager(
IJsonSerializer jsonSerializer,
IHttpClientFactory httpClientFactory,
IWeChatTokenProvider weChatTokenProvider,
IUserWeChatOpenIdFinder userWeChatOpenIdFinder,
AbpWeChatMiniProgramOptionsFactory miniProgramOptionsFactory)
{
JsonSerializer = jsonSerializer;
HttpClientFactory = httpClientFactory;
WeChatTokenProvider = weChatTokenProvider;
UserWeChatOpenIdFinder = userWeChatOpenIdFinder;
@ -48,7 +44,7 @@ namespace LINGYUN.Abp.WeChat.MiniProgram.Messages
Dictionary<string, object> data = null,
CancellationToken cancellation = default)
{
var openId = await UserWeChatOpenIdFinder.FindByUserIdAsync(toUser, AbpWeChatMiniProgramConsts.ProviderKey);
var openId = await UserWeChatOpenIdFinder.FindByUserIdAsync(toUser, AbpWeChatMiniProgramConsts.ProviderName);
if (openId.IsNullOrWhiteSpace())
{
Logger.LogWarning("Can not found openId, Unable to send WeChat message!");
@ -75,7 +71,7 @@ namespace LINGYUN.Abp.WeChat.MiniProgram.Messages
var weChatSendNotificationPath = "/cgi-bin/message/subscribe/send";
var requestUrl = BuildRequestUrl(weChatSendNotificationUrl, weChatSendNotificationPath, requestParamters);
var responseContent = await MakeRequestAndGetResultAsync(requestUrl, message, cancellationToken);
var response = JsonSerializer.Deserialize<SubscribeMessageResponse>(responseContent);
var response = JsonConvert.DeserializeObject<SubscribeMessageResponse>(responseContent);
if (!response.IsSuccessed)
{
@ -87,7 +83,7 @@ namespace LINGYUN.Abp.WeChat.MiniProgram.Messages
protected virtual async Task<string> MakeRequestAndGetResultAsync(string url, SubscribeMessage message, CancellationToken cancellationToken = default)
{
var client = HttpClientFactory.CreateClient(AbpWeChatMiniProgramConsts.HttpClient);
var sendDataContent = JsonSerializer.Serialize(message);
var sendDataContent = JsonConvert.SerializeObject(message);
var requestContent = new StringContent(sendDataContent);
var requestMessage = new HttpRequestMessage(HttpMethod.Post, url)
{

2
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialConsts.cs

@ -5,7 +5,7 @@
/// <summary>
/// 微信公众号对应的Provider名称
/// </summary>
public static string ProviderKey { get; set; } = "WeChat.Official";
public static string ProviderName { get; set; } = "WeChat.Official";
/// <summary>
/// 微信公众平台授权类型

8
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.SettingManagement/LINGYUN/Abp/WeChat/SettingManagement/WeChatSettingAppService.cs

@ -2,6 +2,7 @@
using LINGYUN.Abp.WeChat.Localization;
using LINGYUN.Abp.WeChat.MiniProgram.Settings;
using LINGYUN.Abp.WeChat.Official.Settings;
using LINGYUN.Abp.WeChat.Settings;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
@ -45,6 +46,13 @@ namespace LINGYUN.Abp.WeChat.SettingManagement
var settingGroups = new List<SettingGroupDto>();
var wechatSettingGroup = new SettingGroupDto(L["DisplayName:WeChat"], L["Description:WeChat"]);
var loginSetting = wechatSettingGroup.AddSetting(L["UserLogin"], L["UserLogin"]);
loginSetting.AddDetail(
SettingDefinitionManager.Get(WeChatSettingNames.EnabledQuickLogin),
StringLocalizerFactory,
await SettingManager.GetOrNullAsync(WeChatSettingNames.EnabledQuickLogin, providerName, providerKey),
ValueType.Boolean);
// 无权限返回空结果,直接报错的话,网关聚合会抛出异常
if (await PermissionChecker.IsGrantedAsync(WeChatSettingPermissionNames.Official))
{

4
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/AbpWeChatModule.cs

@ -7,6 +7,7 @@ using Volo.Abp.Features;
using Volo.Abp.Json;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Settings;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.WeChat
@ -14,7 +15,8 @@ namespace LINGYUN.Abp.WeChat
[DependsOn(
typeof(AbpCachingModule),
typeof(AbpFeaturesModule),
typeof(AbpJsonModule))]
typeof(AbpJsonModule),
typeof(AbpSettingsModule))]
public class AbpWeChatModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)

7
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Crypto/IWeChatCryptoService.cs

@ -0,0 +1,7 @@
namespace LINGYUN.Abp.WeChat.Crypto
{
public interface IWeChatCryptoService
{
string Decrypt(string encryptedData, string iv, string sessionKey);
}
}

36
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Crypto/WeChatCryptoService.cs

@ -0,0 +1,36 @@
using System;
using System.Security.Cryptography;
using System.Text;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.WeChat.Crypto
{
public class WeChatCryptoService : IWeChatCryptoService, ITransientDependency
{
public virtual string Decrypt(string encryptedData, string iv, string sessionKey)
{
using var aes = new AesCryptoServiceProvider();
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
// 对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充。
aes.Padding = PaddingMode.PKCS7;
//格式化待处理字符串
// 对称解密的目标密文为 Base64_Decode(encryptedData)。
byte[] byte_encryptedData = Convert.FromBase64String(encryptedData);
// 对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。
byte[] byte_iv = Convert.FromBase64String(iv);
// 对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。
byte[] byte_sessionKey = Convert.FromBase64String(sessionKey);
//根据设置好的数据生成解密器实例
using var transform = aes.CreateDecryptor(byte_iv, byte_sessionKey);
//解密
byte[] final = transform.TransformFinalBlock(byte_encryptedData, 0, byte_encryptedData.Length);
//生成结果
string result = Encoding.UTF8.GetString(final);
return result;
}
}
}

5
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Localization/Resources/en.json

@ -4,6 +4,9 @@
"Features:WeChat": "WeChat",
"Permission:WeChat": "WeChat",
"DisplayName:WeChat": "WeChat",
"Description:WeChat": "WeChat"
"Description:WeChat": "WeChat",
"UserLogin": "User Login",
"DisplayName:WeChat.EnabledQuickLogin": "Enabled Quick Login",
"Description:WeChat.EnabledQuickLogin": "Users can login directly with the code given by wx.login when they are not registered"
}
}

5
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Localization/Resources/zh-Hans.json

@ -4,6 +4,9 @@
"Features:WeChat": "微信开发",
"Permission:WeChat": "微信开发",
"DisplayName:WeChat": "微信开发平台",
"Description:WeChat": "微信开发平台"
"Description:WeChat": "微信开发平台",
"UserLogin": "用户登录",
"DisplayName:WeChat.EnabledQuickLogin": "启用快捷登录",
"Description:WeChat.EnabledQuickLogin": "用户可在未注册时通过 wx.login 得到的code直接登录"
}
}

8
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/OpenId/IWeChatOpenIdFinder.cs

@ -5,5 +5,13 @@ namespace LINGYUN.Abp.WeChat.OpenId
public interface IWeChatOpenIdFinder
{
Task<WeChatOpenId> FindAsync(string code, string appId, string appSecret);
/// <summary>
/// 获取当前登录用户OpenId
/// </summary>
/// <param name="appId">应用标识</param>
/// <returns></returns>
/// <exception cref="Volo.Abp.Authorization.AbpAuthorizationException">用户未登录时</exception>
/// <exception cref="Volo.Abp.AbpException">微信sessionKey过期时</exception>
Task<WeChatOpenId> FindAsync(string appId);
}
}

10
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/OpenId/WeChatOpenIdCacheItem.cs

@ -1,4 +1,6 @@
namespace LINGYUN.Abp.WeChat.OpenId
using System;
namespace LINGYUN.Abp.WeChat.OpenId
{
public class WeChatOpenIdCacheItem
{
@ -16,6 +18,12 @@
WeChatOpenId = weChatOpenId;
}
public static string CalculateCacheKey(string appId, Guid userId)
{
return "app:" + appId + ";user:" + userId.ToString("D");
}
public static string CalculateCacheKey(string appId, string code)
{
return "app:" + appId + ";code:" + code;

32
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/OpenId/WeChatOpenIdFinder.cs

@ -2,13 +2,16 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Authorization;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Users;
namespace LINGYUN.Abp.WeChat.OpenId
{
@ -18,23 +21,36 @@ namespace LINGYUN.Abp.WeChat.OpenId
{
public ILogger<WeChatOpenIdFinder> Logger { get; set; }
protected ICurrentTenant CurrentTenant { get; }
protected ICurrentUser CurrentUser { get; }
protected IHttpClientFactory HttpClientFactory { get; }
protected IJsonSerializer JsonSerializer { get; }
protected IDistributedCache<WeChatOpenIdCacheItem> Cache { get; }
public WeChatOpenIdFinder(
ICurrentUser currentUser,
ICurrentTenant currentTenant,
IJsonSerializer jsonSerializer,
IHttpClientFactory httpClientFactory,
IDistributedCache<WeChatOpenIdCacheItem> cache)
{
CurrentUser = currentUser;
CurrentTenant = currentTenant;
JsonSerializer = jsonSerializer;
HttpClientFactory = httpClientFactory;
Cache = cache;
Logger = NullLogger<WeChatOpenIdFinder>.Instance;
}
public virtual async Task<WeChatOpenId> FindAsync(string appId)
{
if (!CurrentUser.IsAuthenticated)
{
throw new AbpAuthorizationException("Try to get wechat information when the user is not logged in!");
}
var cacheKey = WeChatOpenIdCacheItem.CalculateCacheKey(appId, CurrentUser.Id.Value);
var openIdCache = await Cache.GetAsync(cacheKey);
return openIdCache?.WeChatOpenId ??
throw new AbpException("The wechat login session has expired. Use 'wx.login' result code to exchange the sessionKey");
}
public virtual async Task<WeChatOpenId> FindAsync(string code, string appId, string appSecret)
{
// TODO: 如果需要获取SessionKey的话呢,需要再以openid作为标识来缓存一下吗
@ -70,7 +86,8 @@ namespace LINGYUN.Abp.WeChat.OpenId
var response = await client.RequestWeChatOpenIdAsync(request);
var responseContent = await response.Content.ReadAsStringAsync();
var weChatOpenIdResponse = JsonSerializer.Deserialize<WeChatOpenIdResponse>(responseContent);
// 改为直接引用 Newtownsoft.Json
var weChatOpenIdResponse = JsonConvert.DeserializeObject<WeChatOpenIdResponse>(responseContent);
var weChatOpenId = weChatOpenIdResponse.ToWeChatOpenId();
cacheItem = new WeChatOpenIdCacheItem(code, weChatOpenId);
@ -87,6 +104,11 @@ namespace LINGYUN.Abp.WeChat.OpenId
await Cache.SetAsync(cacheKey, cacheItem, cacheOptions);
if (CurrentUser.IsAuthenticated)
{
await Cache.SetAsync(WeChatOpenIdCacheItem.CalculateCacheKey(appId, CurrentUser.Id.Value), cacheItem, cacheOptions);
}
Logger.LogDebug($"Finished setting the cache item: {cacheKey}");
return cacheItem;

28
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Settings/WeChatSettingDefinitionProvider.cs

@ -0,0 +1,28 @@
using LINGYUN.Abp.WeChat.Localization;
using Volo.Abp.Localization;
using Volo.Abp.Settings;
namespace LINGYUN.Abp.WeChat.Settings
{
public class WeChatSettingDefinitionProvider : SettingDefinitionProvider
{
public override void Define(ISettingDefinitionContext context)
{
context.Add(
new SettingDefinition(
WeChatSettingNames.EnabledQuickLogin,
// 默认启用
true.ToString(),
L("DisplayName:WeChat.EnabledQuickLogin"),
L("Description:WeChat.EnabledQuickLogin"),
isVisibleToClients: true,
isEncrypted: false)
);
}
protected ILocalizableString L(string name)
{
return LocalizableString.Create<WeChatResource>(name);
}
}
}

5
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Settings/WeChatSettingNames.cs

@ -3,5 +3,10 @@
public static class WeChatSettingNames
{
public const string Prefix = "Abp.WeChat";
/// <summary>
/// 启用快捷登录
/// 通过微信code登录时,如果没有注册用户信息且此配置启用时,直接创建新用户并关联openid
/// </summary>
public const string EnabledQuickLogin = Prefix + ".EnabledQuickLogin";
}
}

8
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Token/WeChatTokenProvider.cs

@ -1,13 +1,13 @@
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
namespace LINGYUN.Abp.WeChat.Token
{
@ -15,14 +15,11 @@ namespace LINGYUN.Abp.WeChat.Token
{
public ILogger<WeChatTokenProvider> Logger { get; set; }
protected IHttpClientFactory HttpClientFactory { get; }
protected IJsonSerializer JsonSerializer { get; }
protected IDistributedCache<WeChatTokenCacheItem> Cache { get; }
public WeChatTokenProvider(
IJsonSerializer jsonSerializer,
IHttpClientFactory httpClientFactory,
IDistributedCache<WeChatTokenCacheItem> cache)
{
JsonSerializer = jsonSerializer;
HttpClientFactory = httpClientFactory;
Cache = cache;
@ -70,7 +67,8 @@ namespace LINGYUN.Abp.WeChat.Token
var response = await client.RequestWeChatCodeTokenAsync(request, cancellationToken);
var responseContent = await response.Content.ReadAsStringAsync();
var weChatTokenResponse = JsonSerializer.Deserialize<WeChatTokenResponse>(responseContent);
// 改为直接引用 Newtownsoft.Json
var weChatTokenResponse = JsonConvert.DeserializeObject<WeChatTokenResponse>(responseContent);
var weChatToken = weChatTokenResponse.ToWeChatToken();
cacheItem = new WeChatTokenCacheItem(appId, weChatToken);

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

@ -7,6 +7,7 @@ using LINGYUN.Abp.EventBus.CAP;
using LINGYUN.Abp.ExceptionHandling;
using LINGYUN.Abp.ExceptionHandling.Notifications;
using LINGYUN.Abp.Hangfire.Storage.MySql;
using LINGYUN.Abp.Identity.WeChat;
using LINGYUN.Abp.IM.SignalR;
using LINGYUN.Abp.MessageService.EntityFrameworkCore;
using LINGYUN.Abp.MessageService.Localization;
@ -42,6 +43,7 @@ using Volo.Abp.BackgroundWorkers;
using Volo.Abp.Caching;
using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Identity.EntityFrameworkCore;
using Volo.Abp.Json;
using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.Localization;
@ -60,7 +62,9 @@ namespace LINGYUN.Abp.MessageService
typeof(AbpMessageServiceApplicationModule),
typeof(AbpMessageServiceHttpApiModule),
typeof(AbpAspNetCoreMultiTenancyModule),
typeof(AbpIdentityWeChatModule),
typeof(AbpMessageServiceEntityFrameworkCoreModule),
typeof(AbpIdentityEntityFrameworkCoreModule),
typeof(AbpTenantManagementEntityFrameworkCoreModule),
typeof(AbpSettingManagementEntityFrameworkCoreModule),
typeof(AbpPermissionManagementEntityFrameworkCoreModule),

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

@ -36,6 +36,7 @@
<PackageReference Include="Volo.Abp.AspNetCore.Authentication.JwtBearer" Version="4.4.0" />
<PackageReference Include="Volo.Abp.Autofac" Version="4.4.0" />
<PackageReference Include="Volo.Abp.EntityFrameworkCore.MySQL" Version="4.4.0" />
<PackageReference Include="Volo.Abp.Identity.EntityFrameworkCore" Version="4.4.0" />
<PackageReference Include="Volo.Abp.TenantManagement.EntityFrameworkCore" Version="4.4.0" />
<PackageReference Include="Volo.Abp.SettingManagement.EntityFrameworkCore" Version="4.4.0" />
<PackageReference Include="Volo.Abp.PermissionManagement.EntityFrameworkCore" Version="4.4.0" />
@ -57,6 +58,7 @@
<ProjectReference Include="..\..\..\modules\message\LINGYUN.Abp.MessageService.HttpApi\LINGYUN.Abp.MessageService.HttpApi.csproj" />
<ProjectReference Include="..\..\..\modules\tenants\LINGYUN.Abp.MultiTenancy.DbFinder\LINGYUN.Abp.MultiTenancy.DbFinder.csproj" />
<ProjectReference Include="..\..\..\modules\tenants\LINGYUN.Abp.MultiTenancy\LINGYUN.Abp.MultiTenancy.csproj" />
<ProjectReference Include="..\..\..\modules\wechat\LINGYUN.Abp.Identity.WeChat\LINGYUN.Abp.Identity.WeChat.csproj" />
<ProjectReference Include="..\..\..\modules\wechat\LINGYUN.Abp.Notifications.WeChat.MiniProgram\LINGYUN.Abp.Notifications.WeChat.MiniProgram.csproj" />
</ItemGroup>

Loading…
Cancel
Save