Browse Source

feat(open-api): 增加对于开放平台签名保护的实现

pull/414/head
cKey 4 years ago
parent
commit
0262da9c0e
  1. 33
      aspnet-core/LINGYUN.MicroService.Common.sln
  2. 18
      aspnet-core/LINGYUN.MicroService.Platform.sln
  3. 19
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi.Authorization/LINGYUN.Abp.OpenApi.Authorization.csproj
  4. 16
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi.Authorization/LINGYUN/Abp/OpenApi/Authorization/AbpOpenApiAuthorizationModule.cs
  5. 10
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi.Authorization/LINGYUN/Abp/OpenApi/Authorization/IOpenApiAuthorizationService.cs
  6. 24
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi.Authorization/LINGYUN/Abp/OpenApi/Authorization/OpenApiAuthorizationMiddleware.cs
  7. 234
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi.Authorization/LINGYUN/Abp/OpenApi/Authorization/OpenApiAuthorizationService.cs
  8. 12
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi.Authorization/Microsoft/AspNetCore/Builder/OpenApiAuthorizationApplicationBuilderExtensions.cs
  9. 25
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN.Abp.OpenApi.csproj
  10. 22
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/AbpOpenApiConsts.cs
  11. 40
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/AbpOpenApiModule.cs
  12. 34
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/AbpOpenApiOptions.cs
  13. 42
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/AppDescriptor.cs
  14. 12
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/ConfigurationStore/AbpDefaultAppKeyStoreOptions.cs
  15. 28
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/ConfigurationStore/DefaultAppKeyStore.cs
  16. 9
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/IAppKeyStore.cs
  17. 9
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/Localization/OpenApiResource.cs
  18. 11
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/Localization/Resources/en.json
  19. 11
      aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/Localization/Resources/zh-Hans.json
  20. 19
      aspnet-core/modules/open-api/OpenApi.Sdk/Microsoft/Extensions/DependencyInjection/ClientProxyServiceCollectionExtensions.cs
  21. 13
      aspnet-core/modules/open-api/OpenApi.Sdk/OpenApi.Sdk.csproj
  22. 25
      aspnet-core/modules/open-api/OpenApi.Sdk/OpenApi/ApiResponse.cs
  23. 45
      aspnet-core/modules/open-api/OpenApi.Sdk/OpenApi/ApiResponse`T.cs
  24. 159
      aspnet-core/modules/open-api/OpenApi.Sdk/OpenApi/ClientProxy.cs
  25. 22
      aspnet-core/modules/open-api/OpenApi.Sdk/OpenApi/IClientProxy.cs
  26. 19
      aspnet-core/modules/open-api/OpenApi.Sdk/OpenApi/IClientProxyExtensions.cs
  27. 25
      aspnet-core/modules/open-api/OpenApi.Sdk/System/StringMd5Extensions.cs
  28. 38
      aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/LINGYUN.Abp.OpenApi.Tests.csproj
  29. 33
      aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/LINGYUN/Abp/OpenApi/AbpOpenApiTestBase.cs
  30. 114
      aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/LINGYUN/Abp/OpenApi/AbpOpenApiTestModule.cs
  31. 28
      aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/LINGYUN/Abp/OpenApi/FakeAppKeyStore.cs
  32. 16
      aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/LINGYUN/Abp/OpenApi/FakeInvokeController.cs
  33. 75
      aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/LINGYUN/Abp/OpenApi/FakeInvokeController_Tests.cs
  34. 20
      aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/LINGYUN/Abp/OpenApi/Startup.cs
  35. 27
      aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/Properties/launchSettings.json

33
aspnet-core/LINGYUN.MicroService.Common.sln

@ -206,7 +206,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.AspNetCore.Mvc.
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Wrapper.Tests", "tests\LINGYUN.Abp.Wrapper.Tests\LINGYUN.Abp.Wrapper.Tests.csproj", "{31AED9ED-29BD-4F2F-8D3A-F00CBB9FC73C}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Wrapper.Tests", "tests\LINGYUN.Abp.Wrapper.Tests\LINGYUN.Abp.Wrapper.Tests.csproj", "{31AED9ED-29BD-4F2F-8D3A-F00CBB9FC73C}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.HttpClient.Wrapper", "modules\common\LINGYUN.Abp.HttpClient.Wrapper\LINGYUN.Abp.HttpClient.Wrapper.csproj", "{F6CABEE7-DE34-458A-8787-95DFB1DA4762}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.HttpClient.Wrapper", "modules\common\LINGYUN.Abp.HttpClient.Wrapper\LINGYUN.Abp.HttpClient.Wrapper.csproj", "{F6CABEE7-DE34-458A-8787-95DFB1DA4762}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "open-api", "open-api", "{8C688427-DD35-4F0B-86DA-6F536D3852D5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OpenApi", "modules\open-api\LINGYUN.Abp.OpenApi\LINGYUN.Abp.OpenApi.csproj", "{2C8A6B4C-D6B2-44FE-9EF5-EC7480D2A6B2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OpenApi.Authorization", "modules\open-api\LINGYUN.Abp.OpenApi.Authorization\LINGYUN.Abp.OpenApi.Authorization.csproj", "{3CE350AF-5574-46EC-8120-8542350AED20}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenApi.Sdk", "modules\open-api\OpenApi.Sdk\OpenApi.Sdk.csproj", "{108192F3-3780-423F-9871-A1BBE323413E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OpenApi.Tests", "tests\LINGYUN.Abp.OpenApi.Tests\LINGYUN.Abp.OpenApi.Tests.csproj", "{6C75799E-4B46-434D-BE1B-4AD71DF49686}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -542,6 +552,22 @@ Global
{F6CABEE7-DE34-458A-8787-95DFB1DA4762}.Debug|Any CPU.Build.0 = Debug|Any CPU {F6CABEE7-DE34-458A-8787-95DFB1DA4762}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F6CABEE7-DE34-458A-8787-95DFB1DA4762}.Release|Any CPU.ActiveCfg = Release|Any CPU {F6CABEE7-DE34-458A-8787-95DFB1DA4762}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F6CABEE7-DE34-458A-8787-95DFB1DA4762}.Release|Any CPU.Build.0 = Release|Any CPU {F6CABEE7-DE34-458A-8787-95DFB1DA4762}.Release|Any CPU.Build.0 = Release|Any CPU
{2C8A6B4C-D6B2-44FE-9EF5-EC7480D2A6B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2C8A6B4C-D6B2-44FE-9EF5-EC7480D2A6B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2C8A6B4C-D6B2-44FE-9EF5-EC7480D2A6B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2C8A6B4C-D6B2-44FE-9EF5-EC7480D2A6B2}.Release|Any CPU.Build.0 = Release|Any CPU
{3CE350AF-5574-46EC-8120-8542350AED20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3CE350AF-5574-46EC-8120-8542350AED20}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3CE350AF-5574-46EC-8120-8542350AED20}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3CE350AF-5574-46EC-8120-8542350AED20}.Release|Any CPU.Build.0 = Release|Any CPU
{108192F3-3780-423F-9871-A1BBE323413E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{108192F3-3780-423F-9871-A1BBE323413E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{108192F3-3780-423F-9871-A1BBE323413E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{108192F3-3780-423F-9871-A1BBE323413E}.Release|Any CPU.Build.0 = Release|Any CPU
{6C75799E-4B46-434D-BE1B-4AD71DF49686}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C75799E-4B46-434D-BE1B-4AD71DF49686}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C75799E-4B46-434D-BE1B-4AD71DF49686}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C75799E-4B46-434D-BE1B-4AD71DF49686}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -646,6 +672,11 @@ Global
{AE5E6DE8-FC02-4633-BA49-C4B8ABADB502} = {B86C21A4-73B7-471E-B73A-B4B905EC9435} {AE5E6DE8-FC02-4633-BA49-C4B8ABADB502} = {B86C21A4-73B7-471E-B73A-B4B905EC9435}
{31AED9ED-29BD-4F2F-8D3A-F00CBB9FC73C} = {B86C21A4-73B7-471E-B73A-B4B905EC9435} {31AED9ED-29BD-4F2F-8D3A-F00CBB9FC73C} = {B86C21A4-73B7-471E-B73A-B4B905EC9435}
{F6CABEE7-DE34-458A-8787-95DFB1DA4762} = {086BE5BE-8594-4DA7-8819-935FEF76DABD} {F6CABEE7-DE34-458A-8787-95DFB1DA4762} = {086BE5BE-8594-4DA7-8819-935FEF76DABD}
{8C688427-DD35-4F0B-86DA-6F536D3852D5} = {02EA4E78-5891-43BC-944F-3E52FEE032E4}
{2C8A6B4C-D6B2-44FE-9EF5-EC7480D2A6B2} = {8C688427-DD35-4F0B-86DA-6F536D3852D5}
{3CE350AF-5574-46EC-8120-8542350AED20} = {8C688427-DD35-4F0B-86DA-6F536D3852D5}
{108192F3-3780-423F-9871-A1BBE323413E} = {8C688427-DD35-4F0B-86DA-6F536D3852D5}
{6C75799E-4B46-434D-BE1B-4AD71DF49686} = {B86C21A4-73B7-471E-B73A-B4B905EC9435}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {06C707C6-02C0-411A-AD3B-2D0E13787CB8} SolutionGuid = {06C707C6-02C0-411A-AD3B-2D0E13787CB8}

18
aspnet-core/LINGYUN.MicroService.Platform.sln

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16 # Visual Studio Version 17
VisualStudioVersion = 16.0.30011.22 VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{15BDA03E-DE8E-46E4-96A8-CA3F2872E812}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{15BDA03E-DE8E-46E4-96A8-CA3F2872E812}"
EndProject EndProject
@ -92,6 +92,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "navigation", "navigation",
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.UI.Navigation", "modules\navigation\LINGYUN.Abp.UI.Navigation\LINGYUN.Abp.UI.Navigation.csproj", "{BE9131C0-7DD4-4032-A5F7-4B9D76EC16CF}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.UI.Navigation", "modules\navigation\LINGYUN.Abp.UI.Navigation\LINGYUN.Abp.UI.Navigation.csproj", "{BE9131C0-7DD4-4032-A5F7-4B9D76EC16CF}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Wrapper", "modules\common\LINGYUN.Abp.Wrapper\LINGYUN.Abp.Wrapper.csproj", "{36EFF070-3400-448E-A912-82930D6E1828}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.AspNetCore.Tests", "tests\LINGYUN.Abp.AspNetCore.Tests\LINGYUN.Abp.AspNetCore.Tests.csproj", "{3B363320-B679-4D29-B428-28311C576E2E}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -226,6 +230,14 @@ Global
{BE9131C0-7DD4-4032-A5F7-4B9D76EC16CF}.Debug|Any CPU.Build.0 = Debug|Any CPU {BE9131C0-7DD4-4032-A5F7-4B9D76EC16CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BE9131C0-7DD4-4032-A5F7-4B9D76EC16CF}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE9131C0-7DD4-4032-A5F7-4B9D76EC16CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BE9131C0-7DD4-4032-A5F7-4B9D76EC16CF}.Release|Any CPU.Build.0 = Release|Any CPU {BE9131C0-7DD4-4032-A5F7-4B9D76EC16CF}.Release|Any CPU.Build.0 = Release|Any CPU
{36EFF070-3400-448E-A912-82930D6E1828}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{36EFF070-3400-448E-A912-82930D6E1828}.Debug|Any CPU.Build.0 = Debug|Any CPU
{36EFF070-3400-448E-A912-82930D6E1828}.Release|Any CPU.ActiveCfg = Release|Any CPU
{36EFF070-3400-448E-A912-82930D6E1828}.Release|Any CPU.Build.0 = Release|Any CPU
{3B363320-B679-4D29-B428-28311C576E2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B363320-B679-4D29-B428-28311C576E2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B363320-B679-4D29-B428-28311C576E2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B363320-B679-4D29-B428-28311C576E2E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -271,6 +283,8 @@ Global
{2A69A38F-E98A-490D-BEAE-1BBBD87121DD} = {4096EC6A-EEAD-4E5B-B087-393D7A4E5874} {2A69A38F-E98A-490D-BEAE-1BBBD87121DD} = {4096EC6A-EEAD-4E5B-B087-393D7A4E5874}
{D61721B8-B0F7-4C3D-AD1B-44FBE81DFA79} = {15BDA03E-DE8E-46E4-96A8-CA3F2872E812} {D61721B8-B0F7-4C3D-AD1B-44FBE81DFA79} = {15BDA03E-DE8E-46E4-96A8-CA3F2872E812}
{BE9131C0-7DD4-4032-A5F7-4B9D76EC16CF} = {D61721B8-B0F7-4C3D-AD1B-44FBE81DFA79} {BE9131C0-7DD4-4032-A5F7-4B9D76EC16CF} = {D61721B8-B0F7-4C3D-AD1B-44FBE81DFA79}
{36EFF070-3400-448E-A912-82930D6E1828} = {265D5E44-682B-49BC-984A-BDD8CA45E60E}
{3B363320-B679-4D29-B428-28311C576E2E} = {CCEFF583-4EEE-433F-8568-9E64166B41FE}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {03D3B66F-8926-4C00-B7AB-A21761EC859E} SolutionGuid = {03D3B66F-8926-4C00-B7AB-A21761EC859E}

19
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi.Authorization/LINGYUN.Abp.OpenApi.Authorization.csproj

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

16
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi.Authorization/LINGYUN/Abp/OpenApi/Authorization/AbpOpenApiAuthorizationModule.cs

@ -0,0 +1,16 @@
using LINGYUN.Abp.Wrapper;
using Volo.Abp.AspNetCore;
using Volo.Abp.Modularity;
using Volo.Abp.Timing;
namespace LINGYUN.Abp.OpenApi.Authorization
{
[DependsOn(
typeof(AbpWrapperModule),
typeof(AbpTimingModule),
typeof(AbpOpenApiModule),
typeof(AbpAspNetCoreModule))]
public class AbpOpenApiAuthorizationModule : AbpModule
{
}
}

10
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi.Authorization/LINGYUN/Abp/OpenApi/Authorization/IOpenApiAuthorizationService.cs

@ -0,0 +1,10 @@
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
namespace LINGYUN.Abp.OpenApi.Authorization
{
public interface IOpenApiAuthorizationService
{
Task<bool> AuthorizeAsync(HttpContext httpContext);
}
}

24
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi.Authorization/LINGYUN/Abp/OpenApi/Authorization/OpenApiAuthorizationMiddleware.cs

@ -0,0 +1,24 @@
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.OpenApi.Authorization
{
public class OpenApiAuthorizationMiddleware : IMiddleware, ITransientDependency
{
private readonly IOpenApiAuthorizationService _authorizationService;
public OpenApiAuthorizationMiddleware(
IOpenApiAuthorizationService authorizationService)
{
_authorizationService = authorizationService;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
if (await _authorizationService.AuthorizeAsync(context))
{
await next(context);
}
}
}
}

234
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi.Authorization/LINGYUN/Abp/OpenApi/Authorization/OpenApiAuthorizationService.cs

@ -0,0 +1,234 @@
using LINGYUN.Abp.Wrapper;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Volo.Abp;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.AspNetCore.WebClientInfo;
using Volo.Abp.Clients;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http;
using Volo.Abp.Json;
namespace LINGYUN.Abp.OpenApi.Authorization
{
public class OpenApiAuthorizationService : IOpenApiAuthorizationService, ITransientDependency
{
private readonly IAppKeyStore _appKeyStore;
private readonly AbpOpenApiOptions _openApiOptions;
private readonly ICurrentClient _currentClient;
private readonly IWebClientInfoProvider _clientInfoProvider;
public OpenApiAuthorizationService(
IAppKeyStore appKeyStore,
ICurrentClient currentClient,
IWebClientInfoProvider clientInfoProvider,
IOptionsMonitor<AbpOpenApiOptions> options)
{
_appKeyStore = appKeyStore;
_currentClient = currentClient;
_clientInfoProvider = clientInfoProvider;
_openApiOptions = options.CurrentValue;
}
public virtual async Task<bool> AuthorizeAsync(HttpContext httpContext)
{
if (!_openApiOptions.IsEnabled)
{
return true;
}
if (_currentClient.IsAuthenticated &&
_openApiOptions.HasWhiteClient(_currentClient.Id))
{
return true;
}
if (!string.IsNullOrWhiteSpace(_clientInfoProvider.ClientIpAddress) &&
_openApiOptions.HasWhiteIpAddress(_clientInfoProvider.ClientIpAddress))
{
return true;
}
BusinessException exception;
if (!httpContext.Request.QueryString.HasValue)
{
exception = new BusinessException(
AbpOpenApiConsts.InvalidAccessWithAppKeyNotFound,
$"{AbpOpenApiConsts.AppKeyFieldName} Not Found",
$"{AbpOpenApiConsts.AppKeyFieldName} Not Found");
await Unauthorized(httpContext, exception);
return false;
}
httpContext.Request.Query.TryGetValue(AbpOpenApiConsts.AppKeyFieldName, out var appKey);
httpContext.Request.Query.TryGetValue(AbpOpenApiConsts.SignatureFieldName, out var sign);
httpContext.Request.Query.TryGetValue(AbpOpenApiConsts.TimeStampFieldName, out var timeStampString);
if (StringValues.IsNullOrEmpty(appKey))
{
exception = new BusinessException(
AbpOpenApiConsts.InvalidAccessWithAppKeyNotFound,
$"{AbpOpenApiConsts.AppKeyFieldName} Not Found",
$"{AbpOpenApiConsts.AppKeyFieldName} Not Found");
await Unauthorized(httpContext, exception);
return false;
}
if (StringValues.IsNullOrEmpty(sign))
{
exception = new BusinessException(
AbpOpenApiConsts.InvalidAccessWithSignNotFound,
$"{AbpOpenApiConsts.SignatureFieldName} Not Found",
$"{AbpOpenApiConsts.SignatureFieldName} Not Found");
await Unauthorized(httpContext, exception);
return false;
}
if (StringValues.IsNullOrEmpty(timeStampString))
{
exception = new BusinessException(
AbpOpenApiConsts.InvalidAccessWithTimestampNotFound,
$"{AbpOpenApiConsts.TimeStampFieldName} Not Found",
$"{AbpOpenApiConsts.TimeStampFieldName} Not Found");
await Unauthorized(httpContext, exception);
return false;
}
if (!long.TryParse(timeStampString.ToString(), out long timeStamp))
{
exception = new BusinessException(
AbpOpenApiConsts.InvalidAccessWithTimestamp,
"invalid timestamp",
"invalid timestamp");
await Unauthorized(httpContext, exception);
return false;
}
var appDescriptor = await _appKeyStore.FindAsync(appKey.ToString());
if (appDescriptor == null)
{
exception = new BusinessException(
AbpOpenApiConsts.InvalidAccessWithAppKey,
"invalid appKey",
"invalid appKey")
.WithData("AppKey", appKey.ToString());
await Unauthorized(httpContext, exception);
return false;
}
var queryDictionary = new Dictionary<string, string>();
var queryStringCollection = httpContext.Request.Query.OrderBy(q => q.Key);
foreach (var queryString in queryStringCollection)
{
if (queryString.Key.Equals(AbpOpenApiConsts.SignatureFieldName))
{
continue;
}
queryDictionary.Add(queryString.Key, queryString.Value.ToString());
}
var requiredSign = CalculationSignature(httpContext.Request.Path.Value, appDescriptor.AppSecret, queryDictionary);
if (!string.Equals(requiredSign, sign.ToString()))
{
exception = new BusinessException(
AbpOpenApiConsts.InvalidAccessWithSign,
"invalid signature",
"invalid signature");
await Unauthorized(httpContext, exception);
return false;
}
if (appDescriptor.SignLifetime.HasValue && appDescriptor.SignLifetime > 0)
{
var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
if ((now - timeStamp) / 1000 > appDescriptor.SignLifetime.Value)
{
exception = new BusinessException(
AbpOpenApiConsts.InvalidAccessWithTimestamp,
"session timed out or expired",
"session timed out or expired");
await Unauthorized(httpContext, exception);
return false;
}
}
return true;
}
protected virtual async Task Unauthorized(HttpContext context, BusinessException exception)
{
var errorInfoConverter = context.RequestServices.GetRequiredService<IExceptionToErrorInfoConverter>();
var errorInfo = errorInfoConverter.Convert(exception, false);
var exceptionWrapHandlerFactory = context.RequestServices.GetRequiredService<IExceptionWrapHandlerFactory>();
var exceptionWrapContext = new ExceptionWrapContext(
exception,
errorInfo,
context.RequestServices);
exceptionWrapHandlerFactory.CreateFor(exceptionWrapContext).Wrap(exceptionWrapContext);
if (context.Request.CanAccept(MimeTypes.Application.Json) ||
context.Request.IsAjax())
{
var wrapResult = new WrapResult(
exceptionWrapContext.ErrorInfo.Code,
exceptionWrapContext.ErrorInfo.Message,
exceptionWrapContext.ErrorInfo.Details);
var jsonSerializer = context.RequestServices.GetRequiredService<IJsonSerializer>();
context.Response.Headers.Add(AbpHttpWrapConsts.AbpWrapResult, "true");
context.Response.StatusCode = (int)HttpStatusCode.OK;
await context.Response.WriteAsync(jsonSerializer.Serialize(wrapResult));
return;
}
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
await context.Response.WriteAsync(errorInfo.Message);
}
private static string CalculationSignature(string url, string appKey, IDictionary<string, string> queryDictionary)
{
var queryString = BuildQuery(queryDictionary);
var encodeUrl = UrlEncode(string.Concat(url, "?", queryString, appKey));
return encodeUrl.ToMd5();
}
private static string BuildQuery(IDictionary<string, string> queryStringDictionary)
{
StringBuilder sb = new StringBuilder();
foreach (var queryString in queryStringDictionary)
{
sb.Append(queryString.Key)
.Append('=')
.Append(queryString.Value)
.Append('&');
}
sb.Remove(sb.Length - 1, 1);
return sb.ToString();
}
private static string UrlEncode(string str)
{
return HttpUtility.UrlEncode(str);
}
}
}

12
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi.Authorization/Microsoft/AspNetCore/Builder/OpenApiAuthorizationApplicationBuilderExtensions.cs

@ -0,0 +1,12 @@
using LINGYUN.Abp.OpenApi.Authorization;
namespace Microsoft.AspNetCore.Builder
{
public static class OpenApiAuthorizationApplicationBuilderExtensions
{
public static IApplicationBuilder UseOpenApiAuthorization(this IApplicationBuilder app)
{
return app.UseMiddleware<OpenApiAuthorizationMiddleware>();
}
}
}

25
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN.Abp.OpenApi.csproj

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<None Remove="LINGYUN\Abp\OpenApi\Localization\Resources\en.json" />
<None Remove="LINGYUN\Abp\OpenApi\Localization\Resources\zh-Hans.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="LINGYUN\Abp\OpenApi\Localization\Resources\en.json" />
<EmbeddedResource Include="LINGYUN\Abp\OpenApi\Localization\Resources\zh-Hans.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Security" Version="4.4.0" />
<PackageReference Include="Volo.Abp.Localization" Version="4.4.0" />
</ItemGroup>
</Project>

22
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/AbpOpenApiConsts.cs

@ -0,0 +1,22 @@
namespace LINGYUN.Abp.OpenApi
{
public static class AbpOpenApiConsts
{
public const string SecurityChecking = "_AbpOpenApiSecurityChecking";
public const string AppKeyFieldName = "appKey";
public const string SignatureFieldName = "sign";
public const string TimeStampFieldName = "t";
public const string KeyPrefix = "AbpOpenApi";
public const string InvalidAccessWithAppKey = KeyPrefix + ":9100";
public const string InvalidAccessWithAppKeyNotFound = KeyPrefix + ":9101";
public const string InvalidAccessWithSign = KeyPrefix + ":9110";
public const string InvalidAccessWithSignNotFound = KeyPrefix + ":9111";
public const string InvalidAccessWithTimestamp = KeyPrefix + ":9210";
public const string InvalidAccessWithTimestampNotFound = KeyPrefix + ":9211";
}
}

40
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/AbpOpenApiModule.cs

@ -0,0 +1,40 @@
using LINGYUN.Abp.OpenApi.Localization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
using Volo.Abp.Security;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.OpenApi
{
[DependsOn(
typeof(AbpSecurityModule),
typeof(AbpLocalizationModule))]
public class AbpOpenApiModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<AbpOpenApiOptions>(configuration.GetSection("OpenApi"));
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpOpenApiModule>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<OpenApiResource>()
.AddVirtualJson("/LINGYUN/Abp/OpenApi/Localization/Resources");
});
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace(AbpOpenApiConsts.KeyPrefix, typeof(OpenApiResource));
});
}
}
}

34
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/AbpOpenApiOptions.cs

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace LINGYUN.Abp.OpenApi
{
public class AbpOpenApiOptions
{
public bool IsEnabled { get; set; }
public string[] WhiteIpAddress { get; set; }
public string[] WhiteClient { get; set; }
public AbpOpenApiOptions()
{
IsEnabled = true;
WhiteIpAddress = new string[0];
WhiteClient = new string[0];
}
public bool HasWhiteIpAddress(string ipAddress)
{
return WhiteIpAddress?.Contains(ipAddress) == true;
}
public bool HasWhiteClient(string clientId)
{
if (clientId.IsNullOrWhiteSpace())
{
return false;
}
return WhiteClient?.Contains(clientId) == true;
}
}
}

42
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/AppDescriptor.cs

@ -0,0 +1,42 @@
namespace LINGYUN.Abp.OpenApi
{
public class AppDescriptor
{
/// <summary>
/// 应用名称
/// </summary>
public string AppName { get; set; }
/// <summary>
/// 应用标识
/// </summary>
public string AppKey { get; set; }
/// <summary>
/// 应用密钥
/// </summary>
public string AppSecret { get; set; }
/// <summary>
/// 应用token
/// </summary>
public string AppToken { get; set; }
/// <summary>
/// 签名有效时间
/// 单位: s
/// </summary>
public int? SignLifetime { get; set; }
public AppDescriptor() { }
public AppDescriptor(
string appName,
string appKey,
string appSecret,
string appToken = null,
int? signLifeTime = null)
{
AppName = appName;
AppKey = appKey;
AppSecret = appSecret;
AppToken = appToken;
SignLifetime = signLifeTime;
}
}
}

12
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/ConfigurationStore/AbpDefaultAppKeyStoreOptions.cs

@ -0,0 +1,12 @@
namespace LINGYUN.Abp.OpenApi.ConfigurationStore
{
public class AbpDefaultAppKeyStoreOptions
{
public AppDescriptor[] Apps { get; set; }
public AbpDefaultAppKeyStoreOptions()
{
Apps = new AppDescriptor[0];
}
}
}

28
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/ConfigurationStore/DefaultAppKeyStore.cs

@ -0,0 +1,28 @@
using Microsoft.Extensions.Options;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.OpenApi.ConfigurationStore
{
[Dependency(TryRegister = true)]
public class DefaultAppKeyStore : IAppKeyStore, ITransientDependency
{
private readonly AbpDefaultAppKeyStoreOptions _options;
public DefaultAppKeyStore(IOptionsMonitor<AbpDefaultAppKeyStoreOptions> options)
{
_options = options.CurrentValue;
}
public Task<AppDescriptor> FindAsync(string appKey)
{
return Task.FromResult(Find(appKey));
}
public AppDescriptor Find(string appKey)
{
return _options.Apps?.FirstOrDefault(t => t.AppKey == appKey);
}
}
}

9
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/IAppKeyStore.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.OpenApi
{
public interface IAppKeyStore
{
Task<AppDescriptor> FindAsync(string appKey);
}
}

9
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/Localization/OpenApiResource.cs

@ -0,0 +1,9 @@
using Volo.Abp.Localization;
namespace LINGYUN.Abp.OpenApi.Localization
{
[LocalizationResourceName("OpenApi")]
public class OpenApiResource
{
}
}

11
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/Localization/Resources/en.json

@ -0,0 +1,11 @@
{
"culture": "en",
"texts": {
"AbpOpenApi:9100": "Invalid appKey {AppKey}.",
"AbpOpenApi:9101": "appKey not found.",
"AbpOpenApi:9110": "Invalid sign.",
"AbpOpenApi:9111": "sign not found.",
"AbpOpenApi:9210": "Request timed out or the session expired.",
"AbpOpenApi:9211": "timestamp not found."
}
}

11
aspnet-core/modules/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/Localization/Resources/zh-Hans.json

@ -0,0 +1,11 @@
{
"culture": "zh-Hans",
"texts": {
"AbpOpenApi:9100": "无效的应用标识 {AppKey}.",
"AbpOpenApi:9101": "未携带应用标识(appKey).",
"AbpOpenApi:9110": "无效的签名 sign.",
"AbpOpenApi:9111": "未携带签名(sign).",
"AbpOpenApi:9210": "请求超时或会话已过期.",
"AbpOpenApi:9211": "未携带时间戳标识."
}
}

19
aspnet-core/modules/open-api/OpenApi.Sdk/Microsoft/Extensions/DependencyInjection/ClientProxyServiceCollectionExtensions.cs

@ -0,0 +1,19 @@
using OpenApi;
using System;
namespace Microsoft.Extensions.DependencyInjection
{
public static class ClientProxyServiceCollectionExtensions
{
public static IServiceCollection AddClientProxy(this IServiceCollection services, string serverUrl)
{
services.AddHttpClient("opensdk", options =>
{
options.BaseAddress = new Uri(serverUrl);
});
services.AddSingleton<IClientProxy, ClientProxy>();
return services;
}
}
}

13
aspnet-core/modules/open-api/OpenApi.Sdk/OpenApi.Sdk.csproj

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>

25
aspnet-core/modules/open-api/OpenApi.Sdk/OpenApi/ApiResponse.cs

@ -0,0 +1,25 @@
using System;
namespace OpenApi
{
[Serializable]
public class ApiResponse : ApiResponse<object>
{
public ApiResponse() { }
public ApiResponse(
string code,
string message,
string details = null)
: base(code, message, details)
{
}
public ApiResponse(
string code,
object result,
string message = "OK")
: base(code, result, message)
{
}
}
}

45
aspnet-core/modules/open-api/OpenApi.Sdk/OpenApi/ApiResponse`T.cs

