Browse Source

feat(oss): 增加文件共享、公共/个人目录搜索api

pull/397/head
cKey 4 years ago
parent
commit
da4c787de4
  1. 32
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/FileShareDto.cs
  2. 21
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/FileShareInput.cs
  3. 17
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/GetFileShareDto.cs
  4. 10
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/GetFilesInput.cs
  5. 5
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IFileAppService.cs
  6. 8
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IPrivateFileAppService.cs
  7. 11
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IShareFileAppService.cs
  8. 45
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/FileAppServiceBase.cs
  9. 96
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/FileShareCacheItem.cs
  10. 2
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/OssManagementApplicationAutoMapperProfile.cs
  11. 151
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PrivateFileAppService.cs
  12. 52
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PublicFileAppService.cs
  13. 119
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/ShareFileAppService.cs
  14. 22
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/PrivateFilesController.cs
  15. 8
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/PublicFilesController.cs
  16. 43
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/ShareFilesController.cs

32
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/FileShareDto.cs

@ -0,0 +1,32 @@
using System;
namespace LINGYUN.Abp.OssManagement
{
public class FileShareDto
{
public string Url { get; set; }
public int MaxAccessCount { get; set; }
public DateTime? ExpirationTime { get; set; }
}
public class MyFileShareDto
{
public string Name { get; set; }
public string Path { get; set; }
public string[] Roles { get; set; }
public string[] Users { get; set; }
public string MD5 { get; set; }
public string Url { get; set; }
public int AccessCount { get; set; }
public int MaxAccessCount { get; set; }
public DateTime ExpirationTime { get; set; }
}
}

21
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/FileShareInput.cs

@ -0,0 +1,21 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace LINGYUN.Abp.OssManagement
{
public class FileShareInput
{
[Required]
public string Name { get; set; }
public string Path { get; set; }
public int MaxAccessCount { get; set; }
public DateTime? ExpirationTime { get; set; }
public string[] Roles { get; set; }
public string[] Users { get; set; }
}
}

17
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/GetFileShareDto.cs

@ -0,0 +1,17 @@
using System.IO;
namespace LINGYUN.Abp.OssManagement
{
public class GetFileShareDto
{
public string Name { get; set; }
public Stream Content { get; set; }
public GetFileShareDto(
string name,
Stream content = null)
{
Name = name;
Content = content ?? Stream.Null;
}
}
}

10
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/GetFilesInput.cs

@ -0,0 +1,10 @@
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Abp.OssManagement
{
public class GetFilesInput: LimitedResultRequestDto
{
public string Filter { get; set; }
public string Path { get; set; }
}
}

5
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IFileAppService.cs

@ -1,5 +1,6 @@
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.OssManagement namespace LINGYUN.Abp.OssManagement
@ -10,6 +11,10 @@ namespace LINGYUN.Abp.OssManagement
Task<Stream> GetAsync(GetPublicFileInput input); Task<Stream> GetAsync(GetPublicFileInput input);
Task<ListResultDto<OssObjectDto>> GetListAsync(GetFilesInput input);
Task UploadAsync(UploadFileChunkInput input); Task UploadAsync(UploadFileChunkInput input);
Task DeleteAsync(GetPublicFileInput input);
} }
} }

8
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IPrivateFileAppService.cs

@ -1,6 +1,12 @@
namespace LINGYUN.Abp.OssManagement using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Abp.OssManagement
{ {
public interface IPrivateFileAppService : IFileAppService public interface IPrivateFileAppService : IFileAppService
{ {
Task<FileShareDto> ShareAsync(FileShareInput input);
Task<ListResultDto<MyFileShareDto>> GetShareListAsync();
} }
} }

11
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IShareFileAppService.cs

@ -0,0 +1,11 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.OssManagement
{
public interface IShareFileAppService : IApplicationService
{
Task<GetFileShareDto> GetAsync(string url);
}
}

45
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/FileAppServiceBase.cs

