From a2d478c9937c7150435acffd30529a05d3dfa128 Mon Sep 17 00:00:00 2001 From: cKey <35512826+colinin@users.noreply.github.com> Date: Fri, 22 Oct 2021 16:29:38 +0800 Subject: [PATCH] feat(oss): add public/private file management api --- .../Aliyun/AliyunOssContainer.cs | 739 +++++++++--------- ...OssManagement.Application.Contracts.csproj | 4 +- ...OssManagementApplicationContractsModule.cs | 24 +- ...pOssManagementFeatureDefinitionProvider.cs | 75 -- .../Features/AbpOssManagementFeatureNames.cs | 41 - ...NGYUN.Abp.OssManagement.Application.csproj | 5 +- .../AbpOssManagementApplicationModule.cs | 50 +- .../OssManagementApplicationServiceBase.cs | 28 +- .../Abp/OssManagement/OssObjectAppService.cs | 217 +++-- .../Abp/OssManagement/PublicFileAppService.cs | 83 +- ...YUN.Abp.OssManagement.Domain.Shared.csproj | 5 +- .../AbpOssManagementDomainSharedModule.cs | 72 +- .../Localization/Resources/en.json | 1 + .../Localization/Resources/zh-Hans.json | 1 + .../OssManagement/OssManagementErrorCodes.cs | 35 +- .../AbpOssManagementDomainModule.cs | 49 +- .../AbpOssManagementFileSystemModule.cs | 36 +- .../FileSystem/FileSystemOssContainer.cs | 15 +- .../FileSystemOssContainerFactory.cs | 96 +-- .../LINGYUN.Abp.OssManagement.HttpApi.csproj | 1 - .../AbpOssManagementHttpApiModule.cs | 68 +- .../Abp/OssManagement/FileValidater.cs | 96 --- .../Abp/OssManagement/IFileValidater.cs | 9 - .../OssManagement/StaticFilesController.cs | 4 +- .../Abp/OssManagement/UploadOssObjectInput.cs | 12 +- ...AbpOssManagementSettingManagementModule.cs | 20 - aspnet-core/modules/oss-management/README.md | 101 +-- .../AppPlatformHttpApiHostModule.cs | 675 ++++++++-------- 28 files changed, 1152 insertions(+), 1410 deletions(-) delete mode 100644 aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureDefinitionProvider.cs delete mode 100644 aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureNames.cs delete mode 100644 aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/FileValidater.cs delete mode 100644 aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/IFileValidater.cs delete mode 100644 aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.SettingManagement/AbpOssManagementSettingManagementModule.cs diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Aliyun/LINGYUN/Abp/OssManagement/Aliyun/AliyunOssContainer.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Aliyun/LINGYUN/Abp/OssManagement/Aliyun/AliyunOssContainer.cs index dc9e66766..9e38b00c8 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Aliyun/LINGYUN/Abp/OssManagement/Aliyun/AliyunOssContainer.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Aliyun/LINGYUN/Abp/OssManagement/Aliyun/AliyunOssContainer.cs @@ -1,369 +1,370 @@ -using Aliyun.OSS; -using LINGYUN.Abp.BlobStoring.Aliyun; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Volo.Abp; -using Volo.Abp.MultiTenancy; - -namespace LINGYUN.Abp.OssManagement.Aliyun -{ - /// - /// Oss容器的阿里云实现 - /// - internal class AliyunOssContainer : IOssContainer - { - protected ICurrentTenant CurrentTenant { get; } - protected IOssClientFactory OssClientFactory { get; } - public AliyunOssContainer( - ICurrentTenant currentTenant, - IOssClientFactory ossClientFactory) - { - CurrentTenant = currentTenant; - OssClientFactory = ossClientFactory; - } - public virtual async Task BulkDeleteObjectsAsync(BulkDeleteObjectRequest request) - { - var ossClient = await CreateClientAsync(); - - var path = GetBasePath(request.Path); - var aliyunRequest = new DeleteObjectsRequest(request.Bucket, request.Objects.Select(x => x += path).ToList()); - - ossClient.DeleteObjects(aliyunRequest); - } - - public virtual async Task CreateAsync(string name) - { - var ossClient = await CreateClientAsync(); - - if (BucketExists(ossClient, name)) - { - throw new BusinessException(code: OssManagementErrorCodes.ContainerAlreadyExists); - } - - var bucket = ossClient.CreateBucket(name); - - return new OssContainer( - bucket.Name, - bucket.CreationDate, - 0L, - bucket.CreationDate, - new Dictionary - { - { "Id", bucket.Owner?.Id }, - { "DisplayName", bucket.Owner?.DisplayName } - }); - } - - public virtual async Task CreateObjectAsync(CreateOssObjectRequest request) - { - var ossClient = await CreateClientAsync(); - - var objectPath = GetBasePath(request.Path); - - var objectName = objectPath.IsNullOrWhiteSpace() - ? request.Object - : objectPath + request.Object; - - if (!request.Overwrite && ObjectExists(ossClient, request.Bucket, objectName)) - { - throw new BusinessException(code: OssManagementErrorCodes.ObjectAlreadyExists); - } - - // 当一个对象名称是以 / 结尾时,不论该对象是否存有数据,都以目录的形式存在 - // 详情见:https://help.aliyun.com/document_detail/31910.html - if (objectName.EndsWith("/") && - request.Content.IsNullOrEmpty()) - { - var emptyStream = new MemoryStream(); - var emptyData = System.Text.Encoding.UTF8.GetBytes(""); - await emptyStream.WriteAsync(emptyData, 0, emptyData.Length); - request.SetContent(emptyStream); - } - - // 没有bucket则创建 - if (!BucketExists(ossClient, request.Bucket)) - { - ossClient.CreateBucket(request.Bucket); - } - - var aliyunObjectRequest = new PutObjectRequest(request.Bucket, objectName, request.Content) - { - Metadata = new ObjectMetadata() - }; - if (request.ExpirationTime.HasValue) - { - aliyunObjectRequest.Metadata.ExpirationTime = DateTime.Now.Add(request.ExpirationTime.Value); - } - - var aliyunObject = ossClient.PutObject(aliyunObjectRequest); - - var ossObject = new OssObject( - !objectPath.IsNullOrWhiteSpace() - ? objectName.Replace(objectPath, "") - : objectName, - objectPath, - DateTime.Now, - aliyunObject.ContentLength, - DateTime.Now, - aliyunObject.ResponseMetadata, - objectName.EndsWith("/") // 名称结尾是 / 符号的则为目录:https://help.aliyun.com/document_detail/31910.html - ) - { - FullName = objectName - }; - - if (!Equals(request.Content, Stream.Null)) - { - request.Content.Seek(0, SeekOrigin.Begin); - ossObject.SetContent(request.Content); - } - - return ossObject; - } - - public virtual async Task DeleteAsync(string name) - { - var ossClient = await CreateClientAsync(); - - if (BucketExists(ossClient, name)) - { - ossClient.DeleteBucket(name); - } - } - - public virtual async Task DeleteObjectAsync(GetOssObjectRequest request) - { - var ossClient = await CreateClientAsync(); - - var objectPath = GetBasePath(request.Path); - - var objectName = objectPath.IsNullOrWhiteSpace() - ? request.Object - : objectPath + request.Object; - - if (BucketExists(ossClient, request.Bucket) && - ObjectExists(ossClient, request.Bucket, objectName)) - { - var objectListing = ossClient.ListObjects(request.Bucket, objectName); - if (objectListing.CommonPrefixes.Any() || - objectListing.ObjectSummaries.Any()) - { - throw new BusinessException(code: OssManagementErrorCodes.ObjectDeleteWithNotEmpty); - // throw new ObjectDeleteWithNotEmptyException("00201", $"Can't not delete oss object {request.Object}, because it is not empty!"); - } - ossClient.DeleteObject(request.Bucket, objectName); - } - } - - public virtual async Task ExistsAsync(string name) - { - var ossClient = await CreateClientAsync(); - - return BucketExists(ossClient, name); - } - - public virtual async Task GetAsync(string name) - { - var ossClient = await CreateClientAsync(); - if (!BucketExists(ossClient, name)) - { - throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound); - // throw new ContainerNotFoundException($"Can't not found container {name} in aliyun blob storing"); - } - var bucket = ossClient.GetBucketInfo(name); - - return new OssContainer( - bucket.Bucket.Name, - bucket.Bucket.CreationDate, - 0L, - bucket.Bucket.CreationDate, - new Dictionary - { - { "Id", bucket.Bucket.Owner?.Id }, - { "DisplayName", bucket.Bucket.Owner?.DisplayName } - }); - } - - public virtual async Task GetObjectAsync(GetOssObjectRequest request) - { - var ossClient = await CreateClientAsync(); - if (!BucketExists(ossClient, request.Bucket)) - { - throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound); - // throw new ContainerNotFoundException($"Can't not found container {request.Bucket} in aliyun blob storing"); - } - - var objectPath = GetBasePath(request.Path); - var objectName = objectPath.IsNullOrWhiteSpace() - ? request.Object - : objectPath + request.Object; - - if (!ObjectExists(ossClient, request.Bucket, objectName)) - { - throw new BusinessException(code: OssManagementErrorCodes.ObjectNotFound); - // throw new ContainerNotFoundException($"Can't not found object {objectName} in container {request.Bucket} with aliyun blob storing"); - } - - var aliyunOssObjectRequest = new GetObjectRequest(request.Bucket, objectName, request.Process); - var aliyunOssObject = ossClient.GetObject(aliyunOssObjectRequest); - var ossObject = new OssObject( - !objectPath.IsNullOrWhiteSpace() - ? aliyunOssObject.Key.Replace(objectPath, "") - : aliyunOssObject.Key, - request.Path, - aliyunOssObject.Metadata.LastModified, - aliyunOssObject.Metadata.ContentLength, - aliyunOssObject.Metadata.LastModified, - aliyunOssObject.Metadata.UserMetadata, - aliyunOssObject.Key.EndsWith("/")) - { - FullName = aliyunOssObject.Key - }; - - if (aliyunOssObject.IsSetResponseStream()) - { - var memoryStream = new MemoryStream(); - await aliyunOssObject.Content.CopyToAsync(memoryStream); - memoryStream.Seek(0, SeekOrigin.Begin); - ossObject.SetContent(memoryStream); - } - - return ossObject; - } - - public virtual async Task GetListAsync(GetOssContainersRequest request) - { - var ossClient = await CreateClientAsync(); - - var aliyunRequest = new ListBucketsRequest - { - Marker = request.Marker, - Prefix = request.Prefix, - MaxKeys = request.MaxKeys - }; - var bucketsResponse = ossClient.ListBuckets(aliyunRequest); - - return new GetOssContainersResponse( - bucketsResponse.Prefix, - bucketsResponse.Marker, - bucketsResponse.NextMaker, - bucketsResponse.MaxKeys ?? 0, - bucketsResponse.Buckets - .Select(x => new OssContainer( - x.Name, - x.CreationDate, - 0L, - x.CreationDate, - new Dictionary - { - { "Id", x.Owner?.Id }, - { "DisplayName", x.Owner?.DisplayName } - })) - .ToList()); - } - - public virtual async Task GetObjectsAsync(GetOssObjectsRequest request) - { - - var ossClient = await CreateClientAsync(); - - var objectPath = GetBasePath(request.Prefix); - var marker = !objectPath.IsNullOrWhiteSpace() && !request.Marker.IsNullOrWhiteSpace() - ? request.Marker.Replace(objectPath, "") - : request.Marker; - var aliyunRequest = new ListObjectsRequest(request.BucketName) - { - Marker = !marker.IsNullOrWhiteSpace() ? objectPath + marker : marker, - Prefix = objectPath, - MaxKeys = request.MaxKeys, - EncodingType = request.EncodingType, - Delimiter = request.Delimiter - }; - var objectsResponse = ossClient.ListObjects(aliyunRequest); - - var ossObjects = objectsResponse.ObjectSummaries - .Where(x => !x.Key.Equals(objectsResponse.Prefix))// 过滤当前的目录返回值 - .Select(x => new OssObject( - !objectPath.IsNullOrWhiteSpace() && !x.Key.Equals(objectPath) - ? x.Key.Replace(objectPath, "") - : x.Key, // 去除目录名称 - request.Prefix, - x.LastModified, - x.Size, - x.LastModified, - new Dictionary - { - { "Id", x.Owner?.Id }, - { "DisplayName", x.Owner?.DisplayName } - }, - x.Key.EndsWith("/")) - { - FullName = x.Key - }) - .ToList(); - // 当 Delimiter 为 / 时, objectsResponse.CommonPrefixes 可用于代表层级目录 - if (objectsResponse.CommonPrefixes.Any()) - { - ossObjects.InsertRange(0, - objectsResponse.CommonPrefixes - .Select(x => new OssObject( - x.Replace(objectPath, ""), - request.Prefix, - null, - 0L, - null, - null, - true))); - } - // 排序 - // TODO: 是否需要客户端来排序 - ossObjects.Sort(new OssObjectComparer()); - - return new GetOssObjectsResponse( - objectsResponse.BucketName, - request.Prefix, - marker, - !objectPath.IsNullOrWhiteSpace() && !objectsResponse.NextMarker.IsNullOrWhiteSpace() - ? objectsResponse.NextMarker.Replace(objectPath, "") - : objectsResponse.NextMarker, - objectsResponse.Delimiter, - objectsResponse.MaxKeys, - ossObjects); - } - - protected virtual string GetBasePath(string path) - { - string objectPath = ""; - if (CurrentTenant.Id == null) - { - objectPath += "host/"; - } - else - { - objectPath += "tenants/" + CurrentTenant.Id.Value.ToString("D"); - } - - objectPath += path ?? ""; - - return objectPath.EnsureEndsWith('/'); - } - - protected virtual bool BucketExists(IOss client, string bucketName) - { - return client.DoesBucketExist(bucketName); - } - - protected virtual bool ObjectExists(IOss client, string bucketName, string objectName) - { - return client.DoesObjectExist(bucketName, objectName); - } - - protected virtual async Task CreateClientAsync() - { - return await OssClientFactory.CreateAsync(); - } - } -} +using Aliyun.OSS; +using LINGYUN.Abp.BlobStoring.Aliyun; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.OssManagement.Aliyun +{ + /// + /// Oss容器的阿里云实现 + /// + internal class AliyunOssContainer : IOssContainer + { + protected ICurrentTenant CurrentTenant { get; } + protected IOssClientFactory OssClientFactory { get; } + public AliyunOssContainer( + ICurrentTenant currentTenant, + IOssClientFactory ossClientFactory) + { + CurrentTenant = currentTenant; + OssClientFactory = ossClientFactory; + } + public virtual async Task BulkDeleteObjectsAsync(BulkDeleteObjectRequest request) + { + var ossClient = await CreateClientAsync(); + + var path = GetBasePath(request.Path); + var aliyunRequest = new DeleteObjectsRequest(request.Bucket, request.Objects.Select(x => x += path).ToList()); + + ossClient.DeleteObjects(aliyunRequest); + } + + public virtual async Task CreateAsync(string name) + { + var ossClient = await CreateClientAsync(); + + if (BucketExists(ossClient, name)) + { + throw new BusinessException(code: OssManagementErrorCodes.ContainerAlreadyExists); + } + + var bucket = ossClient.CreateBucket(name); + + return new OssContainer( + bucket.Name, + bucket.CreationDate, + 0L, + bucket.CreationDate, + new Dictionary + { + { "Id", bucket.Owner?.Id }, + { "DisplayName", bucket.Owner?.DisplayName } + }); + } + + public virtual async Task CreateObjectAsync(CreateOssObjectRequest request) + { + var ossClient = await CreateClientAsync(); + + var objectPath = GetBasePath(request.Path); + + var objectName = objectPath.IsNullOrWhiteSpace() + ? request.Object + : objectPath + request.Object; + + if (!request.Overwrite && ObjectExists(ossClient, request.Bucket, objectName)) + { + throw new BusinessException(code: OssManagementErrorCodes.ObjectAlreadyExists); + } + + // 当一个对象名称是以 / 结尾时,不论该对象是否存有数据,都以目录的形式存在 + // 详情见:https://help.aliyun.com/document_detail/31910.html + if (objectName.EndsWith("/") && + request.Content.IsNullOrEmpty()) + { + var emptyStream = new MemoryStream(); + var emptyData = System.Text.Encoding.UTF8.GetBytes(""); + await emptyStream.WriteAsync(emptyData, 0, emptyData.Length); + request.SetContent(emptyStream); + } + + // 没有bucket则创建 + if (!BucketExists(ossClient, request.Bucket)) + { + ossClient.CreateBucket(request.Bucket); + } + + var aliyunObjectRequest = new PutObjectRequest(request.Bucket, objectName, request.Content) + { + Metadata = new ObjectMetadata() + }; + if (request.ExpirationTime.HasValue) + { + aliyunObjectRequest.Metadata.ExpirationTime = DateTime.Now.Add(request.ExpirationTime.Value); + } + + var aliyunObject = ossClient.PutObject(aliyunObjectRequest); + + var ossObject = new OssObject( + !objectPath.IsNullOrWhiteSpace() + ? objectName.Replace(objectPath, "") + : objectName, + objectPath, + DateTime.Now, + aliyunObject.ContentLength, + DateTime.Now, + aliyunObject.ResponseMetadata, + objectName.EndsWith("/") // 名称结尾是 / 符号的则为目录:https://help.aliyun.com/document_detail/31910.html + ) + { + FullName = objectName + }; + + if (!Equals(request.Content, Stream.Null)) + { + request.Content.Seek(0, SeekOrigin.Begin); + ossObject.SetContent(request.Content); + } + + return ossObject; + } + + public virtual async Task DeleteAsync(string name) + { + // 阿里云oss在控制台设置即可,无需改变 + var ossClient = await CreateClientAsync(); + + if (BucketExists(ossClient, name)) + { + ossClient.DeleteBucket(name); + } + } + + public virtual async Task DeleteObjectAsync(GetOssObjectRequest request) + { + var ossClient = await CreateClientAsync(); + + var objectPath = GetBasePath(request.Path); + + var objectName = objectPath.IsNullOrWhiteSpace() + ? request.Object + : objectPath + request.Object; + + if (BucketExists(ossClient, request.Bucket) && + ObjectExists(ossClient, request.Bucket, objectName)) + { + var objectListing = ossClient.ListObjects(request.Bucket, objectName); + if (objectListing.CommonPrefixes.Any() || + objectListing.ObjectSummaries.Any()) + { + throw new BusinessException(code: OssManagementErrorCodes.ObjectDeleteWithNotEmpty); + // throw new ObjectDeleteWithNotEmptyException("00201", $"Can't not delete oss object {request.Object}, because it is not empty!"); + } + ossClient.DeleteObject(request.Bucket, objectName); + } + } + + public virtual async Task ExistsAsync(string name) + { + var ossClient = await CreateClientAsync(); + + return BucketExists(ossClient, name); + } + + public virtual async Task GetAsync(string name) + { + var ossClient = await CreateClientAsync(); + if (!BucketExists(ossClient, name)) + { + throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound); + // throw new ContainerNotFoundException($"Can't not found container {name} in aliyun blob storing"); + } + var bucket = ossClient.GetBucketInfo(name); + + return new OssContainer( + bucket.Bucket.Name, + bucket.Bucket.CreationDate, + 0L, + bucket.Bucket.CreationDate, + new Dictionary + { + { "Id", bucket.Bucket.Owner?.Id }, + { "DisplayName", bucket.Bucket.Owner?.DisplayName } + }); + } + + public virtual async Task GetObjectAsync(GetOssObjectRequest request) + { + var ossClient = await CreateClientAsync(); + if (!BucketExists(ossClient, request.Bucket)) + { + throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound); + // throw new ContainerNotFoundException($"Can't not found container {request.Bucket} in aliyun blob storing"); + } + + var objectPath = GetBasePath(request.Path); + var objectName = objectPath.IsNullOrWhiteSpace() + ? request.Object + : objectPath + request.Object; + + if (!ObjectExists(ossClient, request.Bucket, objectName)) + { + throw new BusinessException(code: OssManagementErrorCodes.ObjectNotFound); + // throw new ContainerNotFoundException($"Can't not found object {objectName} in container {request.Bucket} with aliyun blob storing"); + } + + var aliyunOssObjectRequest = new GetObjectRequest(request.Bucket, objectName, request.Process); + var aliyunOssObject = ossClient.GetObject(aliyunOssObjectRequest); + var ossObject = new OssObject( + !objectPath.IsNullOrWhiteSpace() + ? aliyunOssObject.Key.Replace(objectPath, "") + : aliyunOssObject.Key, + request.Path, + aliyunOssObject.Metadata.LastModified, + aliyunOssObject.Metadata.ContentLength, + aliyunOssObject.Metadata.LastModified, + aliyunOssObject.Metadata.UserMetadata, + aliyunOssObject.Key.EndsWith("/")) + { + FullName = aliyunOssObject.Key + }; + + if (aliyunOssObject.IsSetResponseStream()) + { + var memoryStream = new MemoryStream(); + await aliyunOssObject.Content.CopyToAsync(memoryStream); + memoryStream.Seek(0, SeekOrigin.Begin); + ossObject.SetContent(memoryStream); + } + + return ossObject; + } + + public virtual async Task GetListAsync(GetOssContainersRequest request) + { + var ossClient = await CreateClientAsync(); + + var aliyunRequest = new ListBucketsRequest + { + Marker = request.Marker, + Prefix = request.Prefix, + MaxKeys = request.MaxKeys + }; + var bucketsResponse = ossClient.ListBuckets(aliyunRequest); + + return new GetOssContainersResponse( + bucketsResponse.Prefix, + bucketsResponse.Marker, + bucketsResponse.NextMaker, + bucketsResponse.MaxKeys ?? 0, + bucketsResponse.Buckets + .Select(x => new OssContainer( + x.Name, + x.CreationDate, + 0L, + x.CreationDate, + new Dictionary + { + { "Id", x.Owner?.Id }, + { "DisplayName", x.Owner?.DisplayName } + })) + .ToList()); + } + + public virtual async Task GetObjectsAsync(GetOssObjectsRequest request) + { + + var ossClient = await CreateClientAsync(); + + var objectPath = GetBasePath(request.Prefix); + var marker = !objectPath.IsNullOrWhiteSpace() && !request.Marker.IsNullOrWhiteSpace() + ? request.Marker.Replace(objectPath, "") + : request.Marker; + var aliyunRequest = new ListObjectsRequest(request.BucketName) + { + Marker = !marker.IsNullOrWhiteSpace() ? objectPath + marker : marker, + Prefix = objectPath, + MaxKeys = request.MaxKeys, + EncodingType = request.EncodingType, + Delimiter = request.Delimiter + }; + var objectsResponse = ossClient.ListObjects(aliyunRequest); + + var ossObjects = objectsResponse.ObjectSummaries + .Where(x => !x.Key.Equals(objectsResponse.Prefix))// 过滤当前的目录返回值 + .Select(x => new OssObject( + !objectPath.IsNullOrWhiteSpace() && !x.Key.Equals(objectPath) + ? x.Key.Replace(objectPath, "") + : x.Key, // 去除目录名称 + request.Prefix, + x.LastModified, + x.Size, + x.LastModified, + new Dictionary + { + { "Id", x.Owner?.Id }, + { "DisplayName", x.Owner?.DisplayName } + }, + x.Key.EndsWith("/")) + { + FullName = x.Key + }) + .ToList(); + // 当 Delimiter 为 / 时, objectsResponse.CommonPrefixes 可用于代表层级目录 + if (objectsResponse.CommonPrefixes.Any()) + { + ossObjects.InsertRange(0, + objectsResponse.CommonPrefixes + .Select(x => new OssObject( + x.Replace(objectPath, ""), + request.Prefix, + null, + 0L, + null, + null, + true))); + } + // 排序 + // TODO: 是否需要客户端来排序 + ossObjects.Sort(new OssObjectComparer()); + + return new GetOssObjectsResponse( + objectsResponse.BucketName, + request.Prefix, + marker, + !objectPath.IsNullOrWhiteSpace() && !objectsResponse.NextMarker.IsNullOrWhiteSpace() + ? objectsResponse.NextMarker.Replace(objectPath, "") + : objectsResponse.NextMarker, + objectsResponse.Delimiter, + objectsResponse.MaxKeys, + ossObjects); + } + + protected virtual string GetBasePath(string path) + { + string objectPath = ""; + if (CurrentTenant.Id == null) + { + objectPath += "host/"; + } + else + { + objectPath += "tenants/" + CurrentTenant.Id.Value.ToString("D"); + } + + objectPath += path ?? ""; + + return objectPath.EnsureEndsWith('/'); + } + + protected virtual bool BucketExists(IOss client, string bucketName) + { + return client.DoesBucketExist(bucketName); + } + + protected virtual bool ObjectExists(IOss client, string bucketName, string objectName) + { + return client.DoesObjectExist(bucketName, objectName); + } + + protected virtual async Task CreateClientAsync() + { + return await OssClientFactory.CreateAsync(); + } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN.Abp.OssManagement.Application.Contracts.csproj b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN.Abp.OssManagement.Application.Contracts.csproj index 937bd2be2..a565151d9 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN.Abp.OssManagement.Application.Contracts.csproj +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN.Abp.OssManagement.Application.Contracts.csproj @@ -1,4 +1,4 @@ - + @@ -8,7 +8,7 @@ - + diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/AbpOssManagementApplicationContractsModule.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/AbpOssManagementApplicationContractsModule.cs index cbbcc02a3..5da181785 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/AbpOssManagementApplicationContractsModule.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/AbpOssManagementApplicationContractsModule.cs @@ -1,12 +1,12 @@ -using Volo.Abp.Application; -using Volo.Abp.Modularity; - -namespace LINGYUN.Abp.OssManagement -{ - [DependsOn( - typeof(AbpOssManagementDomainSharedModule), - typeof(AbpDddApplicationModule))] - public class AbpOssManagementApplicationContractsModule : AbpModule - { - } -} +using Volo.Abp.Application; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.OssManagement +{ + [DependsOn( + typeof(AbpOssManagementDomainSharedModule), + typeof(AbpDddApplicationContractsModule))] + public class AbpOssManagementApplicationContractsModule : AbpModule + { + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureDefinitionProvider.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureDefinitionProvider.cs deleted file mode 100644 index df5aa95b1..000000000 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureDefinitionProvider.cs +++ /dev/null @@ -1,75 +0,0 @@ -using LINGYUN.Abp.OssManagement.Localization; -using Volo.Abp.Features; -using Volo.Abp.Localization; -using Volo.Abp.Validation.StringValues; - -namespace LINGYUN.Abp.OssManagement.Features -{ - public class AbpOssManagementFeatureDefinitionProvider : FeatureDefinitionProvider - { - public override void Define(IFeatureDefinitionContext context) - { - var featureGroup = context.AddGroup( - name: AbpOssManagementFeatureNames.GroupName, - displayName: L("Features:OssManagement")); - - var ossFeature = featureGroup.AddFeature( - name: AbpOssManagementFeatureNames.OssObject.Default, - defaultValue: true.ToString(), - displayName: L("Features:DisplayName:OssObject"), - description: L("Features:Description:OssObject"), - valueType: new ToggleStringValueType(new BooleanValueValidator())); - - ossFeature.CreateChild( - name: AbpOssManagementFeatureNames.OssObject.DownloadFile, - defaultValue: false.ToString(), - displayName: L("Features:DisplayName:DownloadFile"), - description: L("Features:Description:DownloadFile"), - valueType: new ToggleStringValueType(new BooleanValueValidator())); - ossFeature.CreateChild( - name: AbpOssManagementFeatureNames.OssObject.DownloadLimit, - defaultValue: "1000", - displayName: L("Features:DisplayName:DownloadLimit"), - description: L("Features:Description:DownloadLimit"), - valueType: new FreeTextStringValueType(new NumericValueValidator(0, 100_0000))); // 上限100万次调用 - ossFeature.CreateChild( - name: AbpOssManagementFeatureNames.OssObject.DownloadInterval, - defaultValue: "1", - displayName: L("Features:DisplayName:DownloadInterval"), - description: L("Features:Description:DownloadInterval"), - valueType: new FreeTextStringValueType(new NumericValueValidator(1, 12))); // 上限12月 - - ossFeature.CreateChild( - name: AbpOssManagementFeatureNames.OssObject.UploadFile, - defaultValue: true.ToString(), - displayName: L("Features:DisplayName:UploadFile"), - description: L("Features:Description:UploadFile"), - valueType: new ToggleStringValueType(new BooleanValueValidator())); - ossFeature.CreateChild( - name: AbpOssManagementFeatureNames.OssObject.UploadLimit, - defaultValue: "1000", - displayName: L("Features:DisplayName:UploadLimit"), - description: L("Features:Description:UploadLimit"), - valueType: new FreeTextStringValueType(new NumericValueValidator(0, 100_0000))); // 上限100万次调用 - ossFeature.CreateChild( - name: AbpOssManagementFeatureNames.OssObject.UploadInterval, - defaultValue: "1", - displayName: L("Features:DisplayName:UploadInterval"), - description: L("Features:Description:UploadInterval"), - valueType: new FreeTextStringValueType(new NumericValueValidator(1, 12))); // 上限12月 - - // TODO: 此功能需要控制器协同,暂时不实现 - //fileSystemFeature.CreateChild( - // name: AbpOssManagementFeatureNames.OssObject.MaxUploadFileCount, - // defaultValue: 1.ToString(), - // displayName: L("Features:DisplayName:MaxUploadFileCount"), - // description: L("Features:Description:MaxUploadFileCount"), - // valueType: new FreeTextStringValueType(new NumericValueValidator(1, 10))); - } - - protected ILocalizableString L(string name) - { - return LocalizableString.Create(name); - } - } -} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureNames.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureNames.cs deleted file mode 100644 index 9b8e93441..000000000 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureNames.cs +++ /dev/null @@ -1,41 +0,0 @@ -namespace LINGYUN.Abp.OssManagement.Features -{ - public class AbpOssManagementFeatureNames - { - public const string GroupName = "AbpOssManagement"; - - - public class OssObject - { - public const string Default = GroupName + ".OssObject"; - /// - /// 下载文件功能 - /// - public const string DownloadFile = Default + ".DownloadFile"; - /// - /// 下载文件功能限制次数 - /// - public const string DownloadLimit = Default + ".DownloadLimit"; - /// - /// 下载文件功能限制次数周期 - /// - public const string DownloadInterval = Default + ".DownloadInterval"; - /// - /// 上传文件功能 - /// - public const string UploadFile = Default + ".UploadFile"; - /// - /// 上传文件功能限制次数 - /// - public const string UploadLimit = Default + ".UploadLimit"; - /// - /// 上传文件功能限制次数周期 - /// - public const string UploadInterval = Default + ".UploadInterval"; - /// - /// 最大上传文件 - /// - public const string MaxUploadFileCount = Default + ".MaxUploadFileCount"; - } - } -} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN.Abp.OssManagement.Application.csproj b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN.Abp.OssManagement.Application.csproj index e2ba1febc..845aa9a35 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN.Abp.OssManagement.Application.csproj +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN.Abp.OssManagement.Application.csproj @@ -1,4 +1,4 @@ - + @@ -9,9 +9,12 @@ + + + diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/AbpOssManagementApplicationModule.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/AbpOssManagementApplicationModule.cs index 41df61378..6268f36ac 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/AbpOssManagementApplicationModule.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/AbpOssManagementApplicationModule.cs @@ -1,23 +1,27 @@ -using Volo.Abp.AutoMapper; -using Volo.Abp.Modularity; -using Microsoft.Extensions.DependencyInjection; - -namespace LINGYUN.Abp.OssManagement -{ - [DependsOn( - typeof(AbpAutoMapperModule), - typeof(AbpOssManagementDomainModule), - typeof(AbpOssManagementApplicationContractsModule))] - public class AbpOssManagementApplicationModule : AbpModule - { - public override void ConfigureServices(ServiceConfigurationContext context) - { - context.Services.AddAutoMapperObjectMapper(); - - Configure(options => - { - options.AddProfile(validate: true); - }); - } - } -} +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Application; +using Volo.Abp.AutoMapper; +using Volo.Abp.Caching; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.OssManagement +{ + [DependsOn( + typeof(AbpOssManagementDomainModule), + typeof(AbpOssManagementApplicationContractsModule), + typeof(AbpCachingModule), + typeof(AbpAutoMapperModule), + typeof(AbpDddApplicationModule))] + public class AbpOssManagementApplicationModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAutoMapperObjectMapper(); + + Configure(options => + { + options.AddProfile(validate: true); + }); + } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/OssManagementApplicationServiceBase.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/OssManagementApplicationServiceBase.cs index 32150b969..b43549ec7 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/OssManagementApplicationServiceBase.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/OssManagementApplicationServiceBase.cs @@ -1,14 +1,14 @@ -using LINGYUN.Abp.OssManagement.Localization; -using Volo.Abp.Application.Services; - -namespace LINGYUN.Abp.OssManagement -{ - public class OssManagementApplicationServiceBase : ApplicationService - { - protected OssManagementApplicationServiceBase() - { - LocalizationResource = typeof(AbpOssManagementResource); - ObjectMapperContext = typeof(AbpOssManagementApplicationModule); - } - } -} +using LINGYUN.Abp.OssManagement.Localization; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.OssManagement +{ + public abstract class OssManagementApplicationServiceBase : ApplicationService + { + protected OssManagementApplicationServiceBase() + { + LocalizationResource = typeof(AbpOssManagementResource); + ObjectMapperContext = typeof(AbpOssManagementApplicationModule); + } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/OssObjectAppService.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/OssObjectAppService.cs index 0d4cbb319..671c88bbe 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/OssObjectAppService.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/OssObjectAppService.cs @@ -1,116 +1,101 @@ -using LINGYUN.Abp.Features.LimitValidation; -using LINGYUN.Abp.OssManagement.Features; -using LINGYUN.Abp.OssManagement.Permissions; -using LINGYUN.Abp.OssManagement.Settings; -using Microsoft.AspNetCore.Authorization; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Volo.Abp.Features; -using Volo.Abp.IO; -using Volo.Abp.Settings; -using Volo.Abp.Validation; - -namespace LINGYUN.Abp.OssManagement -{ - [Authorize(AbpOssManagementPermissions.OssObject.Default)] - public class OssObjectAppService : OssManagementApplicationServiceBase, IOssObjectAppService - { - protected IOssContainerFactory OssContainerFactory { get; } - - public OssObjectAppService( - IOssContainerFactory ossContainerFactory) - { - OssContainerFactory = ossContainerFactory; - } - - [Authorize(AbpOssManagementPermissions.OssObject.Create)] - [RequiresFeature(AbpOssManagementFeatureNames.OssObject.UploadFile)] - [RequiresLimitFeature( - AbpOssManagementFeatureNames.OssObject.UploadLimit, - AbpOssManagementFeatureNames.OssObject.UploadInterval, - LimitPolicy.Month)] - public virtual async Task CreateAsync(CreateOssObjectInput input) - { - if (!input.Content.IsNullOrEmpty()) - { - // 检查文件大小 - var fileSizeLimited = await SettingProvider - .GetAsync( - AbpOssManagementSettingNames.FileLimitLength, - AbpOssManagementSettingNames.DefaultFileLimitLength); - if (fileSizeLimited * 1024 * 1024 < input.Content.Length) - { - ThrowValidationException(L["UploadFileSizeBeyondLimit", fileSizeLimited], nameof(input.Content)); - } - - // 文件扩展名 - var fileExtensionName = FileHelper.GetExtension(input.Object); - var fileAllowExtension = await SettingProvider.GetOrNullAsync(AbpOssManagementSettingNames.AllowFileExtensions); - // 检查文件扩展名 - if (!fileAllowExtension.Split(',') - .Any(fe => fe.Equals(fileExtensionName, StringComparison.CurrentCultureIgnoreCase))) - { - ThrowValidationException(L["NotAllowedFileExtensionName", fileExtensionName], "FileName"); - } - } - - var oss = CreateOssContainer(); - - var createOssObjectRequest = new CreateOssObjectRequest( - input.Bucket, - input.Object, - input.Content, - input.Path, - input.ExpirationTime) - { - Overwrite = input.Overwrite - }; - var ossObject = await oss.CreateObjectAsync(createOssObjectRequest); - - return ObjectMapper.Map(ossObject); - } - - [Authorize(AbpOssManagementPermissions.OssObject.Delete)] - public virtual async Task BulkDeleteAsync(BulkDeleteOssObjectInput input) - { - var oss = CreateOssContainer(); - - await oss.BulkDeleteObjectsAsync(input.Bucket, input.Objects, input.Path); - } - - [Authorize(AbpOssManagementPermissions.OssObject.Delete)] - public virtual async Task DeleteAsync(GetOssObjectInput input) - { - var oss = CreateOssContainer(); - - await oss.DeleteObjectAsync(input.Bucket, input.Object, input.Path); - } - - public virtual async Task GetAsync(GetOssObjectInput input) - { - var oss = CreateOssContainer(); - - var ossObject = await oss.GetObjectAsync(input.Bucket, input.Object, input.Path); - - return ObjectMapper.Map(ossObject); - } - - protected virtual IOssContainer CreateOssContainer() - { - return OssContainerFactory.Create(); - } - - private static void ThrowValidationException(string message, string memberName) - { - throw new AbpValidationException(message, - new List - { - new ValidationResult(message, new[] {memberName}) - }); - } - } -} +using LINGYUN.Abp.Features.LimitValidation; +using LINGYUN.Abp.OssManagement.Features; +using LINGYUN.Abp.OssManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp.Features; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.OssManagement +{ + [Authorize(AbpOssManagementPermissions.OssObject.Default)] + public class OssObjectAppService : OssManagementApplicationServiceBase, IOssObjectAppService + { + protected IFileValidater FileValidater { get; } + protected IOssContainerFactory OssContainerFactory { get; } + + public OssObjectAppService( + IFileValidater fileValidater, + IOssContainerFactory ossContainerFactory) + { + FileValidater = fileValidater; + OssContainerFactory = ossContainerFactory; + } + + [Authorize(AbpOssManagementPermissions.OssObject.Create)] + [RequiresFeature(AbpOssManagementFeatureNames.OssObject.UploadFile)] + [RequiresLimitFeature( + AbpOssManagementFeatureNames.OssObject.UploadLimit, + AbpOssManagementFeatureNames.OssObject.UploadInterval, + LimitPolicy.Month)] + public virtual async Task CreateAsync(CreateOssObjectInput input) + { + if (!input.Content.IsNullOrEmpty()) + { + await FileValidater.ValidationAsync(new UploadFile + { + TotalSize = input.Content.Length, + FileName = input.Object + }); + } + + var oss = CreateOssContainer(); + + var createOssObjectRequest = new CreateOssObjectRequest( + input.Bucket, + input.Object, + input.Content, + input.Path, + input.ExpirationTime) + { + Overwrite = input.Overwrite + }; + var ossObject = await oss.CreateObjectAsync(createOssObjectRequest); + + return ObjectMapper.Map(ossObject); + } + + [Authorize(AbpOssManagementPermissions.OssObject.Delete)] + public virtual async Task BulkDeleteAsync(BulkDeleteOssObjectInput input) + { + var oss = CreateOssContainer(); + + await oss.BulkDeleteObjectsAsync(input.Bucket, input.Objects, input.Path); + } + + [Authorize(AbpOssManagementPermissions.OssObject.Delete)] + public virtual async Task DeleteAsync(GetOssObjectInput input) + { + var oss = CreateOssContainer(); + + await oss.DeleteObjectAsync(input.Bucket, input.Object, input.Path); + } + + public virtual async Task GetAsync(GetOssObjectInput input) + { + var oss = CreateOssContainer(); + + var ossObject = await oss.GetObjectAsync(input.Bucket, input.Object, input.Path); + + return ObjectMapper.Map(ossObject); + } + + protected virtual IOssContainer CreateOssContainer() + { + return OssContainerFactory.Create(); + } + + private static void ThrowValidationException(string message, string memberName) + { + throw new AbpValidationException(message, + new List + { + new ValidationResult(message, new[] {memberName}) + }); + } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PublicFileAppService.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PublicFileAppService.cs index 4473a1b96..0d802e7f8 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PublicFileAppService.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PublicFileAppService.cs @@ -1,89 +1,16 @@ -using LINGYUN.Abp.Features.LimitValidation; -using LINGYUN.Abp.OssManagement.Features; -using Microsoft.AspNetCore.Authorization; -using System.IO; -using System.Threading.Tasks; -using System.Web; -using Volo.Abp; -using Volo.Abp.Features; -using Volo.Abp.Users; - -namespace LINGYUN.Abp.OssManagement +namespace LINGYUN.Abp.OssManagement { - /// - /// 所有登录用户公开访问文件服务接口 - /// bucket限制在users - /// path限制在用户id - /// - [Authorize] - // 不对外公开,仅通过控制器调用 - [RemoteService(IsEnabled = false, IsMetadataEnabled = false)] - public class PublicFileAppService : OssManagementApplicationServiceBase, IPublicFileAppService + public class PublicFileAppService : FileAppServiceBase, IPublicFileAppService { - private readonly IFileValidater _fileValidater; - private readonly IOssContainerFactory _ossContainerFactory; - public PublicFileAppService( IFileValidater fileValidater, IOssContainerFactory ossContainerFactory) + : base(fileValidater, ossContainerFactory) { - _fileValidater = fileValidater; - _ossContainerFactory = ossContainerFactory; } - - [RequiresFeature(AbpOssManagementFeatureNames.OssObject.UploadFile)] - [RequiresLimitFeature( - AbpOssManagementFeatureNames.OssObject.UploadLimit, - AbpOssManagementFeatureNames.OssObject.UploadInterval, - LimitPolicy.Month)] - public virtual async Task UploadAsync(UploadPublicFileInput input) + protected override string GetCurrentBucket() { - await _fileValidater.ValidationAsync(new UploadFile - { - TotalSize = input.Content.Length, - FileName = input.Object - }); - - var oss = _ossContainerFactory.Create(); - - var createOssObjectRequest = new CreateOssObjectRequest( - "users", - HttpUtility.UrlDecode(input.Object), - input.Content, - GetCurrentUserPath(HttpUtility.UrlDecode(input.Path))) - { - Overwrite = input.Overwrite - }; - - var ossObject = await oss.CreateObjectAsync(createOssObjectRequest); - - return ObjectMapper.Map(ossObject); - } - - [RequiresFeature(AbpOssManagementFeatureNames.OssObject.DownloadFile)] - [RequiresLimitFeature( - AbpOssManagementFeatureNames.OssObject.DownloadLimit, - AbpOssManagementFeatureNames.OssObject.DownloadInterval, - LimitPolicy.Month)] - public virtual async Task GetAsync(GetPublicFileInput input) - { - var ossObjectRequest = new GetOssObjectRequest( - "users", // 需要处理特殊字符 - HttpUtility.UrlDecode(input.Name), - GetCurrentUserPath(HttpUtility.UrlDecode(input.Path)), - HttpUtility.UrlDecode(input.Process)); - - var ossContainer = _ossContainerFactory.Create(); - var ossObject = await ossContainer.GetObjectAsync(ossObjectRequest); - - return ossObject.Content; - } - - private string GetCurrentUserPath(string path) - { - path = path.StartsWith("/") ? path.Substring(1) : path; - var userId = CurrentUser.GetId().ToString(); - return path.StartsWith(userId) ? path : $"{userId}/{path}"; + return "public"; } } } diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN.Abp.OssManagement.Domain.Shared.csproj b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN.Abp.OssManagement.Domain.Shared.csproj index 683c05848..66323bc06 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN.Abp.OssManagement.Domain.Shared.csproj +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN.Abp.OssManagement.Domain.Shared.csproj @@ -1,4 +1,4 @@ - + @@ -18,7 +18,8 @@ - + + diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/AbpOssManagementDomainSharedModule.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/AbpOssManagementDomainSharedModule.cs index 1479ef76c..ec260106f 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/AbpOssManagementDomainSharedModule.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/AbpOssManagementDomainSharedModule.cs @@ -1,36 +1,36 @@ -using LINGYUN.Abp.OssManagement.Localization; -using Volo.Abp.Localization; -using Volo.Abp.Localization.ExceptionHandling; -using Volo.Abp.Modularity; -using Volo.Abp.Validation; -using Volo.Abp.Validation.Localization; -using Volo.Abp.VirtualFileSystem; - -namespace LINGYUN.Abp.OssManagement -{ - [DependsOn(typeof(AbpValidationModule))] - public class AbpOssManagementDomainSharedModule : AbpModule - { - public override void ConfigureServices(ServiceConfigurationContext context) - { - Configure(options => - { - options.FileSets.AddEmbedded(); - }); - - Configure(options => - { - options.Resources - .Add("en") - .AddBaseTypes( - typeof(AbpValidationResource) - ).AddVirtualJson("/LINGYUN/Abp/OssManagement/Localization/Resources"); - }); - - Configure(options => - { - options.MapCodeNamespace(OssManagementErrorCodes.Namespace, typeof(AbpOssManagementResource)); - }); - } - } -} +using LINGYUN.Abp.OssManagement.Localization; +using Volo.Abp.Features; +using Volo.Abp.Localization; +using Volo.Abp.Localization.ExceptionHandling; +using Volo.Abp.Modularity; +using Volo.Abp.Validation; +using Volo.Abp.VirtualFileSystem; + +namespace LINGYUN.Abp.OssManagement +{ + [DependsOn( + typeof(AbpFeaturesModule), + typeof(AbpValidationModule))] + public class AbpOssManagementDomainSharedModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Add("en") + .AddVirtualJson("/LINGYUN/Abp/OssManagement/Localization/Resources"); + }); + + Configure(options => + { + options.MapCodeNamespace(OssManagementErrorCodes.Namespace, typeof(AbpOssManagementResource)); + }); + } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/en.json b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/en.json index 6e7560e11..58d760a60 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/en.json +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/en.json @@ -1,6 +1,7 @@ { "culture": "en", "texts": { + "Abp.OssManagement:010000": "System definition containers cannot be deleted!", "Abp.OssManagement:010001": "Cannot delete a container that has more than one object!", "Abp.OssManagement:010402": "The container name already exists!", "Abp.OssManagement:010404": "The queried container could not be found!", diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/zh-Hans.json b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/zh-Hans.json index 278a99068..262a849a8 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/zh-Hans.json @@ -1,6 +1,7 @@ { "culture": "zh-Hans", "texts": { + "Abp.OssManagement:010000": "不能删除系统定义容器!", "Abp.OssManagement:010001": "不能删除存在多个对象的容器!", "Abp.OssManagement:010402": "容器名称已经存在!", "Abp.OssManagement:010404": "未能找到查询的容器!", diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/OssManagementErrorCodes.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/OssManagementErrorCodes.cs index 6a4b57251..aa2915c8b 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/OssManagementErrorCodes.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/OssManagementErrorCodes.cs @@ -1,17 +1,18 @@ -namespace LINGYUN.Abp.OssManagement -{ - public static class OssManagementErrorCodes - { - public const string Namespace = "Abp.OssManagement"; - - public const string ContainerDeleteWithNotEmpty = Namespace + ":010001"; - public const string ContainerAlreadyExists = Namespace + ":010402"; - public const string ContainerNotFound = Namespace + ":010404"; - - public const string ObjectDeleteWithNotEmpty = Namespace + ":020001"; - public const string ObjectAlreadyExists = Namespace + ":020402"; - public const string ObjectNotFound = Namespace + ":020404"; - - public const string OssNameHasTooLong = Namespace + ":000405"; - } -} +namespace LINGYUN.Abp.OssManagement +{ + public static class OssManagementErrorCodes + { + public const string Namespace = "Abp.OssManagement"; + + public const string ContainerDeleteWithStatic = Namespace + ":010000"; + public const string ContainerDeleteWithNotEmpty = Namespace + ":010001"; + public const string ContainerAlreadyExists = Namespace + ":010402"; + public const string ContainerNotFound = Namespace + ":010404"; + + public const string ObjectDeleteWithNotEmpty = Namespace + ":020001"; + public const string ObjectAlreadyExists = Namespace + ":020402"; + public const string ObjectNotFound = Namespace + ":020404"; + + public const string OssNameHasTooLong = Namespace + ":000405"; + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/AbpOssManagementDomainModule.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/AbpOssManagementDomainModule.cs index 660c38007..782e06ceb 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/AbpOssManagementDomainModule.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/AbpOssManagementDomainModule.cs @@ -1,17 +1,32 @@ -using LINGYUN.Abp.Features.LimitValidation; -using Volo.Abp.Domain; -using Volo.Abp.Modularity; -using Volo.Abp.MultiTenancy; - -namespace LINGYUN.Abp.OssManagement -{ - [DependsOn( - typeof(AbpDddDomainModule), - typeof(AbpMultiTenancyModule), - typeof(AbpFeaturesLimitValidationModule), - typeof(AbpOssManagementDomainSharedModule) - )] - public class AbpOssManagementDomainModule : AbpModule - { - } -} +using LINGYUN.Abp.Features.LimitValidation; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp; +using Volo.Abp.Domain; +using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.OssManagement +{ + [DependsOn( + typeof(AbpOssManagementDomainSharedModule), + typeof(AbpDddDomainModule), + typeof(AbpMultiTenancyModule), + typeof(AbpFeaturesLimitValidationModule) + )] + public class AbpOssManagementDomainModule : AbpModule + { + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + // TODO: 是否有必要自动创建容器 + var ossOptions = context.ServiceProvider.GetRequiredService>().Value; + var ossFactory = context.ServiceProvider.GetRequiredService(); + var ossContainer = ossFactory.Create(); + + foreach (var bucket in ossOptions.StaticBuckets) + { + _ = ossContainer.CreateIfNotExistsAsync(bucket); + } + } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/AbpOssManagementFileSystemModule.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/AbpOssManagementFileSystemModule.cs index 5434bb019..936016ccf 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/AbpOssManagementFileSystemModule.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/AbpOssManagementFileSystemModule.cs @@ -1,17 +1,19 @@ -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.BlobStoring.FileSystem; -using Volo.Abp.Modularity; - -namespace LINGYUN.Abp.OssManagement.FileSystem -{ - [DependsOn( - typeof(AbpBlobStoringFileSystemModule), - typeof(AbpOssManagementDomainModule))] - public class AbpOssManagementFileSystemModule : AbpModule - { - public override void ConfigureServices(ServiceConfigurationContext context) - { - context.Services.AddTransient(); - } - } -} +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp; +using Volo.Abp.BlobStoring.FileSystem; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.OssManagement.FileSystem +{ + [DependsOn( + typeof(AbpBlobStoringFileSystemModule), + typeof(AbpOssManagementDomainModule))] + public class AbpOssManagementFileSystemModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddTransient(); + } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/FileSystemOssContainer.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/FileSystemOssContainer.cs index 5e31d3d9c..0a62581c2 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/FileSystemOssContainer.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/FileSystemOssContainer.cs @@ -25,6 +25,7 @@ namespace LINGYUN.Abp.OssManagement.FileSystem protected IBlobContainerConfigurationProvider ConfigurationProvider { get; } protected IServiceProvider ServiceProvider { get; } protected FileSystemOssOptions Options { get; } + protected AbpOssManagementOptions OssOptions { get; } public FileSystemOssContainer( ICurrentTenant currentTenant, @@ -32,7 +33,8 @@ namespace LINGYUN.Abp.OssManagement.FileSystem IServiceProvider serviceProvider, IBlobFilePathCalculator blobFilePathCalculator, IBlobContainerConfigurationProvider configurationProvider, - IOptions options) + IOptions options, + IOptions ossOptions) { CurrentTenant = currentTenant; Environment = environment; @@ -40,6 +42,7 @@ namespace LINGYUN.Abp.OssManagement.FileSystem FilePathCalculator = blobFilePathCalculator; ConfigurationProvider = configurationProvider; Options = options.Value; + OssOptions = ossOptions.Value; } public virtual Task BulkDeleteObjectsAsync(BulkDeleteObjectRequest request) @@ -173,6 +176,8 @@ namespace LINGYUN.Abp.OssManagement.FileSystem public virtual Task DeleteAsync(string name) { + CheckStaticBucket(name); + var filePath = CalculateFilePath(name); if (!Directory.Exists(filePath)) { @@ -533,6 +538,14 @@ namespace LINGYUN.Abp.OssManagement.FileSystem return blobPath; } + protected virtual void CheckStaticBucket(string bucket) + { + if (OssOptions.CheckStaticBucket(bucket)) + { + throw new BusinessException(code: OssManagementErrorCodes.ContainerDeleteWithStatic); + } + } + private void ThrowOfPathHasTooLong(string path) { // Windows 133 260 diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/FileSystemOssContainerFactory.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/FileSystemOssContainerFactory.cs index 2088a3476..7bb617608 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/FileSystemOssContainerFactory.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/FileSystemOssContainerFactory.cs @@ -1,46 +1,50 @@ -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; -using System; -using Volo.Abp.BlobStoring; -using Volo.Abp.BlobStoring.FileSystem; -using Volo.Abp.MultiTenancy; - -namespace LINGYUN.Abp.OssManagement.FileSystem -{ - public class FileSystemOssContainerFactory : IOssContainerFactory - { - protected ICurrentTenant CurrentTenant { get; } - protected IHostEnvironment Environment { get; } - protected IServiceProvider ServiceProvider { get; } - protected IBlobFilePathCalculator FilePathCalculator { get; } - protected IBlobContainerConfigurationProvider ConfigurationProvider { get; } - protected IOptions Options { get; } - - public FileSystemOssContainerFactory( - ICurrentTenant currentTenant, - IHostEnvironment environment, - IServiceProvider serviceProvider, - IBlobFilePathCalculator blobFilePathCalculator, - IBlobContainerConfigurationProvider configurationProvider, - IOptions options) - { - Environment = environment; - CurrentTenant = currentTenant; - ServiceProvider = serviceProvider; - FilePathCalculator = blobFilePathCalculator; - ConfigurationProvider = configurationProvider; - Options = options; - } - - public IOssContainer Create() - { - return new FileSystemOssContainer( - CurrentTenant, - Environment, - ServiceProvider, - FilePathCalculator, - ConfigurationProvider, - Options); - } - } -} +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using System; +using Volo.Abp.BlobStoring; +using Volo.Abp.BlobStoring.FileSystem; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.OssManagement.FileSystem +{ + public class FileSystemOssContainerFactory : IOssContainerFactory + { + protected ICurrentTenant CurrentTenant { get; } + protected IHostEnvironment Environment { get; } + protected IServiceProvider ServiceProvider { get; } + protected IBlobFilePathCalculator FilePathCalculator { get; } + protected IBlobContainerConfigurationProvider ConfigurationProvider { get; } + protected IOptions Options { get; } + protected IOptions OssOptions { get; } + + public FileSystemOssContainerFactory( + ICurrentTenant currentTenant, + IHostEnvironment environment, + IServiceProvider serviceProvider, + IBlobFilePathCalculator blobFilePathCalculator, + IBlobContainerConfigurationProvider configurationProvider, + IOptions options, + IOptions ossOptions) + { + Environment = environment; + CurrentTenant = currentTenant; + ServiceProvider = serviceProvider; + FilePathCalculator = blobFilePathCalculator; + ConfigurationProvider = configurationProvider; + Options = options; + OssOptions = ossOptions; + } + + public IOssContainer Create() + { + return new FileSystemOssContainer( + CurrentTenant, + Environment, + ServiceProvider, + FilePathCalculator, + ConfigurationProvider, + Options, + OssOptions); + } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN.Abp.OssManagement.HttpApi.csproj b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN.Abp.OssManagement.HttpApi.csproj index b74aa373e..6ae3799a6 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN.Abp.OssManagement.HttpApi.csproj +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN.Abp.OssManagement.HttpApi.csproj @@ -12,7 +12,6 @@ - diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/AbpOssManagementHttpApiModule.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/AbpOssManagementHttpApiModule.cs index 05b3ae7e7..1666dd651 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/AbpOssManagementHttpApiModule.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/AbpOssManagementHttpApiModule.cs @@ -1,21 +1,47 @@ -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.Modularity; - -namespace LINGYUN.Abp.OssManagement -{ - [DependsOn( - typeof(AbpOssManagementApplicationContractsModule), - typeof(AbpAspNetCoreMvcModule) - )] - public class AbpOssManagementHttpApiModule : AbpModule - { - public override void PreConfigureServices(ServiceConfigurationContext context) - { - PreConfigure(mvcBuilder => - { - mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpOssManagementHttpApiModule).Assembly); - }); - } - } -} +using LINGYUN.Abp.OssManagement.Localization; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Authorization.Localization; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.Validation.Localization; +using Volo.Abp.AspNetCore.Mvc.DataAnnotations; +using Volo.Abp.AspNetCore.Mvc.Localization; + +namespace LINGYUN.Abp.OssManagement +{ + [DependsOn( + typeof(AbpOssManagementApplicationContractsModule), + typeof(AbpAspNetCoreMvcModule) + )] + public class AbpOssManagementHttpApiModule : AbpModule + { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(mvcBuilder => + { + mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpOssManagementHttpApiModule).Assembly); + }); + + PreConfigure(options => + { + options.AddAssemblyResource( + typeof(AbpOssManagementResource), + typeof(AbpOssManagementApplicationContractsModule).Assembly); + }); + } + + //public override void ConfigureServices(ServiceConfigurationContext context) + //{ + // Configure(options => + // { + // options.Resources + // .Get() + // .AddBaseTypes( + // typeof(AbpAuthorizationResource), + // typeof(AbpValidationResource) + // ); + // }); + //} + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/FileValidater.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/FileValidater.cs deleted file mode 100644 index 746249392..000000000 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/FileValidater.cs +++ /dev/null @@ -1,96 +0,0 @@ -using LINGYUN.Abp.OssManagement.Localization; -using LINGYUN.Abp.OssManagement.Settings; -using Microsoft.Extensions.Caching.Memory; -using Microsoft.Extensions.Localization; -using System; -using System.Linq; -using System.Threading.Tasks; -using Volo.Abp; -using Volo.Abp.DependencyInjection; -using Volo.Abp.IO; -using Volo.Abp.Settings; - -namespace LINGYUN.Abp.OssManagement -{ - public class FileValidater : IFileValidater, ISingletonDependency - { - private readonly IMemoryCache _cache; - private readonly ISettingProvider _settingProvider; - private readonly IServiceProvider _serviceProvider; - private readonly IStringLocalizer _stringLocalizer; - - public FileValidater( - IMemoryCache cache, - ISettingProvider settingProvider, - IServiceProvider serviceProvider, - IStringLocalizer stringLocalizer) - { - _cache = cache; - _settingProvider = settingProvider; - _serviceProvider = serviceProvider; - _stringLocalizer = stringLocalizer; - } - - public virtual async Task ValidationAsync(UploadOssObjectInput input) - { - var validation = await GetByCacheItemAsync(); - if (validation.SizeLimit * 1024 * 1024 < input.TotalSize) - { - throw new UserFriendlyException(_stringLocalizer["UploadFileSizeBeyondLimit", validation.SizeLimit]); - } - var fileExtensionName = FileHelper.GetExtension(input.FileName); - if (!validation.AllowedExtensions - .Any(fe => fe.Equals(fileExtensionName, StringComparison.CurrentCultureIgnoreCase))) - { - throw new UserFriendlyException(_stringLocalizer["NotAllowedFileExtensionName", fileExtensionName]); - } - } - - protected virtual async Task GetByCacheItemAsync() - { - var fileValidation = _cache.Get(FileValidation.CacheKey); - if (fileValidation == null) - { - fileValidation = await GetBySettingAsync(); - _cache.Set(FileValidation.CacheKey, - fileValidation, - new MemoryCacheEntryOptions - { - AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(2) - }); - } - return fileValidation; - } - - protected virtual async Task GetBySettingAsync() - { - var fileSizeLimited = await _settingProvider - .GetAsync( - AbpOssManagementSettingNames.FileLimitLength, - AbpOssManagementSettingNames.DefaultFileLimitLength); - var fileAllowExtension = await _settingProvider - .GetOrDefaultAsync(AbpOssManagementSettingNames.AllowFileExtensions, _serviceProvider); - - return new FileValidation(fileSizeLimited, fileAllowExtension.Split(',')); - } - } - - public class FileValidation - { - public const string CacheKey = "Abp.OssManagement.FileValidation"; - public long SizeLimit { get; set; } - public string[] AllowedExtensions { get; set; } - public FileValidation() - { - - } - - public FileValidation( - long sizeLimit, - string[] allowedExtensions) - { - SizeLimit = sizeLimit; - AllowedExtensions = allowedExtensions; - } - } -} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/IFileValidater.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/IFileValidater.cs deleted file mode 100644 index 2f9446e26..000000000 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/IFileValidater.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Threading.Tasks; - -namespace LINGYUN.Abp.OssManagement -{ - public interface IFileValidater - { - Task ValidationAsync(UploadOssObjectInput input); - } -} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/StaticFilesController.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/StaticFilesController.cs index b0303b976..d07942c02 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/StaticFilesController.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/StaticFilesController.cs @@ -1,7 +1,6 @@ using LINGYUN.Abp.OssManagement.Localization; using LINGYUN.Abp.OssManagement.Permissions; using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -15,9 +14,10 @@ using Volo.Abp.Validation; namespace LINGYUN.Abp.OssManagement { - [RemoteService(Name = OssManagementRemoteServiceConsts.RemoteServiceName)] [Area("oss-management")] [Route("api/files/static")] + [RemoteService(false)] + [ApiExplorerSettings(IgnoreApi = true)] public class StaticFilesController : AbpController { private readonly IOssObjectAppService _ossObjectAppService; diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/UploadOssObjectInput.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/UploadOssObjectInput.cs index 2341a35ab..a75819221 100644 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/UploadOssObjectInput.cs +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/UploadOssObjectInput.cs @@ -3,18 +3,13 @@ using System.ComponentModel.DataAnnotations; namespace LINGYUN.Abp.OssManagement { - public class UploadOssObjectInput + public class UploadOssObjectInput : UploadFile { public string Bucket { get; set; } public string Path { get; set; } #region 配合Uplaoder 分块传输 /// - /// 文件名 - /// - [Required] - public string FileName { get; set; } - /// /// 常规块大小 /// [Required] @@ -34,11 +29,6 @@ namespace LINGYUN.Abp.OssManagement /// [Required] public int TotalChunks { get; set; } - /// - /// 总文件大小 - /// - [Required] - public long TotalSize { get; set; } #endregion diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.SettingManagement/AbpOssManagementSettingManagementModule.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.SettingManagement/AbpOssManagementSettingManagementModule.cs deleted file mode 100644 index 8d30e73f2..000000000 --- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.SettingManagement/AbpOssManagementSettingManagementModule.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.Modularity; - -namespace LINGYUN.Abp.OssManagement.SettingManagement -{ - [DependsOn( - typeof(AbpOssManagementApplicationContractsModule), - typeof(AbpAspNetCoreMvcModule))] - public class AbpOssManagementSettingManagementModule : AbpModule - { - public override void PreConfigureServices(ServiceConfigurationContext context) - { - PreConfigure(mvcBuilder => - { - mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpOssManagementSettingManagementModule).Assembly); - }); - } - } -} diff --git a/aspnet-core/modules/oss-management/README.md b/aspnet-core/modules/oss-management/README.md index 9bd5a6546..d82dd708a 100644 --- a/aspnet-core/modules/oss-management/README.md +++ b/aspnet-core/modules/oss-management/README.md @@ -1,50 +1,51 @@ -# Oss-Management - -File-Management更名为Oss-Management - -## 模块说明 - -### 基础模块 - -* [LINGYUN.Abp.OssManagement.Domain.Shared](./LINGYUN.Abp.OssManagement.Domain.Shared) 领域层公共模块,定义了错误代码、本地化、模块设置 -* [LINGYUN.Abp.OssManagement.Domain](./LINGYUN.Abp.OssManagement.Domain) 领域层模块,定义了抽象的Oss容器与对象管理接口 -* [LINGYUN.Abp.OssManagement.Application.Contracts](./LINGYUN.Abp.OssManagement.Application.Contracts) 应用服务层公共模块,定义了管理Oss的外部接口、权限、功能限制策略 -* [LINGYUN.Abp.OssManagement.Application](./LINGYUN.Abp.OssManagement.Application) 应用服务层实现,实现了Oss管理接口 -* [LINGYUN.Abp.OssManagement.HttpApi](./LINGYUN.Abp.OssManagement.HttpApi) RestApi实现,实现了独立的对外RestApi接口 -* [LINGYUN.Abp.OssManagement.SettingManagement](./LINGYUN.Abp.OssManagement.SettingManagement) 设置管理模块,对外暴露自身的设置管理,用于网关聚合 - -### 高阶模块 - -* [LINGYUN.Abp.OssManagement.Aliyun](./LINGYUN.Abp.OssManagement.Aliyun) Oss管理的阿里云实现,实现了部分阿里云Oss服务的容器与对象管理 -* [LINGYUN.Abp.OssManagement.FileSystem](./LINGYUN.Abp.OssManagement.FileSystem) Oss管理的本地文件系统实现,实现了部分本地文件系统的容器(目录)与对象(文件/目录)管理 -* [LINGYUN.Abp.OssManagement.FileSystem.ImageSharp](./LINGYUN.Abp.OssManagement.FileSystem.ImageSharp) Oss本地对象的ImageSharp扩展,当前端传递需求处理对象时,此模块用于实现基于图形文件流的处理 - -### 权限定义 - -* AbpOssManagement.Container 授权对象是否允许访问容器(bucket) -* AbpOssManagement.Container.Create 授权对象是否允许创建容器(bucket) -* AbpOssManagement.Container.Delete 授权对象是否允许删除容器(bucket) -* AbpOssManagement.OssObject 授权对象是否允许访问Oss对象 -* AbpOssManagement.OssObject.Create 授权对象是否允许创建Oss对象 -* AbpOssManagement.OssObject.Delete 授权对象是否允许删除Oss对象 -* AbpOssManagement.OssObject.Download 授权对象是否允许下载Oss对象 - -### 功能定义 - -* AbpOssManagement.OssObject.DownloadFile 用户可以下载文件 -* AbpOssManagement.OssObject.DownloadLimit 用户在周期内允许下载文件的最大次数,范围0-1000000 -* AbpOssManagement.OssObject.DownloadInterval 用户限制下载文件次数的周期,时钟刻度:月,默认: 1,范围1-12 -* AbpOssManagement.OssObject.UploadFile 用户可以上传文件 -* AbpOssManagement.OssObject.UploadLimit 用户在周期内允许上传文件的最大次数,范围0-1000000 -* AbpOssManagement.OssObject.UploadInterval 用户限制上传文件次数的周期,时钟刻度:月,默认: 1,范围1-12 -* AbpOssManagement.OssObject.MaxUploadFileCount 单次上传文件的数量,未实现 - -### 配置定义 - -* Abp.OssManagement.DownloadPackageSize 下载分包大小,分块下载时单次传输的数据大小,未实现 -* Abp.OssManagement.FileLimitLength 上传文件限制大小,默认:100 -* Abp.OssManagement.AllowFileExtensions 允许的上传文件扩展名,多个扩展名以逗号分隔,默认:dll,zip,rar,txt,log,xml,config,json,jpeg,jpg,png,bmp,ico,xlsx,xltx,xls,xlt,docs,dots,doc,dot,pptx,potx,ppt,pot,chm - -## 更新日志 - -*【2021-03-10】 变更FileManagement命名空间为OssManagement +# Oss-Management + +File-Management更名为Oss-Management + +## 模块说明 + +### 基础模块 + +* [LINGYUN.Abp.OssManagement.Domain.Shared](./LINGYUN.Abp.OssManagement.Domain.Shared) 领域层公共模块,定义了错误代码、本地化、模块设置 +* [LINGYUN.Abp.OssManagement.Domain](./LINGYUN.Abp.OssManagement.Domain) 领域层模块,定义了抽象的Oss容器与对象管理接口 +* [LINGYUN.Abp.OssManagement.Application.Contracts](./LINGYUN.Abp.OssManagement.Application.Contracts) 应用服务层公共模块,定义了管理Oss的外部接口、权限、功能限制策略 +* [LINGYUN.Abp.OssManagement.Application](./LINGYUN.Abp.OssManagement.Application) 应用服务层实现,实现了Oss管理接口 +* [LINGYUN.Abp.OssManagement.HttpApi](./LINGYUN.Abp.OssManagement.HttpApi) RestApi实现,实现了独立的对外RestApi接口 +* [LINGYUN.Abp.OssManagement.SettingManagement](./LINGYUN.Abp.OssManagement.SettingManagement) 设置管理模块,对外暴露自身的设置管理,用于网关聚合 + +### 高阶模块 + +* [LINGYUN.Abp.OssManagement.Aliyun](./LINGYUN.Abp.OssManagement.Aliyun) Oss管理的阿里云实现,实现了部分阿里云Oss服务的容器与对象管理 +* [LINGYUN.Abp.OssManagement.FileSystem](./LINGYUN.Abp.OssManagement.FileSystem) Oss管理的本地文件系统实现,实现了部分本地文件系统的容器(目录)与对象(文件/目录)管理 +* [LINGYUN.Abp.OssManagement.FileSystem.ImageSharp](./LINGYUN.Abp.OssManagement.FileSystem.ImageSharp) Oss本地对象的ImageSharp扩展,当前端传递需求处理对象时,此模块用于实现基于图形文件流的处理 + +### 权限定义 + +* AbpOssManagement.Container 授权对象是否允许访问容器(bucket) +* AbpOssManagement.Container.Create 授权对象是否允许创建容器(bucket) +* AbpOssManagement.Container.Delete 授权对象是否允许删除容器(bucket) +* AbpOssManagement.OssObject 授权对象是否允许访问Oss对象 +* AbpOssManagement.OssObject.Create 授权对象是否允许创建Oss对象 +* AbpOssManagement.OssObject.Delete 授权对象是否允许删除Oss对象 +* AbpOssManagement.OssObject.Download 授权对象是否允许下载Oss对象 + +### 功能定义 + +* AbpOssManagement.OssObject.DownloadFile 用户可以下载文件 +* AbpOssManagement.OssObject.DownloadLimit 用户在周期内允许下载文件的最大次数,范围0-1000000 +* AbpOssManagement.OssObject.DownloadInterval 用户限制下载文件次数的周期,时钟刻度:月,默认: 1,范围1-12 +* AbpOssManagement.OssObject.UploadFile 用户可以上传文件 +* AbpOssManagement.OssObject.UploadLimit 用户在周期内允许上传文件的最大次数,范围0-1000000 +* AbpOssManagement.OssObject.UploadInterval 用户限制上传文件次数的周期,时钟刻度:月,默认: 1,范围1-12 +* AbpOssManagement.OssObject.MaxUploadFileCount 单次上传文件的数量,未实现 + +### 配置定义 + +* Abp.OssManagement.DownloadPackageSize 下载分包大小,分块下载时单次传输的数据大小,未实现 +* Abp.OssManagement.FileLimitLength 上传文件限制大小,默认:100 +* Abp.OssManagement.AllowFileExtensions 允许的上传文件扩展名,多个扩展名以逗号分隔,默认:dll,zip,rar,txt,log,xml,config,json,jpeg,jpg,png,bmp,ico,xlsx,xltx,xls,xlt,docs,dots,doc,dot,pptx,potx,ppt,pot,chm + +## 更新日志 + +*【2021-03-10】 变更FileManagement命名空间为OssManagement +*【2021-10-22】 增加PublicFilesController用于身份认证通过的用户上传/下载文件,所有操作限定在用户目录下 diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs index eea1836db..48c8d4f9b 100644 --- a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs @@ -1,333 +1,342 @@ -using DotNetCore.CAP; -using LINGYUN.Abp.AspNetCore.HttpOverrides; -using LINGYUN.Abp.EventBus.CAP; -using LINGYUN.Abp.ExceptionHandling; -using LINGYUN.Abp.ExceptionHandling.Emailing; -using LINGYUN.Abp.Features.LimitValidation.Redis; -using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; -using LINGYUN.Abp.MultiTenancy.DbFinder; -using LINGYUN.Abp.Notifications; -using LINGYUN.Abp.OssManagement; -using LINGYUN.Abp.OssManagement.FileSystem; -using LINGYUN.Abp.OssManagement.FileSystem.ImageSharp; -using LINGYUN.Abp.OssManagement.SettingManagement; -using LINGYUN.Platform.EntityFrameworkCore; -using LINGYUN.Platform.HttpApi; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.DataProtection; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.Extensions.Caching.StackExchangeRedis; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.OpenApi.Models; -using StackExchange.Redis; -using System; -using System.IO; -using System.Text; -using System.Text.Encodings.Web; -using System.Text.Unicode; -using Volo.Abp; -using Volo.Abp.AspNetCore.Authentication.JwtBearer; -using Volo.Abp.AspNetCore.MultiTenancy; -using Volo.Abp.AspNetCore.Security.Claims; -using Volo.Abp.Auditing; -using Volo.Abp.AuditLogging.EntityFrameworkCore; -using Volo.Abp.Autofac; -using Volo.Abp.BlobStoring; -using Volo.Abp.BlobStoring.FileSystem; -using Volo.Abp.Caching; -using Volo.Abp.Caching.StackExchangeRedis; -using Volo.Abp.Data; -using Volo.Abp.EntityFrameworkCore; -using Volo.Abp.FeatureManagement.EntityFrameworkCore; -using Volo.Abp.Http.Client.IdentityModel.Web; -using Volo.Abp.Identity; -using Volo.Abp.Json; -using Volo.Abp.Json.SystemTextJson; -using Volo.Abp.Localization; -using Volo.Abp.Modularity; -using Volo.Abp.MultiTenancy; -using Volo.Abp.PermissionManagement.EntityFrameworkCore; -using Volo.Abp.Security.Claims; -using Volo.Abp.Security.Encryption; -using Volo.Abp.SettingManagement.EntityFrameworkCore; -using Volo.Abp.TenantManagement.EntityFrameworkCore; -using Volo.Abp.Threading; -using Volo.Abp.VirtualFileSystem; - -namespace LINGYUN.Platform -{ - [DependsOn( - // typeof(AbpOssManagementAliyunModule), - typeof(AbpOssManagementFileSystemModule), // 本地文件系统提供者模块 - typeof(AbpOssManagementFileSystemImageSharpModule), // 本地文件系统图形处理模块 - typeof(AbpOssManagementApplicationModule), - typeof(AbpOssManagementHttpApiModule), - typeof(AbpOssManagementSettingManagementModule), - typeof(PlatformApplicationModule), - typeof(PlatformHttpApiModule), - typeof(PlatformEntityFrameworkCoreModule), - typeof(AbpIdentityHttpApiClientModule), - typeof(AbpHttpClientIdentityModelWebModule), - typeof(AbpAspNetCoreMultiTenancyModule), - typeof(AbpFeatureManagementEntityFrameworkCoreModule), - typeof(AbpAuditLoggingEntityFrameworkCoreModule), - typeof(AbpTenantManagementEntityFrameworkCoreModule), - typeof(AbpSettingManagementEntityFrameworkCoreModule), - typeof(AbpPermissionManagementEntityFrameworkCoreModule), - typeof(AbpLocalizationManagementEntityFrameworkCoreModule), - typeof(AbpAspNetCoreAuthenticationJwtBearerModule), - typeof(AbpNotificationModule), - typeof(AbpEmailingExceptionHandlingModule), - typeof(AbpCAPEventBusModule), - typeof(AbpFeaturesValidationRedisModule), - // typeof(AbpFeaturesClientModule),// 当需要客户端特性限制时取消注释此模块 - // typeof(AbpFeaturesValidationRedisClientModule),// 当需要客户端特性限制时取消注释此模块 - typeof(AbpDbFinderMultiTenancyModule), - typeof(AbpCachingStackExchangeRedisModule), - typeof(AbpAspNetCoreHttpOverridesModule), - typeof(AbpAutofacModule) - )] - public class AppPlatformHttpApiHostModule : AbpModule - { - public override void PreConfigureServices(ServiceConfigurationContext context) - { - var configuration = context.Services.GetConfiguration(); - - PreConfigure(options => - { - options - .UseMySql(configuration.GetConnectionString("Default")) - .UseRabbitMQ(rabbitMQOptions => - { - configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions); - }) - .UseDashboard(); - }); - } - - public override void ConfigureServices(ServiceConfigurationContext context) - { - var hostingEnvironment = context.Services.GetHostingEnvironment(); - var configuration = hostingEnvironment.BuildConfiguration(); - - // 配置Ef - Configure(options => - { - options.UseMySQL(); - }); - - //// 中文序列化的编码问题 - Configure(options => - { - options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); - }); - - Configure(options => - { - options.Limits.MaxRequestBodySize = null; - options.Limits.MaxRequestBufferSize = null; - }); - - Configure(options => - { - options.Containers.ConfigureAll((containerName, containerConfiguration) => - { - containerConfiguration.UseFileSystem(fileSystem => - { - fileSystem.BasePath = Path.Combine(Directory.GetCurrentDirectory(), "file-blob-storing"); - }); - }); - }); - - // 加解密 - Configure(options => - { - var encryptionConfiguration = configuration.GetSection("Encryption"); - if (encryptionConfiguration.Exists()) - { - options.DefaultPassPhrase = encryptionConfiguration["PassPhrase"] ?? options.DefaultPassPhrase; - options.DefaultSalt = encryptionConfiguration.GetSection("Salt").Exists() - ? Encoding.ASCII.GetBytes(encryptionConfiguration["Salt"]) - : options.DefaultSalt; - options.InitVectorBytes = encryptionConfiguration.GetSection("InitVector").Exists() - ? Encoding.ASCII.GetBytes(encryptionConfiguration["InitVector"]) - : options.InitVectorBytes; - } - }); - - // 自定义需要处理的异常 - Configure(options => - { - // 加入需要处理的异常类型 - options.Handlers.Add(); - options.Handlers.Add(); - options.Handlers.Add(); - options.Handlers.Add(); - options.Handlers.Add(); - options.Handlers.Add(); - options.Handlers.Add(); - options.Handlers.Add(); - }); - // 自定义需要发送邮件通知的异常类型 - Configure(options => - { - // 是否发送堆栈信息 - options.SendStackTrace = true; - // 未指定异常接收者的默认接收邮件 - // 指定自己的邮件地址 - // options.DefaultReceiveEmail = "colin.in@foxmail.com"; - }); - - Configure(options => - { - // 最好统一命名,不然某个缓存变动其他应用服务有例外发生 - options.KeyPrefix = "LINGYUN.Abp.Application"; - // 滑动过期30天 - options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30); - // 绝对过期60天 - options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60); - }); - - Configure(options => - { - var redisConfig = ConfigurationOptions.Parse(options.Configuration); - options.ConfigurationOptions = redisConfig; - options.InstanceName = configuration["Redis:InstanceName"]; - }); - - Configure(options => - { - options.FileSets.AddEmbedded("LINGYUN.Platform"); - }); - - // 多租户 - Configure(options => - { - options.IsEnabled = true; - }); - - Configure(options => - { - options.ApplicationName = "Platform"; - // 是否启用实体变更记录 - var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged"); - if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get()) - { - options - .EntityHistorySelectors - .AddAllEntities(); - } - }); - - // Swagger - context.Services.AddSwaggerGen( - options => - { - options.SwaggerDoc("v1", new OpenApiInfo { Title = "Platform API", Version = "v1" }); - options.DocInclusionPredicate((docName, description) => true); - options.CustomSchemaIds(type => type.FullName); - options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme - { - Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", - Name = "Authorization", - In = ParameterLocation.Header, - Scheme = "bearer", - Type = SecuritySchemeType.Http, - BearerFormat = "JWT" - }); - options.AddSecurityRequirement(new OpenApiSecurityRequirement - { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } - }, - new string[] { } - } - }); - }); - - // 支持本地化语言类型 - Configure(options => - { - options.Languages.Add(new LanguageInfo("en", "en", "English")); - options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); - - options.Resources.AddDynamic(); - }); - - Configure(options => - { - options.Maps.TryAdd("name", () => AbpClaimTypes.UserName); - }); - - context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) - .AddJwtBearer(options => - { - options.Authority = configuration["AuthServer:Authority"]; - options.RequireHttpsMetadata = false; - options.Audience = configuration["AuthServer:ApiName"]; - }); - - if (!hostingEnvironment.IsDevelopment()) - { - var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); - context.Services - .AddDataProtection() - .PersistKeysToStackExchangeRedis(redis, "Platform-Protection-Keys"); - } - } - - //public override void OnPostApplicationInitialization(ApplicationInitializationContext context) - //{ - // var backgroundJobManager = context.ServiceProvider.GetRequiredService(); - // // 五分钟执行一次的定时任务 - // AsyncHelper.RunSync(async () => await - // backgroundJobManager.EnqueueAsync(CronGenerator.Minute(5), new NotificationCleanupExpritionJobArgs(200))); - //} - - public override void OnApplicationInitialization(ApplicationInitializationContext context) - { - var app = context.GetApplicationBuilder(); - var env = context.GetEnvironment(); - // http调用链 - app.UseCorrelationId(); - // 虚拟文件系统 - app.UseStaticFiles(); - // 本地化 - app.UseAbpRequestLocalization(); - // 多租户 - app.UseMultiTenancy(); - //路由 - app.UseRouting(); - // 认证 - app.UseAuthentication(); - // jwt - app.UseJwtTokenMiddleware(); - // 授权 - app.UseAuthorization(); - // Swagger - app.UseSwagger(); - // Swagger可视化界面 - app.UseSwaggerUI(options => - { - options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support Platform API"); - }); - // 审计日志 - app.UseAuditing(); - // 路由 - app.UseConfiguredEndpoints(); - - if (env.IsDevelopment()) - { - AsyncHelper.RunSync(async () => - await app.ApplicationServices.GetRequiredService() - .SeedAsync()); - } - } - } -} +using DotNetCore.CAP; +using LINGYUN.Abp.AspNetCore.HttpOverrides; +using LINGYUN.Abp.EventBus.CAP; +using LINGYUN.Abp.ExceptionHandling; +using LINGYUN.Abp.ExceptionHandling.Emailing; +using LINGYUN.Abp.Features.LimitValidation.Redis; +using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; +using LINGYUN.Abp.MultiTenancy.DbFinder; +using LINGYUN.Abp.Notifications; +using LINGYUN.Abp.OssManagement; +using LINGYUN.Abp.OssManagement.FileSystem; +using LINGYUN.Abp.OssManagement.FileSystem.ImageSharp; +using LINGYUN.Abp.OssManagement.SettingManagement; +using LINGYUN.Platform.EntityFrameworkCore; +using LINGYUN.Platform.HttpApi; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.Caching.StackExchangeRedis; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.OpenApi.Models; +using StackExchange.Redis; +using System; +using System.IO; +using System.Text; +using System.Text.Encodings.Web; +using System.Text.Unicode; +using Volo.Abp; +using Volo.Abp.AspNetCore.Authentication.JwtBearer; +using Volo.Abp.AspNetCore.MultiTenancy; +using Volo.Abp.AspNetCore.Security.Claims; +using Volo.Abp.Auditing; +using Volo.Abp.AuditLogging.EntityFrameworkCore; +using Volo.Abp.Autofac; +using Volo.Abp.BlobStoring; +using Volo.Abp.BlobStoring.FileSystem; +using Volo.Abp.Caching; +using Volo.Abp.Caching.StackExchangeRedis; +using Volo.Abp.Data; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.FeatureManagement.EntityFrameworkCore; +using Volo.Abp.Http.Client.IdentityModel.Web; +using Volo.Abp.Identity; +using Volo.Abp.Json; +using Volo.Abp.Json.SystemTextJson; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; +using Volo.Abp.PermissionManagement.EntityFrameworkCore; +using Volo.Abp.Security.Claims; +using Volo.Abp.Security.Encryption; +using Volo.Abp.SettingManagement.EntityFrameworkCore; +using Volo.Abp.TenantManagement.EntityFrameworkCore; +using Volo.Abp.Threading; +using Volo.Abp.VirtualFileSystem; + +namespace LINGYUN.Platform +{ + [DependsOn( + // typeof(AbpOssManagementAliyunModule), + typeof(AbpOssManagementFileSystemModule), // 本地文件系统提供者模块 + typeof(AbpOssManagementFileSystemImageSharpModule), // 本地文件系统图形处理模块 + typeof(AbpOssManagementApplicationModule), + typeof(AbpOssManagementHttpApiModule), + typeof(AbpOssManagementSettingManagementModule), + typeof(PlatformApplicationModule), + typeof(PlatformHttpApiModule), + typeof(PlatformEntityFrameworkCoreModule), + typeof(AbpIdentityHttpApiClientModule), + typeof(AbpHttpClientIdentityModelWebModule), + typeof(AbpAspNetCoreMultiTenancyModule), + typeof(AbpFeatureManagementEntityFrameworkCoreModule), + typeof(AbpAuditLoggingEntityFrameworkCoreModule), + typeof(AbpTenantManagementEntityFrameworkCoreModule), + typeof(AbpSettingManagementEntityFrameworkCoreModule), + typeof(AbpPermissionManagementEntityFrameworkCoreModule), + typeof(AbpLocalizationManagementEntityFrameworkCoreModule), + typeof(AbpAspNetCoreAuthenticationJwtBearerModule), + typeof(AbpNotificationModule), + typeof(AbpEmailingExceptionHandlingModule), + typeof(AbpCAPEventBusModule), + typeof(AbpFeaturesValidationRedisModule), + // typeof(AbpFeaturesClientModule),// 当需要客户端特性限制时取消注释此模块 + // typeof(AbpFeaturesValidationRedisClientModule),// 当需要客户端特性限制时取消注释此模块 + typeof(AbpDbFinderMultiTenancyModule), + typeof(AbpCachingStackExchangeRedisModule), + typeof(AbpAspNetCoreHttpOverridesModule), + typeof(AbpAutofacModule) + )] + public class AppPlatformHttpApiHostModule : AbpModule + { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + PreConfigure(options => + { + options + .UseMySql(configuration.GetConnectionString("Default")) + .UseRabbitMQ(rabbitMQOptions => + { + configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions); + }) + .UseDashboard(); + }); + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = hostingEnvironment.BuildConfiguration(); + + // 配置Ef + Configure(options => + { + options.UseMySQL(); + }); + + //// 中文序列化的编码问题 + Configure(options => + { + options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); + }); + + Configure(options => + { + options.Limits.MaxRequestBodySize = null; + options.Limits.MaxRequestBufferSize = null; + }); + + Configure(options => + { + options.Containers.ConfigureAll((containerName, containerConfiguration) => + { + containerConfiguration.UseFileSystem(fileSystem => + { + fileSystem.BasePath = Path.Combine(Directory.GetCurrentDirectory(), "file-blob-storing"); + }); + }); + }); + + // 加解密 + Configure(options => + { + var encryptionConfiguration = configuration.GetSection("Encryption"); + if (encryptionConfiguration.Exists()) + { + options.DefaultPassPhrase = encryptionConfiguration["PassPhrase"] ?? options.DefaultPassPhrase; + options.DefaultSalt = encryptionConfiguration.GetSection("Salt").Exists() + ? Encoding.ASCII.GetBytes(encryptionConfiguration["Salt"]) + : options.DefaultSalt; + options.InitVectorBytes = encryptionConfiguration.GetSection("InitVector").Exists() + ? Encoding.ASCII.GetBytes(encryptionConfiguration["InitVector"]) + : options.InitVectorBytes; + } + }); + + // 自定义需要处理的异常 + Configure(options => + { + // 加入需要处理的异常类型 + options.Handlers.Add(); + options.Handlers.Add(); + options.Handlers.Add(); + options.Handlers.Add(); + options.Handlers.Add(); + options.Handlers.Add(); + options.Handlers.Add(); + options.Handlers.Add(); + }); + + Configure(options => + { + // 是否发送错误详情 + options.SendExceptionsDetailsToClients = false; + }); + + // 自定义需要发送邮件通知的异常类型 + Configure(options => + { + // 是否发送堆栈信息 + options.SendStackTrace = true; + // 未指定异常接收者的默认接收邮件 + // 指定自己的邮件地址 + // options.DefaultReceiveEmail = "colin.in@foxmail.com"; + }); + + Configure(options => + { + // 最好统一命名,不然某个缓存变动其他应用服务有例外发生 + options.KeyPrefix = "LINGYUN.Abp.Application"; + // 滑动过期30天 + options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30); + // 绝对过期60天 + options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60); + }); + + Configure(options => + { + var redisConfig = ConfigurationOptions.Parse(options.Configuration); + options.ConfigurationOptions = redisConfig; + options.InstanceName = configuration["Redis:InstanceName"]; + }); + + Configure(options => + { + options.FileSets.AddEmbedded("LINGYUN.Platform"); + }); + + // 多租户 + Configure(options => + { + options.IsEnabled = true; + }); + + Configure(options => + { + options.ApplicationName = "Platform"; + // 是否启用实体变更记录 + var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged"); + if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get()) + { + options + .EntityHistorySelectors + .AddAllEntities(); + } + }); + + // Swagger + context.Services.AddSwaggerGen( + options => + { + options.SwaggerDoc("v1", new OpenApiInfo { Title = "Platform API", Version = "v1" }); + options.DocInclusionPredicate((docName, description) => true); + options.CustomSchemaIds(type => type.FullName); + options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", + Name = "Authorization", + In = ParameterLocation.Header, + Scheme = "bearer", + Type = SecuritySchemeType.Http, + BearerFormat = "JWT" + }); + options.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } + }, + new string[] { } + } + }); + }); + + // 支持本地化语言类型 + Configure(options => + { + options.Languages.Add(new LanguageInfo("en", "en", "English")); + options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); + + options.Resources.AddDynamic(); + }); + + Configure(options => + { + options.Maps.TryAdd("name", () => AbpClaimTypes.UserName); + }); + + context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(options => + { + options.Authority = configuration["AuthServer:Authority"]; + options.RequireHttpsMetadata = false; + options.Audience = configuration["AuthServer:ApiName"]; + }); + + if (!hostingEnvironment.IsDevelopment()) + { + var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); + context.Services + .AddDataProtection() + .PersistKeysToStackExchangeRedis(redis, "Platform-Protection-Keys"); + } + } + + //public override void OnPostApplicationInitialization(ApplicationInitializationContext context) + //{ + // var backgroundJobManager = context.ServiceProvider.GetRequiredService(); + // // 五分钟执行一次的定时任务 + // AsyncHelper.RunSync(async () => await + // backgroundJobManager.EnqueueAsync(CronGenerator.Minute(5), new NotificationCleanupExpritionJobArgs(200))); + //} + + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + var app = context.GetApplicationBuilder(); + var env = context.GetEnvironment(); + // http调用链 + app.UseCorrelationId(); + // 虚拟文件系统 + app.UseStaticFiles(); + // 本地化 + app.UseAbpRequestLocalization(); + // 多租户 + app.UseMultiTenancy(); + //路由 + app.UseRouting(); + // 认证 + app.UseAuthentication(); + // jwt + app.UseJwtTokenMiddleware(); + // 授权 + app.UseAuthorization(); + // Swagger + app.UseSwagger(); + // Swagger可视化界面 + app.UseSwaggerUI(options => + { + options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support Platform API"); + }); + // 审计日志 + app.UseAuditing(); + // 工作单元 + app.UseUnitOfWork(); + // 路由 + app.UseConfiguredEndpoints(); + + if (env.IsDevelopment()) + { + AsyncHelper.RunSync(async () => + await app.ApplicationServices.GetRequiredService() + .SeedAsync()); + } + } + } +}