@ -0,0 +1,45 @@
using System;
namespace OpenApi
{
[Serializable]
public class ApiResponse<TResult>
{
/// <summary>
/// 错误代码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 错误提示消息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 补充消息
/// </summary>
public string Details { get; set; }
/// <summary>
/// 返回值
/// </summary>
public TResult Result { get; set; }
public ApiResponse() { }
public ApiResponse(
string code,
string message,
string details = null)
{
Code = code;
Message = message;
Details = details;
}
public ApiResponse(
string code,
TResult result,
string message = "OK")
{
Code = code;
Result = result;
Message = message;
}
}
}

159
aspnet-core/modules/open-api/OpenApi.Sdk/OpenApi/ClientProxy.cs

@ -0,0 +1,159 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace OpenApi
{
public class ClientProxy : IClientProxy
{
private readonly IHttpClientFactory _httpClientFactory;
public ClientProxy(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public virtual async Task<ApiResponse<TResult>> DeleteAsync<TResult>(string url, string appKey, string appSecret)
{
return await RequestAsync<TResult>(url, appKey, appSecret, HttpMethod.Delete);
}
public virtual async Task<ApiResponse<TResult>> GetAsync<TResult>(string url, string appKey, string appSecret)
{
return await RequestAsync<TResult>(url, appKey, appSecret, HttpMethod.Get);
}
public virtual async Task<ApiResponse<TResult>> PostAsync<TRequest, TResult>(string url, string appKey, string appSecret, TRequest request)
{
return await RequestAsync<TRequest, TResult>(url, appKey, appSecret, request, HttpMethod.Post);
}
public virtual async Task<ApiResponse<TResult>> PutAsync<TRequest, TResult>(string url, string appKey, string appSecret, TRequest request)
{
return await RequestAsync<TRequest, TResult>(url, appKey, appSecret, request, HttpMethod.Put);
}
public virtual async Task<ApiResponse<TResult>> RequestAsync<TResult>(string url, string appKey, string appSecret, HttpMethod httpMethod)
{
return await RequestAsync<object, TResult>(url, appKey, appSecret, null, httpMethod);
}
public virtual async Task<ApiResponse<TResult>> RequestAsync<TRequest, TResult>(string url, string appKey, string appSecret, TRequest request, HttpMethod httpMethod)
{
// 构建请求客户端
var client = _httpClientFactory.CreateClient("opensdk");
return await RequestAsync<TRequest, TResult>(client, url, appKey, appSecret, request, httpMethod);
}
public virtual async Task<ApiResponse<TResult>> RequestAsync<TRequest, TResult>(HttpClient client, string url, string appKey, string appSecret, TRequest request, HttpMethod httpMethod)
{
// UTC时间戳
var timeStamp = GetUtcTimeStampString();
// 取出api地址
var baseUrl = url.Split('?')[0];
// 组装请求参数
var requestUrl = string.Concat(
url,
url.Contains('?') ? "&" : "?",
"appKey=",
appKey,
"&t=",
timeStamp);
var quertString = ReverseQueryString(requestUrl);
// 对请求参数签名
var sign = CalculationSignature(baseUrl, appSecret, quertString);
// 签名随请求传递
quertString.Add("sign", sign);
// 重新拼接请求参数
requestUrl = string.Concat(baseUrl, "?", BuildQuery(quertString));
// 构建请求体
var requestMessage = new HttpRequestMessage(httpMethod, requestUrl);
if (request != null)
{
// Request Payload
requestMessage.Content = new StringContent(JsonConvert.SerializeObject(request));
}
// 返回中文错误提示
requestMessage.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(CultureInfo.CurrentUICulture.Name));
// 返回错误消息可序列化
requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// 序列化响应
var response = await client.SendAsync(requestMessage);
var stringContent = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<ApiResponse<TResult>>(stringContent);
}
protected virtual string GetUtcTimeStampString()
{
return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
}
private static IDictionary<string, string> ReverseQueryString(string requestUri)
{
if (!requestUri.Contains("?"))
{
throw new Exception("查询路径格式不合法");
}
var queryString = requestUri.Split('?')[1];
// 按照首字母排序
var paramters = queryString.Split('&').OrderBy(p => p);
var queryDic = new Dictionary<string, string>();
foreach (var parm in paramters)
{
var thisParams = parm.Split('=');
if (thisParams.Length == 0)
{
continue;
}
queryDic.Add(thisParams[0], thisParams.Length > 0 ? thisParams[1] : "");
}
// 返回参数列表
return queryDic;
}
private static string CalculationSignature(string url, string appSecret, IDictionary<string, string> queryDictionary)
{
var queryString = BuildQuery(queryDictionary);
var requestUrl = string.Concat(
url,
url.Contains('?') ? "" : "?",
queryString,
appSecret);
var encodeUrl = UrlEncode(requestUrl);
return encodeUrl.ToMd5();
}
private static string BuildQuery(IDictionary<string, string> queryStringDictionary)
{
StringBuilder sb = new StringBuilder();
foreach (var queryString in queryStringDictionary)
{
sb.Append(queryString.Key)
.Append('=')
.Append(queryString.Value)
.Append('&');
}
sb.Remove(sb.Length - 1, 1);
return sb.ToString();
}
private static string UrlEncode(string str)
{
return HttpUtility.UrlEncode(str);
}
}
}