@ -1,33 +1,35 @@
using LINGYUN.Abp.Features.LimitValidation; using LINGYUN.Abp.Features.LimitValidation;
using LINGYUN.Abp.OssManagement.Features; using LINGYUN.Abp.OssManagement.Features;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Features; using Volo.Abp.Features;
namespace LINGYUN.Abp.OssManagement namespace LINGYUN.Abp.OssManagement
{ {
public abstract class FileAppServiceBase : OssManagementApplicationServiceBase, IFileAppService public abstract class FileAppServiceBase : OssManagementApplicationServiceBase, IFileAppService
{ {
private readonly IFileUploader _fileUploader; protected IFileUploader FileUploader { get; }
private readonly IFileValidater _fileValidater; protected IFileValidater FileValidater { get; }
private readonly IOssContainerFactory _ossContainerFactory; protected IOssContainerFactory OssContainerFactory { get; }
protected FileAppServiceBase( protected FileAppServiceBase(
IFileUploader fileUploader, IFileUploader fileUploader,
IFileValidater fileValidater, IFileValidater fileValidater,
IOssContainerFactory ossContainerFactory) IOssContainerFactory ossContainerFactory)
{ {
_fileUploader = fileUploader; FileUploader = fileUploader;
_fileValidater = fileValidater; FileValidater = fileValidater;
_ossContainerFactory = ossContainerFactory; OssContainerFactory = ossContainerFactory;
} }
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.UploadFile)] [RequiresFeature(AbpOssManagementFeatureNames.OssObject.UploadFile)]
public virtual async Task UploadAsync(UploadFileChunkInput input) public virtual async Task UploadAsync(UploadFileChunkInput input)
{ {
await _fileUploader.UploadAsync( await FileUploader.UploadAsync(
new UploadFileChunkInput new UploadFileChunkInput
{ {
Bucket = GetCurrentBucket(), Bucket = GetCurrentBucket(),
@ -49,13 +51,13 @@ namespace LINGYUN.Abp.OssManagement
LimitPolicy.Month)] LimitPolicy.Month)]
public virtual async Task<OssObjectDto> UploadAsync(UploadFileInput input) public virtual async Task<OssObjectDto> UploadAsync(UploadFileInput input)
{ {
await _fileValidater.ValidationAsync(new UploadFile await FileValidater.ValidationAsync(new UploadFile
{ {
TotalSize = input.Content.Length, TotalSize = input.Content.Length,
FileName = input.Object FileName = input.Object
}); });
var oss = _ossContainerFactory.Create(); var oss = OssContainerFactory.Create();
var createOssObjectRequest = new CreateOssObjectRequest( var createOssObjectRequest = new CreateOssObjectRequest(
GetCurrentBucket(), GetCurrentBucket(),
@ -71,6 +73,19 @@ namespace LINGYUN.Abp.OssManagement
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject); return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject);
} }
public virtual async Task<ListResultDto<OssObjectDto>> GetListAsync(GetFilesInput input)
{
var ossContainer = OssContainerFactory.Create();
var response = await ossContainer.GetObjectsAsync(
GetCurrentBucket(),
GetCurrentPath(HttpUtility.UrlDecode(input.Path)),
skipCount: 0,
maxResultCount: input.MaxResultCount);
return new ListResultDto<OssObjectDto>(
ObjectMapper.Map<List<OssObject>, List<OssObjectDto>>(response.Objects));
}
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.DownloadFile)] [RequiresFeature(AbpOssManagementFeatureNames.OssObject.DownloadFile)]
[RequiresLimitFeature( [RequiresLimitFeature(
AbpOssManagementFeatureNames.OssObject.DownloadLimit, AbpOssManagementFeatureNames.OssObject.DownloadLimit,
@ -88,12 +103,22 @@ namespace LINGYUN.Abp.OssManagement
MD5 = true, MD5 = true,
}; };
var ossContainer = _ossContainerFactory.Create(); var ossContainer = OssContainerFactory.Create();
var ossObject = await ossContainer.GetObjectAsync(ossObjectRequest); var ossObject = await ossContainer.GetObjectAsync(ossObjectRequest);
return ossObject.Content; return ossObject.Content;
} }
public virtual async Task DeleteAsync(GetPublicFileInput input)
{
var ossContainer = OssContainerFactory.Create();
await ossContainer.DeleteObjectAsync(
GetCurrentBucket(),
HttpUtility.UrlDecode(input.Name),
GetCurrentPath(HttpUtility.UrlDecode(input.Path)));
}
protected virtual string GetCurrentBucket() protected virtual string GetCurrentBucket()
{ {
throw new System.NotImplementedException(); throw new System.NotImplementedException();

96
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/FileShareCacheItem.cs

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace LINGYUN.Abp.OssManagement
{
[Serializable]
public class MyFileShareCacheItem
{
private const string CacheKeyFormat = "ui:{0}";
public List<FileShareCacheItem> Items { get; set; }
public MyFileShareCacheItem() { }
public MyFileShareCacheItem(List<FileShareCacheItem> items)
{
Items = items ?? new List<FileShareCacheItem>();
}
public static string CalculateCacheKey(Guid userId)
{
return string.Format(CacheKeyFormat, userId.ToString("N"));
}
public DateTime? GetLastExpirationTime()
{
if (!Items.Any())
{
return null;
}
return Items
.OrderByDescending(item => item.ExpirationTime)
.Select(item => item.ExpirationTime)
.FirstOrDefault();
}
}
[Serializable]
public class FileShareCacheItem
{
private const string CacheKeyFormat = "url:{0}";
public string Bucket { get; set; }
public string Name { get; set; }
public string Path { get; set; }
public string[] Roles { get; set; }
public string[] Users { get; set; }
public string MD5 { get; set; }
public string Url { get; set; }
public int AccessCount { get; set; }
public int MaxAccessCount { get; set; }
public DateTime ExpirationTime { get; set; }
public Guid UserId { get; set; }
public FileShareCacheItem() { }
public FileShareCacheItem(
Guid userId,
string bucket,
string name,
string path,
string md5,
string url,
DateTime expirationTime,
string[] roles = null,
string[] users = null,
int maxAccessCount = 0)
{
UserId = userId;
Bucket = bucket;
Name = name;
Path = path;
MD5 = md5;
Url = url;
ExpirationTime = expirationTime;
Roles = roles ?? new string[0];
Users = users ?? new string[0];
MaxAccessCount = maxAccessCount;
}
public static string CalculateCacheKey(string shareUrl)
{
return string.Format(CacheKeyFormat, shareUrl);
}
}
}

2
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/OssManagementApplicationAutoMapperProfile.cs

@ -12,6 +12,8 @@ namespace LINGYUN.Abp.OssManagement
CreateMap<GetOssContainersResponse, OssContainersResultDto>(); CreateMap<GetOssContainersResponse, OssContainersResultDto>();
CreateMap<GetOssObjectsResponse, OssObjectsResultDto>(); CreateMap<GetOssObjectsResponse, OssObjectsResultDto>();
CreateMap<FileShareCacheItem, MyFileShareDto>();
} }
} }
} }

