From 6be80447b4da0d7507490965bcf1649a6ed0255f Mon Sep 17 00:00:00 2001 From: cKey <35512826+colinin@users.noreply.github.com> Date: Fri, 19 Jun 2020 11:59:46 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=98=BF=E9=87=8C=E4=BA=91?= =?UTF-8?q?=E5=85=AC=E5=85=B1=E8=AE=BF=E9=97=AE=E6=A8=A1=E5=9D=97;?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=98=BF=E9=87=8C=E4=BA=91Oss=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=E5=AD=98=E5=82=A8Abp=E6=89=A9=E5=B1=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LINGYUN.Abp.Aliyun.Authorization.csproj | 12 ++ .../AbpAliyunAuthorizationModule.cs | 15 ++ .../Aliyun/Authorization/AbpAliyunOptions.cs | 14 ++ .../LINGYUN.Abp.BlobStoring.Aliyun.csproj | 25 +++ .../Aliyun/AbpBlobStoringAliyunModule.cs | 35 +++++ ...yunBlobContainerConfigurationExtensions.cs | 25 +++ .../BlobStoring/Aliyun/AliyunBlobProvider.cs | 148 ++++++++++++++++++ .../Aliyun/AliyunBlobProviderConfiguration.cs | 62 ++++++++ .../AliyunBlobProviderConfigurationNames.cs | 22 +++ .../Aliyun/DefaultAliyunBlobNameCalculator.cs | 24 +++ .../Aliyun/IAliyunBlobNameCalculator.cs | 9 ++ .../LINGYUN.Abp.Sms.Aliyun.csproj | 4 + .../Abp/Sms/Aliyun/AbpAliyunSmsModule.cs | 6 +- .../LINYUN/Abp/Sms/Aliyun/AliyunSmsOptions.cs | 8 - .../LINYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs | 9 +- ...INGYUN.Abp.BlobStoring.Aliyun.Tests.csproj | 18 +++ .../Aliyun/AbpBlobStoringAliyunTestBase.cs | 9 ++ .../Aliyun/AbpBlobStoringAliyunTestModule.cs | 56 +++++++ .../BlobStoring/Aliyun/BlobContainer_Tests.cs | 99 ++++++++++++ .../BlobStoring/TestObjects/TestContainer1.cs | 6 + .../LINGYUN.Abp.TestsBase.csproj | 21 +++ .../LINGYUN/Abp/Tests/AbpTestsBase.cs | 59 +++++++ .../LINGYUN/Abp/Tests/AbpTestsBaseModule.cs | 21 +++ 23 files changed, 695 insertions(+), 12 deletions(-) create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN.Abp.Aliyun.Authorization.csproj create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN/Abp/Aliyun/Authorization/AbpAliyunAuthorizationModule.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN/Abp/Aliyun/Authorization/AbpAliyunOptions.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobContainerConfigurationExtensions.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/DefaultAliyunBlobNameCalculator.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/IAliyunBlobNameCalculator.cs create mode 100644 aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests.csproj create mode 100644 aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestBase.cs create mode 100644 aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestModule.cs create mode 100644 aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/BlobContainer_Tests.cs create mode 100644 aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/TestObjects/TestContainer1.cs create mode 100644 aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN.Abp.TestsBase.csproj create mode 100644 aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN/Abp/Tests/AbpTestsBase.cs create mode 100644 aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN/Abp/Tests/AbpTestsBaseModule.cs diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN.Abp.Aliyun.Authorization.csproj b/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN.Abp.Aliyun.Authorization.csproj new file mode 100644 index 000000000..8be61f7bf --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN.Abp.Aliyun.Authorization.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.0 + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN/Abp/Aliyun/Authorization/AbpAliyunAuthorizationModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN/Abp/Aliyun/Authorization/AbpAliyunAuthorizationModule.cs new file mode 100644 index 000000000..1dc254e80 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN/Abp/Aliyun/Authorization/AbpAliyunAuthorizationModule.cs @@ -0,0 +1,15 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Aliyun.Authorization +{ + public class AbpAliyunAuthorizationModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + Configure(configuration.GetSection("Aliyun:Auth")); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN/Abp/Aliyun/Authorization/AbpAliyunOptions.cs b/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN/Abp/Aliyun/Authorization/AbpAliyunOptions.cs new file mode 100644 index 000000000..7d90f6da9 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN/Abp/Aliyun/Authorization/AbpAliyunOptions.cs @@ -0,0 +1,14 @@ +namespace LINGYUN.Abp.Aliyun.Authorization +{ + public class AbpAliyunOptions + { + /// + /// 访问标识 + /// + public string AccessKeyId { get; set; } + /// + /// 访问密钥 + /// + public string AccessKeySecret { get; set; } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj new file mode 100644 index 000000000..92d56b011 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj @@ -0,0 +1,25 @@ + + + + netstandard2.0 + + true + 2.9.0 + LINGYUN + 阿里云Oss对象存储Abp集成 + + + + D:\LocalNuget + + + + + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs new file mode 100644 index 000000000..4e77d7030 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs @@ -0,0 +1,35 @@ +using LINGYUN.Abp.Aliyun.Authorization; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System.Collections.Generic; +using Volo.Abp.BlobStoring; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + [DependsOn( + typeof(AbpBlobStoringModule), + typeof(AbpAliyunAuthorizationModule))] + public class AbpBlobStoringAliyunModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + Configure(options => + { + context.Services.ExecutePreConfiguredActions(options); + options.Containers.ConfigureAll((containerName, containerConfiguration) => + { + containerConfiguration.UseAliyun(aliyun => + { + aliyun.BucketName = configuration[AliyunBlobProviderConfigurationNames.BucketName]; + aliyun.CreateBucketIfNotExists = configuration.GetSection(AliyunBlobProviderConfigurationNames.CreateBucketIfNotExists).Get(); + aliyun.CreateBucketReferer = configuration.GetSection(AliyunBlobProviderConfigurationNames.CreateBucketReferer).Get>(); + aliyun.Endpoint = configuration[AliyunBlobProviderConfigurationNames.Endpoint]; + }); + }); + }); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobContainerConfigurationExtensions.cs b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobContainerConfigurationExtensions.cs new file mode 100644 index 000000000..6a73a482a --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobContainerConfigurationExtensions.cs @@ -0,0 +1,25 @@ +using System; +using Volo.Abp.BlobStoring; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public static class AliyunBlobContainerConfigurationExtensions + { + public static AliyunBlobProviderConfiguration GetAliyunConfiguration( + this BlobContainerConfiguration containerConfiguration) + { + return new AliyunBlobProviderConfiguration(containerConfiguration); + } + + public static BlobContainerConfiguration UseAliyun( + this BlobContainerConfiguration containerConfiguration, + Action aliyunConfigureAction) + { + containerConfiguration.ProviderType = typeof(AliyunBlobProvider); + + aliyunConfigureAction(new AliyunBlobProviderConfiguration(containerConfiguration)); + + return containerConfiguration; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs new file mode 100644 index 000000000..c076c3843 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs @@ -0,0 +1,148 @@ +using Aliyun.OSS; +using LINGYUN.Abp.Aliyun.Authorization; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp.BlobStoring; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public class AliyunBlobProvider : BlobProviderBase, ITransientDependency + { + protected AbpAliyunOptions Options { get; } + protected IAliyunBlobNameCalculator AliyunBlobNameCalculator { get; } + + public AliyunBlobProvider( + IOptions options, + IAliyunBlobNameCalculator aliyunBlobNameCalculator) + { + Options = options.Value; + AliyunBlobNameCalculator = aliyunBlobNameCalculator; + } + + public override async Task DeleteAsync(BlobProviderDeleteArgs args) + { + var blobName = AliyunBlobNameCalculator.Calculate(args); + + if (await BlobExistsAsync(args, blobName)) + { + var ossClient = GetOssClient(args); + + return ossClient.DeleteObject(GetBucketName(args), blobName).DeleteMarker; + } + + return false; + } + + public override async Task ExistsAsync(BlobProviderExistsArgs args) + { + var blobName = AliyunBlobNameCalculator.Calculate(args); + + return await BlobExistsAsync(args, blobName); + } + + public override async Task GetOrNullAsync(BlobProviderGetArgs args) + { + var blobName = AliyunBlobNameCalculator.Calculate(args); + + if (!await BlobExistsAsync(args, blobName)) + { + return null; + } + + var ossClient = GetOssClient(args); + var ossObject = ossClient.GetObject(GetBucketName(args), blobName); + // 返回原始结果才会调用 Stream.ReadAsync(); + return ossObject.Content; + } + + public override async Task SaveAsync(BlobProviderSaveArgs args) + { + var blobName = AliyunBlobNameCalculator.Calculate(args); + var configuration = args.Configuration.GetAliyunConfiguration(); + if (!args.OverrideExisting && await BlobExistsAsync(args, blobName)) + { + throw new BlobAlreadyExistsException($"Saving BLOB '{args.BlobName}' does already exists in the bucketName '{GetBucketName(args)}'! Set {nameof(args.OverrideExisting)} if it should be overwritten."); + } + + if (configuration.CreateBucketIfNotExists) + { + await CreateBucketIfNotExists(args, configuration.CreateBucketReferer); + } + + var bucketName = GetBucketName(args); + var ossClient = GetOssClient(args); + + if (args.OverrideExisting && await BlobExistsAsync(args, blobName)) + { + ossClient.DeleteObject(bucketName, blobName); + } + + ossClient.PutObject(bucketName, blobName, args.BlobStream); + } + + protected virtual OssClient GetOssClient(BlobProviderArgs args) + { + var configuration = args.Configuration.GetAliyunConfiguration(); + var ossClient = new OssClient(configuration.Endpoint, Options.AccessKeyId, Options.AccessKeySecret); + return ossClient; + } + + protected virtual async Task CreateBucketIfNotExists(BlobProviderArgs args, IList refererList = null) + { + if (! await BucketExistsAsync(args)) + { + var ossClient = GetOssClient(args); + var bucketName = GetBucketName(args); + + var request = new CreateBucketRequest(bucketName) + { + //设置存储空间访问权限ACL。 + ACL = CannedAccessControlList.PublicReadWrite, + //设置数据容灾类型。 + DataRedundancyType = DataRedundancyType.ZRS + }; + + ossClient.CreateBucket(request); + + if (refererList != null && refererList.Count > 0) + { + var srq = new SetBucketRefererRequest(bucketName, refererList); + ossClient.SetBucketReferer(srq); + } + } + } + + private async Task BlobExistsAsync(BlobProviderArgs args, string blobName) + { + var ossClient = GetOssClient(args); + var bucketExists = await BucketExistsAsync(args); + if (bucketExists) + { + var objectExists = ossClient.DoesObjectExist(GetBucketName(args), blobName); + + return objectExists; + } + return false; + } + + private Task BucketExistsAsync(BlobProviderArgs args) + { + var ossClient = GetOssClient(args); + var bucketExists = ossClient.DoesBucketExist(GetBucketName(args)); + + return Task.FromResult(bucketExists); + } + + private static string GetBucketName(BlobProviderArgs args) + { + var configuration = args.Configuration.GetAliyunConfiguration(); + return configuration.BucketName.IsNullOrWhiteSpace() + ? args.ContainerName + : configuration.BucketName; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs new file mode 100644 index 000000000..b6f2637ab --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using Volo.Abp; +using Volo.Abp.BlobStoring; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public class AliyunBlobProviderConfiguration + { + /// + /// 数据中心 + /// + /// + /// 详见 https://help.aliyun.com/document_detail/31837.html?spm=a2c4g.11186623.2.14.417cd47eLc9LHc#concept-zt4-cvy-5db + /// + public string Endpoint + { + get => _containerConfiguration.GetConfiguration(AliyunBlobProviderConfigurationNames.Endpoint); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.Endpoint, Check.NotNullOrWhiteSpace(value, nameof(value))); + } + /// + /// 命名空间 + /// + public string BucketName + { + get => _containerConfiguration.GetConfiguration(AliyunBlobProviderConfigurationNames.BucketName); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.BucketName, Check.NotNullOrWhiteSpace(value, nameof(value))); + } + /// + /// 命名空间不存在是否创建 + /// + public bool CreateBucketIfNotExists + { + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.CreateBucketIfNotExists, false); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.CreateBucketIfNotExists, value); + } + /// + /// 创建命名空间时防盗链列表 + /// + public List CreateBucketReferer + { + get => _containerConfiguration.GetConfiguration>(AliyunBlobProviderConfigurationNames.CreateBucketReferer); + set + { + if (value == null) + { + _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.CreateBucketReferer, new List()); + } + else + { + _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.CreateBucketReferer, value); + } + } + } + + private readonly BlobContainerConfiguration _containerConfiguration; + + public AliyunBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration) + { + _containerConfiguration = containerConfiguration; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs new file mode 100644 index 000000000..66b0c17ef --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs @@ -0,0 +1,22 @@ +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public static class AliyunBlobProviderConfigurationNames + { + /// + /// 数据中心 + /// + public const string Endpoint = "Aliyun:OSS:Endpoint"; + /// + /// 命名空间 + /// + public const string BucketName = "Aliyun:OSS:BucketName"; + /// + /// 命名空间不存在是否创建 + /// + public const string CreateBucketIfNotExists = "Aliyun:OSS:CreateBucketIfNotExists"; + /// + /// 创建命名空间时防盗链列表 + /// + public const string CreateBucketReferer = "Aliyun:OSS:CreateBucketReferer"; + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/DefaultAliyunBlobNameCalculator.cs b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/DefaultAliyunBlobNameCalculator.cs new file mode 100644 index 000000000..220a13c56 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/DefaultAliyunBlobNameCalculator.cs @@ -0,0 +1,24 @@ +using Volo.Abp.BlobStoring; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public class DefaultAliyunBlobNameCalculator : IAliyunBlobNameCalculator, ITransientDependency + { + protected ICurrentTenant CurrentTenant { get; } + + public DefaultAliyunBlobNameCalculator( + ICurrentTenant currentTenant) + { + CurrentTenant = currentTenant; + } + + public string Calculate(BlobProviderArgs args) + { + return CurrentTenant.Id == null + ? $"host/{args.BlobName}" + : $"tenants/{CurrentTenant.Id.Value:D}/{args.BlobName}"; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/IAliyunBlobNameCalculator.cs b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/IAliyunBlobNameCalculator.cs new file mode 100644 index 000000000..b8dbe6a60 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/IAliyunBlobNameCalculator.cs @@ -0,0 +1,9 @@ +using Volo.Abp.BlobStoring; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public interface IAliyunBlobNameCalculator + { + string Calculate(BlobProviderArgs args); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN.Abp.Sms.Aliyun.csproj b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN.Abp.Sms.Aliyun.csproj index 8c6bc0335..1b84eb70e 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN.Abp.Sms.Aliyun.csproj +++ b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN.Abp.Sms.Aliyun.csproj @@ -30,4 +30,8 @@ + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AbpAliyunSmsModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AbpAliyunSmsModule.cs index e36a96c42..cad4c903a 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AbpAliyunSmsModule.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AbpAliyunSmsModule.cs @@ -1,4 +1,5 @@ -using LINYUN.Abp.Sms.Aliyun.Localization; +using LINGYUN.Abp.Aliyun.Authorization; +using LINYUN.Abp.Sms.Aliyun.Localization; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Json; using Volo.Abp.Localization; @@ -11,7 +12,8 @@ namespace LINYUN.Abp.Sms.Aliyun [DependsOn( typeof(AbpSmsModule), typeof(AbpJsonModule), - typeof(AbpLocalizationModule))] + typeof(AbpLocalizationModule), + typeof(AbpAliyunAuthorizationModule))] public class AbpAliyunSmsModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsOptions.cs b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsOptions.cs index 3384f9982..19f3e04a4 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsOptions.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsOptions.cs @@ -15,14 +15,6 @@ /// public string ActionName { get; set; } = "SendSms"; /// - /// ApiKey - /// - public string AccessKeyId { get; set; } - /// - /// Api密钥 - /// - public string AccessKeySecret { get; set; } - /// /// 默认版本号 /// public string Version { get; set; } = "2017-05-25"; diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs index 36690094b..7f87d2a2f 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs @@ -2,6 +2,7 @@ using Aliyun.Acs.Core.Exceptions; using Aliyun.Acs.Core.Http; using Aliyun.Acs.Core.Profile; +using LINGYUN.Abp.Aliyun.Authorization; using LINYUN.Abp.Sms.Aliyun.Localization; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -21,6 +22,7 @@ namespace LINYUN.Abp.Sms.Aliyun [ExposeServices(typeof(ISmsSender), typeof(AliyunSmsSender))] public class AliyunSmsSender : ISmsSender { + protected AbpAliyunOptions AuthOptions { get; } protected AliyunSmsOptions Options { get; } protected IJsonSerializer JsonSerializer { get; } protected IHostEnvironment Environment { get; } @@ -29,9 +31,12 @@ namespace LINYUN.Abp.Sms.Aliyun IHostEnvironment environment, IJsonSerializer jsonSerializer, IServiceProvider serviceProvider, - IOptions options) + IOptions options, + IOptions authOptions) { Options = options.Value; + AuthOptions = authOptions.Value; + Environment = environment; JsonSerializer = jsonSerializer; ServiceProvider = serviceProvider; @@ -53,7 +58,7 @@ namespace LINYUN.Abp.Sms.Aliyun try { - IClientProfile profile = DefaultProfile.GetProfile(Options.RegionId, Options.AccessKeyId, Options.AccessKeySecret); + IClientProfile profile = DefaultProfile.GetProfile(Options.RegionId, AuthOptions.AccessKeyId, AuthOptions.AccessKeySecret); IAcsClient client = new DefaultAcsClient(profile); CommonResponse response = client.GetCommonResponse(request); var responseContent = Encoding.Default.GetString(response.HttpResponse.Content); diff --git a/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests.csproj new file mode 100644 index 000000000..acf12d3c1 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + diff --git a/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestBase.cs b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestBase.cs new file mode 100644 index 000000000..2a75696bd --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestBase.cs @@ -0,0 +1,9 @@ +using LINGYUN.Abp.Tests; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public class AbpBlobStoringAliyunTestBase : AbpTestsBase + { + + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestModule.cs b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestModule.cs new file mode 100644 index 000000000..4333b987f --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestModule.cs @@ -0,0 +1,56 @@ +using Aliyun.OSS; +using LINGYUN.Abp.Tests; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; +using Volo.Abp; +using Volo.Abp.Autofac; +using Volo.Abp.BlobStoring; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + [DependsOn( + typeof(AbpBlobStoringModule), + typeof(AbpBlobStoringAliyunModule), + typeof(AbpTestsBaseModule), + typeof(AbpAutofacModule) + )] + public class AbpBlobStoringAliyunTestModule : AbpModule + { + private string _bucketName; + private string _accessKeyId; + private string _accessKeySecret; + private string _endPoint; + + public override void PreConfigureServices(ServiceConfigurationContext context) + { + var configurationOptions = new AbpConfigurationBuilderOptions + { + BasePath = @"D:\Projects\Development\Abp\BlobStoring\Aliyun", + EnvironmentName = "Development" + }; + + context.Services.ReplaceConfiguration(ConfigurationHelper.BuildConfiguration(configurationOptions)); + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + _endPoint = configuration[AliyunBlobProviderConfigurationNames.Endpoint]; + _bucketName = configuration[AliyunBlobProviderConfigurationNames.BucketName]; + _accessKeyId = configuration["Aliyun:Auth:AccessKeyId"]; + _accessKeySecret = configuration["Aliyun:Auth:AccessKeySecret"]; + } + + public override void OnApplicationShutdown(ApplicationShutdownContext context) + { + var ossClient = new OssClient(_endPoint, _accessKeyId, _accessKeySecret); + if (ossClient.DoesBucketExist(_bucketName)) + { + ossClient.DeleteBucket(_bucketName); + } + } + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/BlobContainer_Tests.cs b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/BlobContainer_Tests.cs new file mode 100644 index 000000000..b28628fc2 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/BlobContainer_Tests.cs @@ -0,0 +1,99 @@ +using LINGYUN.Abp.BlobStoring.TestObjects; +using Shouldly; +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.BlobStoring; +using Xunit; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public class BlobContainer_Tests : AbpBlobStoringAliyunTestBase + { + protected IBlobContainer Container { get; } + public BlobContainer_Tests() + { + Container = GetRequiredService>(); + } + + [Theory] + [InlineData("test-blob-1")] + [InlineData("test-blob-1.txt")] + [InlineData("test-folder/test-blob-1")] + public async Task Should_Save_And_Get_Blobs(string blobName) + { + var testContent = "test content".GetBytes(); + await Container.SaveAsync(blobName, testContent); + try + { + var resultBytes = await Container.GetAllBytesAsync(blobName); + resultBytes.SequenceEqual(testContent).ShouldBeTrue(); + } + finally + { + await Container.DeleteAsync(blobName); + } + } + + [Fact] + public async Task Should_Overwrite_Pre_Saved_Blob_If_Requested() + { + var blobName = "test-blob-1"; + + var testContent = "test content".GetBytes(); + await Container.SaveAsync(blobName, testContent); + + var testContentOverwritten = "test content overwritten".GetBytes(); + await Container.SaveAsync(blobName, testContentOverwritten, true); + + var result = await Container.GetAllBytesAsync(blobName); + result.SequenceEqual(testContentOverwritten).ShouldBeTrue(); + + await Container.DeleteAsync(blobName); + } + + + [Fact] + public async Task Should_Not_Allow_To_Overwrite_Pre_Saved_Blob_By_Default() + { + var blobName = "test-blob-1"; + + var testContent = "test content".GetBytes(); + await Container.SaveAsync(blobName, testContent); + + var testContentOverwritten = "test content overwritten".GetBytes(); + await Assert.ThrowsAsync(() => + Container.SaveAsync(blobName, testContentOverwritten) + ); + + await Container.DeleteAsync(blobName); + } + + [Theory] + [InlineData("test-blob-1")] + [InlineData("test-blob-1.txt")] + [InlineData("test-folder/test-blob-1")] + public async Task Should_Delete_Saved_Blobs(string blobName) + { + await Container.SaveAsync(blobName, "test content".GetBytes()); + (await Container.GetAllBytesAsync(blobName)).ShouldNotBeNull(); + + await Container.DeleteAsync(blobName); + (await Container.GetAllBytesOrNullAsync(blobName)).ShouldBeNull(); + } + + [Theory] + [InlineData("test-blob-1")] + [InlineData("test-blob-1.txt")] + [InlineData("test-folder/test-blob-1")] + public virtual async Task Saved_Blobs_Should_Exists(string blobName) + { + await Container.SaveAsync(blobName, "test content".GetBytes()); + (await Container.ExistsAsync(blobName)).ShouldBeTrue(); + + await Container.DeleteAsync(blobName); + (await Container.ExistsAsync(blobName)).ShouldBeFalse(); + } + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/TestObjects/TestContainer1.cs b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/TestObjects/TestContainer1.cs new file mode 100644 index 000000000..47562c6a3 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/TestObjects/TestContainer1.cs @@ -0,0 +1,6 @@ +namespace LINGYUN.Abp.BlobStoring.TestObjects +{ + public class TestContainer1 + { + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN.Abp.TestsBase.csproj b/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN.Abp.TestsBase.csproj new file mode 100644 index 000000000..d1b8b5acc --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN.Abp.TestsBase.csproj @@ -0,0 +1,21 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + + + + diff --git a/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN/Abp/Tests/AbpTestsBase.cs b/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN/Abp/Tests/AbpTestsBase.cs new file mode 100644 index 000000000..fb8afac33 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN/Abp/Tests/AbpTestsBase.cs @@ -0,0 +1,59 @@ +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Modularity; +using Volo.Abp.Testing; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.Tests +{ + public abstract class AbpTestsBase : AbpIntegratedTest + where TStartupModule : IAbpModule + { + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + + protected virtual Task WithUnitOfWorkAsync(Func func) + { + return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); + } + + protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func action) + { + using (var scope = ServiceProvider.CreateScope()) + { + var uowManager = scope.ServiceProvider.GetRequiredService(); + + using (var uow = uowManager.Begin(options)) + { + await action(); + + await uow.CompleteAsync(); + } + } + } + + protected virtual Task WithUnitOfWorkAsync(Func> func) + { + return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); + } + + protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func> func) + { + using (var scope = ServiceProvider.CreateScope()) + { + var uowManager = scope.ServiceProvider.GetRequiredService(); + + using (var uow = uowManager.Begin(options)) + { + var result = await func(); + await uow.CompleteAsync(); + return result; + } + } + } + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN/Abp/Tests/AbpTestsBaseModule.cs b/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN/Abp/Tests/AbpTestsBaseModule.cs new file mode 100644 index 000000000..f7b0d6cff --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN/Abp/Tests/AbpTestsBaseModule.cs @@ -0,0 +1,21 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; +using Volo.Abp.Authorization; +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Tests +{ + [DependsOn( + typeof(AbpAutofacModule), + typeof(AbpTestBaseModule), + typeof(AbpAuthorizationModule) + )] + public class AbpTestsBaseModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAlwaysAllowAuthorization(); + } + } +}