22
aspnet-core/modules/open-api/OpenApi.Sdk/OpenApi/IClientProxy.cs

@ -0,0 +1,22 @@
using System.Net.Http;
using System.Threading.Tasks;
namespace OpenApi
{
public interface IClientProxy
{
Task<ApiResponse<TResult>> GetAsync<TResult>(string url, string appKey, string appSecret);
Task<ApiResponse<TResult>> DeleteAsync<TResult>(string url, string appKey, string appSecret);
Task<ApiResponse<TResult>> PutAsync<TRequest, TResult>(string url, string appKey, string appSecret, TRequest request);
Task<ApiResponse<TResult>> PostAsync<TRequest, TResult>(string url, string appKey, string appSecret, TRequest request);
Task<ApiResponse<TResult>> RequestAsync<TResult>(string url, string appKey, string appSecret, HttpMethod httpMethod);
Task<ApiResponse<TResult>> RequestAsync<TRequest, TResult>(string url, string appKey, string appSecret, TRequest request, HttpMethod httpMethod);
Task<ApiResponse<TResult>> RequestAsync<TRequest, TResult>(HttpClient client, string url, string appKey, string appSecret, TRequest request, HttpMethod httpMethod);
}
}

19
aspnet-core/modules/open-api/OpenApi.Sdk/OpenApi/IClientProxyExtensions.cs