151
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PrivateFileAppService.cs

@ -1,4 +1,13 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Web;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Caching;
using Volo.Abp.IO;
using Volo.Abp.Users; using Volo.Abp.Users;
namespace LINGYUN.Abp.OssManagement namespace LINGYUN.Abp.OssManagement
@ -13,12 +22,154 @@ namespace LINGYUN.Abp.OssManagement
//[RemoteService(IsMetadataEnabled = false)] //[RemoteService(IsMetadataEnabled = false)]
public class PrivateFileAppService : FileAppServiceBase, IPrivateFileAppService public class PrivateFileAppService : FileAppServiceBase, IPrivateFileAppService
{ {
private readonly IDistributedCache<FileShareCacheItem> _shareCache;
private readonly IDistributedCache<MyFileShareCacheItem> _myShareCache;
public PrivateFileAppService( public PrivateFileAppService(
IDistributedCache<FileShareCacheItem> shareCache,
IDistributedCache<MyFileShareCacheItem> myShareCache,
IFileUploader fileUploader, IFileUploader fileUploader,
IFileValidater fileValidater, IFileValidater fileValidater,
IOssContainerFactory ossContainerFactory) IOssContainerFactory ossContainerFactory)
: base(fileUploader, fileValidater, ossContainerFactory) : base(fileUploader, fileValidater, ossContainerFactory)
{ {
_shareCache = shareCache;
_myShareCache = myShareCache;
}
[Authorize]
public override async Task<Stream> GetAsync(GetPublicFileInput input)
{
return await base.GetAsync(input);
}
[Authorize]
public override async Task<ListResultDto<OssObjectDto>> GetListAsync(GetFilesInput input)
{
return await base.GetListAsync(input);
}
[Authorize]
public override async Task<OssObjectDto> UploadAsync(UploadFileInput input)
{
return await base.UploadAsync(input);
}
[Authorize]
public override async Task UploadAsync(UploadFileChunkInput input)
{
await base.UploadAsync(input);
}
[Authorize]
public virtual async Task<ListResultDto<MyFileShareDto>> GetShareListAsync()
{
var cacheKey = MyFileShareCacheItem.CalculateCacheKey(CurrentUser.GetId());
var cacheItem = await _myShareCache.GetAsync(cacheKey);
if (cacheItem == null)
{
return new ListResultDto<MyFileShareDto>();
}
// 被动刷新用户共享缓存
// 手动调用时清除一下应该被清理掉的缓存
cacheItem.Items.RemoveAll(items => items.MaxAccessCount > 0 && items.AccessCount > items.MaxAccessCount);
cacheItem.Items.RemoveAll(items => items.ExpirationTime < Clock.Now);
DistributedCacheEntryOptions cacheOptions = null;
var myShareCacheExpirationTime = cacheItem.GetLastExpirationTime();
if (myShareCacheExpirationTime.HasValue)
{
cacheOptions = new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.Add(
Clock.Normalize(myShareCacheExpirationTime.Value) - Clock.Now),
};
}
await _myShareCache.SetAsync(cacheKey, cacheItem, cacheOptions);
return new ListResultDto<MyFileShareDto>(
ObjectMapper.Map<List<FileShareCacheItem>, List<MyFileShareDto>>(cacheItem.Items));
}
[Authorize]
public virtual async Task<FileShareDto> ShareAsync(FileShareInput input)
{
var ossObjectRequest = new GetOssObjectRequest(
GetCurrentBucket(),
// 需要处理特殊字符
HttpUtility.UrlDecode(input.Name),
GetCurrentPath(HttpUtility.UrlDecode(input.Path)))
{
MD5 = true,
};
var ossContainer = OssContainerFactory.Create();
var ossObject = await ossContainer.GetObjectAsync(ossObjectRequest);
var shareUrl = $"{GuidGenerator.Create():N}.{FileHelper.GetExtension(ossObject.Name)}";
var cacheItem = new FileShareCacheItem(
CurrentUser.GetId(),
GetCurrentBucket(),
ossObject.Name,
ossObject.Prefix,
ossObject.MD5,
shareUrl,
input.ExpirationTime ?? Clock.Now.AddDays(7),
input.Roles,
input.Users,
input.MaxAccessCount);
var cacheOptions = new DistributedCacheEntryOptions
{
// 不传递过期时间, 默认7天
AbsoluteExpiration = DateTimeOffset.Now.Add(
Clock.Normalize(cacheItem.ExpirationTime) - Clock.Now),
};
await _shareCache.SetAsync(
FileShareCacheItem.CalculateCacheKey(shareUrl),
cacheItem,
cacheOptions);
#region 当前用户共享缓存
// 被动刷新用户共享缓存
var myShareCacheKey = MyFileShareCacheItem.CalculateCacheKey(CurrentUser.GetId());
var myShareCacheItem = await _myShareCache.GetAsync(myShareCacheKey);
if (myShareCacheItem == null)
{
myShareCacheItem = new MyFileShareCacheItem(
new List<FileShareCacheItem>() { cacheItem });
}
else
{
myShareCacheItem.Items.Add(cacheItem);
}
DistributedCacheEntryOptions myShareCacheOptions = null;
var myShareCacheExpirationTime = myShareCacheItem.GetLastExpirationTime();
if (myShareCacheExpirationTime.HasValue)
{
myShareCacheOptions = new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.Add(
Clock.Normalize(myShareCacheExpirationTime.Value) - Clock.Now),
};
}
await _myShareCache.SetAsync(myShareCacheKey, myShareCacheItem, myShareCacheOptions);
#endregion
return new FileShareDto
{
Url = shareUrl,
MaxAccessCount = input.MaxAccessCount,
ExpirationTime = input.ExpirationTime,
};
}
[Authorize]
public override async Task DeleteAsync(GetPublicFileInput input)
{
await base.DeleteAsync(input);
} }
protected override string GetCurrentBucket() protected override string GetCurrentBucket()