@ -0,0 +1,19 @@
using System.Net.Http;
using System.Threading.Tasks;
namespace OpenApi
{
public static class IClientProxyExtensions
{
public static async Task<ApiResponse<TResult>> RequestAsync<TResult>(
this IClientProxy proxy,
HttpClient client,
string url,
string appKey,
string appSecret,
HttpMethod httpMethod)
{
return await proxy.RequestAsync<object, TResult>(client, url, appKey, appSecret, null, httpMethod);
}
}
}

25
aspnet-core/modules/open-api/OpenApi.Sdk/System/StringMd5Extensions.cs

@ -0,0 +1,25 @@
using System.Security.Cryptography;
using System.Text;
namespace System
{
internal static class StringMd5Extensions
{
public static string ToMd5(this string str)
{
using (MD5 mD = MD5.Create())
{
byte[] bytes = Encoding.UTF8.GetBytes(str);
byte[] array = mD.ComputeHash(bytes);
StringBuilder stringBuilder = new StringBuilder();
byte[] array2 = array;
foreach (byte b in array2)
{
stringBuilder.Append(b.ToString("X2"));
}
return stringBuilder.ToString();
}
}
}
}

38
aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/LINGYUN.Abp.OpenApi.Tests.csproj

@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace />
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<Compile Remove="LINGYUN\Abp\AspNetCore\**" />
<Content Remove="LINGYUN\Abp\AspNetCore\**" />
<EmbeddedResource Remove="LINGYUN\Abp\AspNetCore\**" />
<None Remove="LINGYUN\Abp\AspNetCore\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="4.4.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\modules\mvc\LINGYUN.Abp.AspNetCore.Mvc.Wrapper\LINGYUN.Abp.AspNetCore.Mvc.Wrapper.csproj" />
<ProjectReference Include="..\..\modules\open-api\LINGYUN.Abp.OpenApi.Authorization\LINGYUN.Abp.OpenApi.Authorization.csproj" />
<ProjectReference Include="..\..\modules\open-api\OpenApi.Sdk\OpenApi.Sdk.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.AspNetCore.Tests\LINGYUN.Abp.AspNetCore.Tests.csproj" />
</ItemGroup>
</Project>

33
aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/LINGYUN/Abp/OpenApi/AbpOpenApiTestBase.cs

@ -0,0 +1,33 @@
using LINGYUN.Abp.AspNetCore;
using Microsoft.Extensions.Hosting;
using System.IO;
using System.Linq;
namespace LINGYUN.Abp.OpenApi
{
public abstract class AbpOpenApiTestBase : AbpAspNetCoreTestBase<Startup>
{
protected override IHostBuilder CreateHostBuilder()
{
return base.CreateHostBuilder();
}
private static string CalculateContentRootPath(string projectFileName, string contentPath)
{
var currentDirectory = Directory.GetCurrentDirectory();
while (!ContainsFile(currentDirectory, projectFileName))
{
currentDirectory = new DirectoryInfo(currentDirectory).Parent.FullName;
}
return Path.Combine(currentDirectory, contentPath);
}
private static bool ContainsFile(string currentDirectory, string projectFileName)
{
return Directory
.GetFiles(currentDirectory, "*.*", SearchOption.TopDirectoryOnly)
.Any(f => Path.GetFileName(f) == projectFileName);
}
}
}

114
aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/LINGYUN/Abp/OpenApi/AbpOpenApiTestModule.cs

@ -0,0 +1,114 @@
using LINGYUN.Abp.AspNetCore.Mvc.Wrapper;
using LINGYUN.Abp.OpenApi.Authorization;
using LINGYUN.Abp.OpenApi.Localization;
using Localization.Resources.AbpUi;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.DependencyInjection;
using OpenApi;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Security.Claims;
using Volo.Abp.AspNetCore.TestBase;
using Volo.Abp.Autofac;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
using Volo.Abp.Validation.Localization;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.OpenApi
{
[DependsOn(
typeof(AbpOpenApiAuthorizationModule),
typeof(AbpAspNetCoreTestBaseModule),
typeof(AbpAspNetCoreMvcWrapperModule),
typeof(AbpAutofacModule)
)]
public class AbpOpenApiTestModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
{
options.AddAssemblyResource(
typeof(OpenApiResource),
typeof(AbpOpenApiTestModule).Assembly
);
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
// 测试环境不需要主机地址
context.Services.AddHttpClient("opensdk");
context.Services.AddSingleton<IClientProxy, ClientProxy>();
context.Services.AddAuthentication(options =>
{
options.DefaultChallengeScheme = "Bearer";
options.DefaultForbidScheme = "Cookie";
}).AddCookie("Cookie").AddJwtBearer("Bearer", _ => { });
context.Services.AddAuthorization(options =>
{
});
Configure<AbpAspNetCoreMvcOptions>(options =>
{
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpOpenApiTestModule>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<OpenApiResource>()
.AddBaseTypes(
typeof(AbpUiResource),
typeof(AbpValidationResource)
).AddVirtualJson("/LINGYUN/Abp/AspNetCore/Mvc/Localization/Resources");
options.Languages.Add(new LanguageInfo("en", "en", "English"));
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
});
Configure<RazorPagesOptions>(options =>
{
options.RootDirectory = "/LINGYUN/Abp/AspNetCore/Mvc";
});
Configure<AbpClaimsMapOptions>(options =>
{
});
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.ErrorCodeNamespaceMappings.Add("Test", typeof(OpenApiResource));
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
app.UseCorrelationId();
app.UseStaticFiles();
app.UseAbpRequestLocalization();
app.UseAbpSecurityHeaders();
app.UseRouting();
app.UseAbpClaimsMap();
app.UseAuthentication();
app.UseOpenApiAuthorization();
app.UseAuthorization();
app.UseAuditing();
app.UseUnitOfWork();
app.UseConfiguredEndpoints();
}
}
}