52
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PublicFileAppService.cs

@ -1,11 +1,15 @@
using LINGYUN.Abp.Features.LimitValidation; using LINGYUN.Abp.Features.LimitValidation;
using LINGYUN.Abp.OssManagement.Features; using LINGYUN.Abp.OssManagement.Features;
using LINGYUN.Abp.OssManagement.Permissions;
using Microsoft.AspNetCore.Authorization;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Features; using Volo.Abp.Features;
namespace LINGYUN.Abp.OssManagement namespace LINGYUN.Abp.OssManagement
{ {
[AllowAnonymous]
public class PublicFileAppService : FileAppServiceBase, IPublicFileAppService public class PublicFileAppService : FileAppServiceBase, IPublicFileAppService
{ {
public PublicFileAppService( public PublicFileAppService(
@ -16,38 +20,54 @@ namespace LINGYUN.Abp.OssManagement
{ {
} }
[RequiresFeature( [Authorize(AbpOssManagementPermissions.OssObject.Delete)]
AbpOssManagementFeatureNames.PublicAccess, public override async Task DeleteAsync(GetPublicFileInput input)
AbpOssManagementFeatureNames.OssObject.UploadFile, {
RequiresAll = true)] await CheckPublicAccessAsync();
await CheckPolicyAsync(AbpOssManagementPermissions.OssObject.Delete);
await base.DeleteAsync(input);
}
public override async Task UploadAsync(UploadFileChunkInput input) public override async Task UploadAsync(UploadFileChunkInput input)
{ {
await CheckPublicAccessAsync();
await FeatureChecker.CheckEnabledAsync(AbpOssManagementFeatureNames.OssObject.UploadFile);
await base.UploadAsync(input); await base.UploadAsync(input);
} }
[RequiresFeature(
AbpOssManagementFeatureNames.PublicAccess,
AbpOssManagementFeatureNames.OssObject.UploadFile,
RequiresAll = true)]
[RequiresLimitFeature( [RequiresLimitFeature(
AbpOssManagementFeatureNames.OssObject.UploadLimit, AbpOssManagementFeatureNames.OssObject.UploadLimit,
AbpOssManagementFeatureNames.OssObject.UploadInterval, AbpOssManagementFeatureNames.OssObject.UploadInterval,
LimitPolicy.Month)] LimitPolicy.Month)]
public override async Task<OssObjectDto> UploadAsync(UploadFileInput input) public override async Task<OssObjectDto> UploadAsync(UploadFileInput input)
{ {
await CheckPublicAccessAsync();
await FeatureChecker.CheckEnabledAsync(AbpOssManagementFeatureNames.OssObject.UploadFile);
// 公共目录不允许覆盖
input.Overwrite = false;
return await base.UploadAsync(input); return await base.UploadAsync(input);
} }
[RequiresFeature( public override async Task<ListResultDto<OssObjectDto>> GetListAsync(GetFilesInput input)
AbpOssManagementFeatureNames.PublicAccess, {
AbpOssManagementFeatureNames.OssObject.DownloadFile, await CheckPublicAccessAsync();
RequiresAll = true)]
return await base.GetListAsync(input);
}
[RequiresLimitFeature( [RequiresLimitFeature(
AbpOssManagementFeatureNames.OssObject.DownloadLimit, AbpOssManagementFeatureNames.OssObject.DownloadLimit,
AbpOssManagementFeatureNames.OssObject.DownloadInterval, AbpOssManagementFeatureNames.OssObject.DownloadInterval,
LimitPolicy.Month)] LimitPolicy.Month)]
public override async Task<Stream> GetAsync(GetPublicFileInput input) public override async Task<Stream> GetAsync(GetPublicFileInput input)
{ {
await CheckPublicAccessAsync();
await FeatureChecker.CheckEnabledAsync(AbpOssManagementFeatureNames.OssObject.DownloadFile);
return await base.GetAsync(input); return await base.GetAsync(input);
} }
@ -55,5 +75,13 @@ namespace LINGYUN.Abp.OssManagement
{ {
return "public"; return "public";
} }
protected virtual async Task CheckPublicAccessAsync()
{
if (!CurrentUser.IsAuthenticated)
{
await FeatureChecker.CheckEnabledAsync(AbpOssManagementFeatureNames.PublicAccess);
}
}
} }
} }

119
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/ShareFileAppService.cs

@ -0,0 +1,119 @@
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Caching;
namespace LINGYUN.Abp.OssManagement
{
public class ShareFileAppService : OssManagementApplicationServiceBase, IShareFileAppService
{
private readonly IDistributedCache<FileShareCacheItem> _shareCache;
private readonly IDistributedCache<MyFileShareCacheItem> _myShareCache;
private readonly IOssContainerFactory _ossContainerFactory;
public ShareFileAppService(
IDistributedCache<FileShareCacheItem> shareCache,
IDistributedCache<MyFileShareCacheItem> myShareCache,
IOssContainerFactory ossContainerFactory)
{
_shareCache = shareCache;
_myShareCache = myShareCache;
_ossContainerFactory = ossContainerFactory;
}
public virtual async Task<GetFileShareDto> GetAsync(string url)
{
var cacheKey = FileShareCacheItem.CalculateCacheKey(url);
var cacheItem = await _shareCache.GetAsync(cacheKey);
if (cacheItem == null)
{
return new GetFileShareDto(url);
}
// 最大访问次数
cacheItem.AccessCount += 1;
// 被动刷新用户共享缓存
await RefreshUserShareAsync(cacheItem);
if (cacheItem.MaxAccessCount > 0 && cacheItem.AccessCount > cacheItem.MaxAccessCount)
{
await _shareCache.RemoveAsync(cacheKey);
return new GetFileShareDto(url);
}
// 共享用户
if (cacheItem.Users != null && cacheItem.Users.Any())
{
if (cacheItem.Users.Any((userName) => !userName.Equals(CurrentUser.UserName)))
{
return new GetFileShareDto(url);
}
}
// 共享角色
if (cacheItem.Roles != null && cacheItem.Roles.Any())
{
if (cacheItem.Roles.Any((role) => !CurrentUser.Roles.Contains(role)))
{
return new GetFileShareDto(url);
}
}
var ossObjectRequest = new GetOssObjectRequest(
cacheItem.Bucket,
cacheItem.Name,
cacheItem.Path)
{
MD5 = true,
};
var ossContainer = _ossContainerFactory.Create();
var ossObject = await ossContainer.GetObjectAsync(ossObjectRequest);
var cacheOptions = new DistributedCacheEntryOptions
{
// 不传递过期时间, 默认7天
AbsoluteExpiration = DateTimeOffset.Now.Add(
Clock.Normalize(cacheItem.ExpirationTime) - Clock.Now),
};
// 改变共享次数
await _shareCache.SetAsync(
cacheKey,
cacheItem,
cacheOptions);
return new GetFileShareDto(ossObject.Name, ossObject.Content);
}
protected virtual async Task RefreshUserShareAsync(FileShareCacheItem shareCacheItem)
{
// 清除当前用户共享缓存
var myShareCacheKey = MyFileShareCacheItem.CalculateCacheKey(shareCacheItem.UserId);
var myShareCacheItem = await _myShareCache.GetAsync(myShareCacheKey);
if (myShareCacheItem != null)
{
myShareCacheItem.Items.RemoveAll(item => item.Url.Equals(shareCacheItem.Url));
if (shareCacheItem.MaxAccessCount == 0 || shareCacheItem.AccessCount < shareCacheItem.MaxAccessCount)
{
myShareCacheItem.Items.Add(shareCacheItem);
}
DistributedCacheEntryOptions myShareCacheOptions = null;
var myShareCacheExpirationTime = myShareCacheItem.GetLastExpirationTime();
if (myShareCacheExpirationTime.HasValue)
{
myShareCacheOptions = new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.Add(
Clock.Normalize(myShareCacheExpirationTime.Value) - Clock.Now),
};
}
await _myShareCache.SetAsync(myShareCacheKey, myShareCacheItem, myShareCacheOptions);
}
}
}
}

22
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/PrivateFilesController.cs

@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Http; using Volo.Abp.Http;
using Volo.Abp.Validation; using Volo.Abp.Validation;
@ -68,6 +69,13 @@ namespace LINGYUN.Abp.OssManagement
return await _privateFileAppService.UploadAsync(createOssObjectInput); return await _privateFileAppService.UploadAsync(createOssObjectInput);
} }
[HttpGet]
[Route("search")]
public virtual async Task<ListResultDto<OssObjectDto>> GetListAsync(GetFilesInput input)
{
return await _privateFileAppService.GetListAsync(input);
}
[HttpGet] [HttpGet]
[Route("{name}")] [Route("{name}")]
[Route("{name}/{process}")] [Route("{name}/{process}")]
@ -94,6 +102,20 @@ namespace LINGYUN.Abp.OssManagement
); );
} }
[HttpGet]
[Route("share")]
public virtual async Task<ListResultDto<MyFileShareDto>> GetShareListAsync()
{
return await _privateFileAppService.GetShareListAsync();
}
[HttpPost]
[Route("share")]
public virtual async Task<FileShareDto> ShareAsync([FromBody] FileShareInput input)
{
return await _privateFileAppService.ShareAsync(input);
}
private static void ThrowValidationException(string message, string memberName) private static void ThrowValidationException(string message, string memberName)
{ {
throw new AbpValidationException(message, throw new AbpValidationException(message,

8
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/PublicFilesController.cs

@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Http; using Volo.Abp.Http;
using Volo.Abp.Validation; using Volo.Abp.Validation;
@ -69,6 +70,13 @@ namespace LINGYUN.Abp.OssManagement
return await _publicFileAppService.UploadAsync(createOssObjectInput); return await _publicFileAppService.UploadAsync(createOssObjectInput);
} }
[HttpGet]
[Route("search")]
public virtual async Task<ListResultDto<OssObjectDto>> GetListAsync(GetFilesInput input)
{
return await _publicFileAppService.GetListAsync(input);
}
[HttpGet] [HttpGet]
[Route("{name}")] [Route("{name}")]
[Route("{name}/{process}")] [Route("{name}/{process}")]

43
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/ShareFilesController.cs

@ -0,0 +1,43 @@
using LINGYUN.Abp.OssManagement.Localization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Http;
namespace LINGYUN.Abp.OssManagement
{
[Area("oss-management")]
[Route("api/files/share")]
[RemoteService(false)]
[ApiExplorerSettings(IgnoreApi = true)]
public class ShareFilesController : AbpController
{
private readonly IShareFileAppService _service;
public ShareFilesController(
IShareFileAppService service)
{
_service = service;
LocalizationResource = typeof(AbpOssManagementResource);
}
[HttpGet]
[Route("{url}")]
public virtual async Task<IActionResult> GetAsync(string url)
{
var ossObject = await _service.GetAsync(url);
if (ossObject.Content.IsNullOrEmpty())
{
return NotFound();
}
return File(ossObject.Content, MimeTypes.GetByExtension(Path.GetExtension(ossObject.Name)));
}
}
}
Loading…
Cancel
Save