28
aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/LINGYUN/Abp/OpenApi/FakeAppKeyStore.cs

@ -0,0 +1,28 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.OpenApi
{
[Dependency(ReplaceServices = true)]
public class FakeAppKeyStore : IAppKeyStore, ISingletonDependency
{
public readonly static AppDescriptor AppDescriptor =
new AppDescriptor(
"TEST",
Guid.NewGuid().ToString("N"),
Guid.NewGuid().ToString("N"),
signLifeTime: 5);
public virtual Task<AppDescriptor> FindAsync(string appKey)
{
AppDescriptor app = null;
if (AppDescriptor.AppKey.Equals(appKey))
{
app = AppDescriptor;
}
return Task.FromResult(app);
}
}
}

16
aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/LINGYUN/Abp/OpenApi/FakeInvokeController.cs

@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc;
namespace LINGYUN.Abp.OpenApi
{
[Route("/api/invoke")]
public class FakeInvokeController : AbpController
{
[HttpGet]
public Task<string> Index()
{
return Task.FromResult("Hello");
}
}
}

75
aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/LINGYUN/Abp/OpenApi/FakeInvokeController_Tests.cs

@ -0,0 +1,75 @@
using OpenApi;
using Shouldly;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Volo.Abp.Localization;
using Xunit;
namespace LINGYUN.Abp.OpenApi
{
public class FakeInvokeController_Tests : AbpOpenApiTestBase
{
private readonly IClientProxy _clientProxy;
public FakeInvokeController_Tests()
{
_clientProxy = GetRequiredService<IClientProxy>();
}
[Fact]
public async Task Should_Invoke_Controller_And_Result_With_Hello()
{
var result = await _clientProxy.RequestAsync<string>(
Client,
"/api/invoke",
FakeAppKeyStore.AppDescriptor.AppKey,
FakeAppKeyStore.AppDescriptor.AppSecret,
HttpMethod.Get);
result.Code.ShouldBe("0");
result.Message.ShouldBe("OK");
result.Result.ShouldBe("Hello");
result.Details.ShouldBeNull();
}
[Fact]
public async Task Should_Invoke_Controller_With_Invalid_App_Key()
{
using (CultureHelper.Use("en"))
{
var appKey = Guid.NewGuid().ToString("N");
var result = await _clientProxy.RequestAsync<string>(
Client,
"/api/invoke",
appKey,
Guid.NewGuid().ToString("N"),
HttpMethod.Get);
result.Code.ShouldBe("9100");
result.Message.ShouldBe($"Invalid appKey {appKey}.");
result.Result.ShouldBeNull();
result.Details.ShouldBeNull();
}
}
[Fact]
public async Task Should_Invoke_Controller_With_Invalid_Signature()
{
using (CultureHelper.Use("en"))
{
var result = await _clientProxy.RequestAsync<string>(
Client,
"/api/invoke",
FakeAppKeyStore.AppDescriptor.AppKey,
Guid.NewGuid().ToString("N"),
HttpMethod.Get);
result.Code.ShouldBe("9110");
result.Message.ShouldBe("Invalid sign.");
result.Result.ShouldBeNull();
result.Details.ShouldBeNull();
}
}
}
}

20
aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/LINGYUN/Abp/OpenApi/Startup.cs

@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace LINGYUN.Abp.OpenApi
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddApplication<AbpOpenApiTestModule>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
app.InitializeApplication();
}
}
}

27
aspnet-core/tests/LINGYUN.Abp.OpenApi.Tests/Properties/launchSettings.json

@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:49160/",
"sslPort": 44396
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"LINGYUN.Abp.OpenApi.Tests": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}
Loading…
Cancel
Save