文件上传加密及增加根据配置文件存储类型自动选择上传方式

This commit is contained in:
YUN-PC5\user 2023-11-22 10:29:07 +08:00
parent 43c9d3564b
commit bebcf559a1
8 changed files with 379 additions and 64 deletions

View File

@ -1,15 +1,10 @@
using System.Net; using Infrastructure.Helper;
using System.Net.Sockets;
using Infrastructure.Helper;
using JinianNet.JNTemplate; using JinianNet.JNTemplate;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json; using Newtonsoft.Json;
using ZR.Admin.WebApi.Filters; using ZR.Admin.WebApi.Filters;
using ZR.Model.System;
using ZR.Service.IService; using ZR.Service.IService;
using ZR.Service.System; using ZR.Service.System;
using ZR.Service.System.IService;
using ZR.ServiceCore.Model; using ZR.ServiceCore.Model;
using ZR.ServiceCore.Services.IService; using ZR.ServiceCore.Services.IService;
@ -135,15 +130,6 @@ namespace ZR.Admin.WebApi.Controllers
SysFile file = new(); SysFile file = new();
string fileExt = Path.GetExtension(formFile.FileName);//文件后缀 string fileExt = Path.GetExtension(formFile.FileName);//文件后缀
double fileSize = Math.Round(formFile.Length / 1024.0, 2);//文件大小KB double fileSize = Math.Round(formFile.Length / 1024.0, 2);//文件大小KB
var scheme = HttpContext.Request.Scheme + "://";
var serverIP = HttpContext.Request.Host.Value;
if (WebHostEnvironment.IsProduction())
{
var host = await Dns.GetHostEntryAsync(Dns.GetHostName());
var ip = host.AddressList
.FirstOrDefault(it => it.AddressFamily == AddressFamily.InterNetwork);
serverIP = ip + ":" + Request.HttpContext.Connection.LocalPort;//获取服务器IP
}
if (OptionsSetting.Upload.NotAllowedExt.Contains(fileExt)) if (OptionsSetting.Upload.NotAllowedExt.Contains(fileExt))
{ {
@ -166,7 +152,7 @@ namespace ZR.Admin.WebApi.Controllers
uploadDto.FileDir = OptionsSetting.Upload.LocalSavePath; uploadDto.FileDir = OptionsSetting.Upload.LocalSavePath;
} }
file = await SysFileService.SaveFileToLocal(savePath, uploadDto.FileName, uploadDto.FileDir, file = await SysFileService.SaveFileToLocal(savePath, uploadDto.FileName, uploadDto.FileDir,
HttpContext.GetUId(), HttpContext.GetName(), formFile, scheme + serverIP); HttpContext.GetUId(), HttpContext.GetNickName(), formFile, OptionsSetting.Upload.UploadUrl);
break; break;
case StoreType.REMOTE: case StoreType.REMOTE:
break; break;
@ -181,7 +167,7 @@ namespace ZR.Admin.WebApi.Controllers
return ToResponse(ResultCode.CUSTOM_ERROR, "上传文件过大,不能超过 " + AlimaxContentLength + " MB"); return ToResponse(ResultCode.CUSTOM_ERROR, "上传文件过大,不能超过 " + AlimaxContentLength + " MB");
} }
file = new(formFile.FileName, uploadDto.FileName, fileExt, fileSize + "kb", file = new(formFile.FileName, uploadDto.FileName, fileExt, fileSize + "kb",
uploadDto.FileDir, HttpContext.GetUId(), HttpContext.GetName()) uploadDto.FileDir, HttpContext.GetUId(), HttpContext.GetNickName())
{ {
StoreType = (int)StoreType.ALIYUN, StoreType = (int)StoreType.ALIYUN,
FileType = formFile.ContentType FileType = formFile.ContentType

View File

@ -1,8 +1,5 @@
using Microsoft.AspNetCore.Mvc;
using SqlSugar; using SqlSugar;
using ZR.Admin.WebApi.Filters; using ZR.Admin.WebApi.Filters;
using ZR.Model.System;
using ZR.Service.System.IService;
using ZR.ServiceCore.Model; using ZR.ServiceCore.Model;
using ZR.ServiceCore.Model.Dto; using ZR.ServiceCore.Model.Dto;
using ZR.ServiceCore.Services.IService; using ZR.ServiceCore.Services.IService;
@ -20,11 +17,11 @@ namespace ZR.Admin.WebApi.Controllers
/// <summary> /// <summary>
/// 文件存储接口 /// 文件存储接口
/// </summary> /// </summary>
private readonly ISysFileService _SysFileService; private readonly ISysFileService _sysFileService;
public SysFileController(ISysFileService SysFileService) public SysFileController(ISysFileService sysFileService)
{ {
_SysFileService = SysFileService; _sysFileService = sysFileService;
} }
/// <summary> /// <summary>
@ -43,7 +40,7 @@ namespace ZR.Admin.WebApi.Controllers
predicate = predicate.AndIF(parm.StoreType != null, m => m.StoreType == parm.StoreType); predicate = predicate.AndIF(parm.StoreType != null, m => m.StoreType == parm.StoreType);
predicate = predicate.AndIF(parm.FileId != null, m => m.Id == parm.FileId); predicate = predicate.AndIF(parm.FileId != null, m => m.Id == parm.FileId);
var response = _SysFileService.GetPages(predicate.ToExpression(), parm, x => x.Id, OrderByType.Desc); var response = _sysFileService.GetPages(predicate.ToExpression(), parm, x => x.Id, OrderByType.Desc);
return SUCCESS(response); return SUCCESS(response);
} }
@ -56,7 +53,7 @@ namespace ZR.Admin.WebApi.Controllers
[ActionPermissionFilter(Permission = "tool:file:query")] [ActionPermissionFilter(Permission = "tool:file:query")]
public IActionResult GetSysFile(long Id) public IActionResult GetSysFile(long Id)
{ {
var response = _SysFileService.GetFirst(x => x.Id == Id); var response = _sysFileService.GetFirst(x => x.Id == Id);
return SUCCESS(response); return SUCCESS(response);
} }
@ -68,13 +65,12 @@ namespace ZR.Admin.WebApi.Controllers
[HttpDelete("{ids}")] [HttpDelete("{ids}")]
[ActionPermissionFilter(Permission = "tool:file:delete")] [ActionPermissionFilter(Permission = "tool:file:delete")]
[Log(Title = "文件存储", BusinessType = BusinessType.DELETE)] [Log(Title = "文件存储", BusinessType = BusinessType.DELETE)]
public IActionResult DeleteSysFile(string ids) public async Task<IActionResult> DeleteSysFile(string ids)
{ {
long[] idsArr = Tools.SpitLongArrary(ids); long[] idsArr = Tools.SpitLongArrary(ids);
if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); } if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); }
var response = _SysFileService.Delete(idsArr); var response = await _sysFileService.DeleteSysFileAsync(idsArr);
//TODO 删除本地资源
return ToResponse(response); return ToResponse(response);
} }
@ -88,10 +84,50 @@ namespace ZR.Admin.WebApi.Controllers
[ActionPermissionFilter(Permission = "tool:file:export")] [ActionPermissionFilter(Permission = "tool:file:export")]
public IActionResult Export() public IActionResult Export()
{ {
var list = _SysFileService.GetAll(); var list = _sysFileService.GetAll();
string sFileName = ExportExcel(list, "SysFile", "文件存储"); string sFileName = ExportExcel(list, "SysFile", "文件存储");
return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName });
} }
/// <summary>
/// 通过文件ID下载文件
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[HttpPost("download")]
public IActionResult Download([FromBody] SysFile file)
{
var sysFile = _sysFileService.Queryable().Where(it => it.Id == file.Id).First();
if (sysFile == null)
{
return NoContent();
}
Stream? stream = null;
switch ((StoreType)Enum.Parse(typeof(StoreType), sysFile.StoreType.ToString() ?? string.Empty))
{
case StoreType.LOCAL:
stream = sysFile.IsEncrypted == "1" ? _sysFileService.DecryptSysFileStream(sysFile.FileUrl)
: new FileStream(sysFile.FileUrl, FileMode.Open);
break;
case StoreType.ALIYUN:
stream = AliyunOssHelper.DownloadFile(sysFile.FileUrl, "", sysFile.IsEncrypted == "1");
break;
default:
throw new CustomException("不支持的存储类型");
}
if (stream != null)
{
return new FileStreamResult(stream, "application/octet-stream")
{
FileDownloadName = sysFile.RealName
};
}
else
{
return NoContent();
}
}
} }
} }

View File

@ -1,8 +1,5 @@
using System.Net; using Microsoft.Extensions.Options;
using System.Net.Sockets;
using Microsoft.AspNetCore.Mvc;
using ZR.Admin.WebApi.Filters; using ZR.Admin.WebApi.Filters;
using ZR.Model.System;
using ZR.Service.System.IService; using ZR.Service.System.IService;
using ZR.ServiceCore.Model; using ZR.ServiceCore.Model;
using ZR.ServiceCore.Model.Dto; using ZR.ServiceCore.Model.Dto;
@ -24,6 +21,7 @@ namespace ZR.Admin.WebApi.Controllers.System
private readonly ISysDeptService DeptService; private readonly ISysDeptService DeptService;
private readonly ISysFileService FileService; private readonly ISysFileService FileService;
private IWebHostEnvironment hostEnvironment; private IWebHostEnvironment hostEnvironment;
private readonly OptionsSetting _optionsSetting;
public SysProfileController( public SysProfileController(
ISysUserService userService, ISysUserService userService,
@ -31,7 +29,8 @@ namespace ZR.Admin.WebApi.Controllers.System
ISysUserPostService postService, ISysUserPostService postService,
ISysDeptService deptService, ISysDeptService deptService,
ISysFileService sysFileService, ISysFileService sysFileService,
IWebHostEnvironment hostEnvironment) IWebHostEnvironment hostEnvironment,
IOptions<OptionsSetting> options)
{ {
UserService = userService; UserService = userService;
RoleService = roleService; RoleService = roleService;
@ -39,6 +38,7 @@ namespace ZR.Admin.WebApi.Controllers.System
DeptService = deptService; DeptService = deptService;
FileService = sysFileService; FileService = sysFileService;
this.hostEnvironment = hostEnvironment; this.hostEnvironment = hostEnvironment;
_optionsSetting = options.Value;
} }
/// <summary> /// <summary>
@ -123,18 +123,9 @@ namespace ZR.Admin.WebApi.Controllers.System
long userId = HttpContext.GetUId(); long userId = HttpContext.GetUId();
if (formFile == null) throw new CustomException("请选择文件"); if (formFile == null) throw new CustomException("请选择文件");
var scheme = HttpContext.Request.Scheme + "://";
var serverIP = HttpContext.Request.Host.Value;
if (hostEnvironment.IsProduction())
{
var host = await Dns.GetHostEntryAsync(Dns.GetHostName());
var ip = host.AddressList
.FirstOrDefault(it => it.AddressFamily == AddressFamily.InterNetwork);
serverIP = ip + ":" + Request.HttpContext.Connection.LocalPort;//获取服务器IP
}
var file = await FileService.SaveFileToLocal(hostEnvironment.WebRootPath, "", "avatar", var file = await FileService.SaveFileToLocal(hostEnvironment.WebRootPath, "", "avatar",
HttpContext.GetUId(), HttpContext.GetName(), formFile, serverIP); HttpContext.GetUId(), HttpContext.GetName(), formFile, _optionsSetting.Upload.UploadUrl);
UserService.UpdatePhoto(new SysUser() { Avatar = file.AccessUrl, UserId = userId }); UserService.UpdatePhoto(new SysUser() { Avatar = file.AccessUrl, UserId = userId });
return SUCCESS(new { imgUrl = file.AccessUrl }); return SUCCESS(new { imgUrl = file.AccessUrl });

View File

@ -3,6 +3,7 @@ using Aliyun.OSS.Common;
using Infrastructure; using Infrastructure;
using System; using System;
using System.IO; using System.IO;
using System.Security.Cryptography;
namespace ZR.Common namespace ZR.Common
{ {
@ -55,7 +56,9 @@ namespace ZR.Common
try try
{ {
OssClient client = new(endpoint, accessKeyId, accessKeySecret); OssClient client = new(endpoint, accessKeyId, accessKeySecret);
dirPath = dirPath.Replace("\\", "/");
DeleteObjectResult putObjectResult = client.DeleteObject(bucketName, dirPath); DeleteObjectResult putObjectResult = client.DeleteObject(bucketName, dirPath);
return putObjectResult.HttpStatusCode;
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -63,5 +66,52 @@ namespace ZR.Common
} }
return System.Net.HttpStatusCode.BadRequest; return System.Net.HttpStatusCode.BadRequest;
} }
public static Stream DownloadFile(string dirPath, string bucketName = "", bool isEncrypted = false)
{
if (string.IsNullOrEmpty(bucketName))
{
bucketName = bucketName1;
}
try
{
OssClient client = new(endpoint, accessKeyId, accessKeySecret);
dirPath = dirPath.Replace("\\", "/");
var ossObject = client.GetObject(bucketName, dirPath);
if (isEncrypted)
{
try
{
var key = new byte[]
{
13, 57, 174, 2, 102, 26, 253, 192, 141, 38, 175, 244, 32, 86, 163, 25, 237, 134,
253, 162, 62, 203, 57, 52, 56, 157, 78, 155, 63, 28, 63, 255
};
var iv = new byte[]
{
137, 221, 84, 122, 104, 162, 48, 60, 108, 130, 170, 238, 186, 190, 111, 176
};
var aes = Aes.Create();
aes.Key = key;
aes.IV = iv;
var decryptor = aes.CreateDecryptor();
var cryptoStream = new CryptoStream(ossObject.Content, decryptor, CryptoStreamMode.Read);
return cryptoStream;
}
catch (Exception e)
{
// 处理异常,例如记录日志或抛出自定义异常
Console.WriteLine($"解密文件时发生异常: {e.Message}");
throw;
}
}
return ossObject.Content;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
} }
} }

View File

@ -1,5 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -126,5 +128,31 @@ namespace ZR.Common
return true; //由数字、字母、符号构成的密码 return true; //由数字、字母、符号构成的密码
} }
/// <summary>
/// 获取文件的MD5值
/// </summary>
/// <param name="filestream">文件流</param>
/// <returns></returns>
public static string GetMD5HashFromFile(Stream filestream)
{
try
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(filestream);
filestream.Close();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return sb.ToString();
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
} }
} }

View File

@ -58,6 +58,21 @@
/// 访问路径 /// 访问路径
/// </summary> /// </summary>
public string AccessUrl { get; set; } public string AccessUrl { get; set; }
/// <summary>
/// 描述 : 文件MD5
/// 空值 : true
/// </summary>
public string FileMd5 { get; set; }
/// <summary>
/// 已加密
/// </summary>
public string IsEncrypted { get; set; }
/// <summary>
/// 描述:文件是否已上传
/// 空值false
/// </summary>
[SugarColumn(IsIgnore = true)]
public bool FileExists { get; set; }
public SysFile() { } public SysFile() { }
public SysFile(string originFileName, string fileName, string ext, string fileSize, string storePath, public SysFile(string originFileName, string fileName, string ext, string fileSize, string storePath,

View File

@ -8,16 +8,20 @@ namespace ZR.ServiceCore.Services.IService
{ {
Task<long> InsertFile(SysFile file); Task<long> InsertFile(SysFile file);
Task<SysFile> SaveFile(SysFile file, IFormFile formFile, string rootPath, string uploadUrl);
/// <summary> /// <summary>
/// 上传文件 /// 上传文件
/// </summary> /// </summary>
/// <param name="fileDir"></param>
/// <param name="fileName"></param>
/// <param name="formFile"></param>
/// <param name="rootPath"></param> /// <param name="rootPath"></param>
/// <param name="userName"></param> /// <param name="fileName"></param>
/// <param name="fileDir"></param>
/// <param name="userId"></param>
/// <param name="nickName"></param>
/// <param name="formFile"></param>
/// <param name="uploadUrl"></param>
/// <returns>文件对象</returns> /// <returns>文件对象</returns>
Task<SysFile> SaveFileToLocal(string rootPath, string fileName, string fileDir, long userId, string userName, Task<SysFile> SaveFileToLocal(string rootPath, string fileName, string fileDir, long userId, string nickName,
IFormFile formFile, string uploadUrl); IFormFile formFile, string uploadUrl);
Task<SysFile> SaveFileToAliyun(SysFile file, IFormFile formFile); Task<SysFile> SaveFileToAliyun(SysFile file, IFormFile formFile);
@ -35,5 +39,26 @@ namespace ZR.ServiceCore.Services.IService
/// <param name="str">文件名,不包括扩展名</param> /// <param name="str">文件名,不包括扩展名</param>
/// <returns></returns> /// <returns></returns>
string HashFileName(string str = null); string HashFileName(string str = null);
/// <summary>
/// 删除文件
/// </summary>
/// <param name="ids">文件ID</param>
/// <returns></returns>
Task<int> DeleteSysFileAsync(long[] ids);
/// <summary>
/// 条件查询文件列表
/// </summary>
/// <param name="sysFile">文件对象</param>
/// <returns></returns>
List<SysFile> SelectFileList(SysFile sysFile);
/// <summary>
/// 文件解密流
/// </summary>
/// <param name="fileUrl"></param>
/// <returns></returns>
Stream DecryptSysFileStream(string fileUrl);
} }
} }

View File

@ -22,25 +22,42 @@ namespace ZR.ServiceCore.Services
public class SysFileService : BaseService<SysFile>, ISysFileService public class SysFileService : BaseService<SysFile>, ISysFileService
{ {
private string domainUrl = AppSettings.GetConfig("ALIYUN_OSS:domainUrl"); private string domainUrl = AppSettings.GetConfig("ALIYUN_OSS:domainUrl");
private readonly ISysConfigService SysConfigService; private readonly ISysConfigService _sysConfigService;
private OptionsSetting OptionsSetting; private OptionsSetting _optionsSetting;
public SysFileService(ISysConfigService sysConfigService, IOptions<OptionsSetting> options) public SysFileService(ISysConfigService sysConfigService, IOptions<OptionsSetting> options)
{ {
SysConfigService = sysConfigService; _sysConfigService = sysConfigService;
OptionsSetting = options.Value; _optionsSetting = options.Value;
}
public async Task<SysFile> SaveFile(SysFile file, IFormFile formFile, string rootPath, string uploadUrl)
{
var storeTypeConfig = _sysConfigService.GetSysConfigByKey("sys.file.storetype").ConfigValue;
switch ((StoreType)Enum.Parse(typeof(StoreType), storeTypeConfig))
{
case StoreType.LOCAL:
return await SaveFileToLocal(rootPath, file.FileName,
file.StorePath, file.Create_by, file.Create_name, formFile, uploadUrl);
case StoreType.ALIYUN:
return await SaveFileToAliyun(file, formFile);
default:
throw new ArgumentOutOfRangeException();
}
} }
/// <summary> /// <summary>
/// 存储本地 /// 存储本地
/// </summary> /// </summary>
/// <param name="fileDir">存储文件夹</param>
/// <param name="rootPath">存储根目录</param> /// <param name="rootPath">存储根目录</param>
/// <param name="fileName">自定文件名</param> /// <param name="fileName">自定文件名</param>
/// <param name="fileDir">存储文件夹</param>
/// <param name="userId"></param>
/// <param name="nickName"></param>
/// <param name="formFile">上传的文件流</param> /// <param name="formFile">上传的文件流</param>
/// <param name="userName"></param> /// <param name="uploadUrl"></param>
/// <returns></returns> /// <returns></returns>
public async Task<SysFile> SaveFileToLocal(string rootPath, string fileName, string fileDir, long userId, string userName, public async Task<SysFile> SaveFileToLocal(string rootPath, string fileName, string fileDir, long userId,
IFormFile formFile, string uploadUrl) string nickName, IFormFile formFile, string uploadUrl)
{ {
string fileExt = Path.GetExtension(formFile.FileName); string fileExt = Path.GetExtension(formFile.FileName);
fileName = (fileName.IsEmpty() ? HashFileName() : fileName) + fileExt; fileName = (fileName.IsEmpty() ? HashFileName() : fileName) + fileExt;
@ -54,19 +71,55 @@ namespace ZR.ServiceCore.Services
Directory.CreateDirectory(Path.GetDirectoryName(finalFilePath)); Directory.CreateDirectory(Path.GetDirectoryName(finalFilePath));
} }
using (var stream = new FileStream(finalFilePath, FileMode.Create)) var md5HashFromFile = Tools.GetMD5HashFromFile(formFile.OpenReadStream());
var exp = Expressionable.Create<SysFile>();
exp.AndIF(md5HashFromFile.IsNotEmpty(), it => it.FileMd5 == md5HashFromFile);
var sysFile = await GetSingleAsync(exp.ToExpression());
if (sysFile != null)
{ {
sysFile.FileExists = true;
return sysFile;
}
var notEncryptExt = _sysConfigService.GetSysConfigByKey("sys.file.notEncryptExt")
.ConfigValue.Split(",");
var encryptOnOff = !notEncryptExt.Contains(fileExt) && _sysConfigService
.GetSysConfigByKey("sys.file.encryptOnOff").ConfigValue.ParseToBool();
if (encryptOnOff)
{
var key = new byte[]
{
13, 57, 174, 2, 102, 26, 253, 192, 141, 38, 175, 244, 32, 86, 163, 25, 237, 134,
253, 162, 62, 203, 57, 52, 56, 157, 78, 155, 63, 28, 63, 255
};
var iv = new byte[]
{
137, 221, 84, 122, 104, 162, 48, 60, 108, 130, 170, 238, 186, 190, 111, 176
};
var encryptor = Aes.Create().CreateEncryptor(key, iv);
await using var outputFileStream = new FileStream(finalFilePath, FileMode.Create);
await using var cryptoStream = new CryptoStream(outputFileStream, encryptor, CryptoStreamMode.Write);
await formFile.CopyToAsync(cryptoStream);
}
else
{
await using var stream = new FileStream(finalFilePath, FileMode.Create);
await formFile.CopyToAsync(stream); await formFile.CopyToAsync(stream);
} }
// string uploadUrl = OptionsSetting.Upload.UploadUrl; // string uploadUrl = OptionsSetting.Upload.UploadUrl;
string accessPath = string.Concat(uploadUrl, "/", filePath.Replace("\\", "/"), "/", fileName); string accessPath = string.Concat(uploadUrl, "/", filePath.Replace("\\", "/"), "/", fileName);
SysFile file = new(formFile.FileName, fileName, fileExt, fileSize + "kb", filePath, userId, userName) SysFile file = new(formFile.FileName, fileName, fileExt, fileSize + "kb", filePath, userId, nickName)
{ {
StoreType = (int)StoreType.LOCAL, StoreType = (int)StoreType.LOCAL,
FileType = formFile.ContentType, FileType = formFile.ContentType,
FileUrl = finalFilePath.Replace("\\", "/"), FileUrl = finalFilePath.Replace("\\", "/"),
AccessUrl = accessPath AccessUrl = accessPath
}; };
file.IsEncrypted = encryptOnOff ? "1" : "0";
file.FileExists = false;
file.FileMd5 = md5HashFromFile;
file.Id = await InsertFile(file); file.Id = await InsertFile(file);
return file; return file;
} }
@ -82,12 +135,49 @@ namespace ZR.ServiceCore.Services
file.FileName = (file.FileName.IsEmpty() ? HashFileName() : file.FileName) + file.FileExt; file.FileName = (file.FileName.IsEmpty() ? HashFileName() : file.FileName) + file.FileExt;
file.StorePath = GetdirPath(file.StorePath); file.StorePath = GetdirPath(file.StorePath);
string finalPath = Path.Combine(file.StorePath, file.FileName); string finalPath = Path.Combine(file.StorePath, file.FileName);
HttpStatusCode statusCode = AliyunOssHelper.PutObjectFromFile(formFile.OpenReadStream(), finalPath, "");
var md5HashFromFile = Tools.GetMD5HashFromFile(formFile.OpenReadStream());
var exp = Expressionable.Create<SysFile>();
exp.AndIF(md5HashFromFile.IsNotEmpty(), it => it.FileMd5 == md5HashFromFile);
var sysFile = await GetSingleAsync(exp.ToExpression());
if (sysFile != null)
{
sysFile.FileExists = true;
return sysFile;
}
var notEncryptExt = _sysConfigService.GetSysConfigByKey("sys.file.notEncryptExt")
.ConfigValue.Split(",");
var encryptOnOff = !notEncryptExt.Contains(file.FileExt) && _sysConfigService.GetSysConfigByKey("sys.file.encryptOnOff")
.ConfigValue.ParseToBool();
if (encryptOnOff)
{
var key = new byte[]
{
13, 57, 174, 2, 102, 26, 253, 192, 141, 38, 175, 244, 32, 86, 163, 25, 237, 134,
253, 162, 62, 203, 57, 52, 56, 157, 78, 155, 63, 28, 63, 255
};
var iv = new byte[]
{
137, 221, 84, 122, 104, 162, 48, 60, 108, 130, 170, 238, 186, 190, 111, 176
};
var encryptor = Aes.Create().CreateEncryptor(key, iv);
await using var cryptoStream = new CryptoStream(formFile.OpenReadStream(), encryptor, CryptoStreamMode.Write);
HttpStatusCode statusCode = AliyunOssHelper.PutObjectFromFile(cryptoStream, finalPath, "");
if (statusCode != HttpStatusCode.OK) return file; if (statusCode != HttpStatusCode.OK) return file;
file.StorePath = file.StorePath; }
else
{
HttpStatusCode statusCode = AliyunOssHelper.PutObjectFromFile(formFile.OpenReadStream(), finalPath, "");
if (statusCode != HttpStatusCode.OK) return file;
}
file.IsEncrypted = encryptOnOff ? "1" : "0";
file.FileExists = false;
file.FileMd5 = md5HashFromFile;
file.FileUrl = finalPath; file.FileUrl = finalPath;
file.AccessUrl = string.Concat(domainUrl, "/", file.StorePath.Replace("\\", "/"), "/", file.FileName); file.AccessUrl = string.Concat(domainUrl, "/", file.StorePath.Replace("\\", "/"), "/", file.FileName);
file.StoreType = (int)StoreType.ALIYUN;
file.Id = await InsertFile(file); file.Id = await InsertFile(file);
return file; return file;
@ -120,6 +210,52 @@ namespace ZR.ServiceCore.Services
return BitConverter.ToString(MD5.HashData(Encoding.Default.GetBytes(str)), 4, 8).Replace("-", ""); return BitConverter.ToString(MD5.HashData(Encoding.Default.GetBytes(str)), 4, 8).Replace("-", "");
} }
public async Task<int> DeleteSysFileAsync(long[] ids)
{
var sysFiles = await GetListAsync(x => ids.Contains(x.Id));
// var accessUrls = sysFiles.Select(t => t.AccessUrl).ToList();
var res = 0;
foreach (var item in sysFiles)
{
switch (item.StoreType)
{
case (int)StoreType.LOCAL:
File.Delete(item.FileUrl);
res += await DeleteByIdAsync(item.Id) ? 1 : 0;
break;
case (int)StoreType.ALIYUN:
var httpStatusCode = AliyunOssHelper.DeleteFile(item.FileUrl);
if (httpStatusCode == HttpStatusCode.NoContent)
{
res += await DeleteByIdAsync(item.Id) ? 1 : 0;
}
break;
}
}
return res;
}
public List<SysFile> SelectFileList(SysFile sysFile)
{
var exp = Expressionable.Create<SysFile>();
exp.AndIF(sysFile.FileName.IsNotEmpty(), it => it.FileName.Contains(sysFile.FileName));
exp.AndIF(sysFile.FileExt.IsNotEmpty(), it => it.FileExt == sysFile.FileExt);
exp.AndIF(sysFile.FileSize.IsNotEmpty(), it => it.FileSize == sysFile.FileSize);
exp.AndIF(sysFile.StorePath.IsNotEmpty(), it => it.StorePath == sysFile.StorePath);
exp.AndIF(sysFile.StoreType > 0, it => it.StoreType == sysFile.StoreType);
exp.AndIF(sysFile.FileType.IsNotEmpty(), it => it.FileType == sysFile.FileType);
exp.AndIF(sysFile.AccessUrl.IsNotEmpty(), it => it.AccessUrl == sysFile.AccessUrl);
exp.AndIF(sysFile.FileUrl.IsNotEmpty(), it => it.FileUrl == sysFile.FileUrl);
exp.AndIF(sysFile.Create_by.IsNotEmpty(), it => it.Create_by == sysFile.Create_by);
exp.AndIF(sysFile.Create_name.IsNotEmpty(), it => it.Create_name == sysFile.Create_name);
exp.AndIF(sysFile.Create_time != null, it => it.Create_time == sysFile.Create_time);
exp.AndIF(sysFile.FileMd5.IsNotEmpty(), it => it.FileMd5 == sysFile.FileMd5);
exp.AndIF(sysFile.Id > 0, it => it.Id == sysFile.Id);
return GetList(exp.ToExpression());
}
public Task<long> InsertFile(SysFile file) public Task<long> InsertFile(SysFile file)
{ {
try try
@ -132,5 +268,53 @@ namespace ZR.ServiceCore.Services
throw new Exception(ex.Message); throw new Exception(ex.Message);
} }
} }
/// <summary>
/// 文件解密流
/// </summary>
/// <param name="fileUrl"></param>
/// <returns></returns>
public Stream DecryptSysFileStream(string fileUrl)
{
var key = new byte[]
{
13, 57, 174, 2, 102, 26, 253, 192, 141, 38, 175, 244, 32, 86, 163, 25, 237, 134,
253, 162, 62, 203, 57, 52, 56, 157, 78, 155, 63, 28, 63, 255
};
var iv = new byte[]
{
137, 221, 84, 122, 104, 162, 48, 60, 108, 130, 170, 238, 186, 190, 111, 176
};
try
{
var aes = Aes.Create();
aes.Key = key;
aes.IV = iv;
var decryptor = aes.CreateDecryptor();
var fsInput = new FileStream(fileUrl.Replace("/","\\"), FileMode.Open, FileAccess.ReadWrite);
var msOutput = new MemoryStream();
var cryptoStream = new CryptoStream(fsInput, decryptor, CryptoStreamMode.Read);
// 从加密文件中读取并解密
int bytesRead;
var buffer = new byte[4096];
while ((bytesRead = cryptoStream.Read(buffer, 0, buffer.Length)) > 0)
{
msOutput.Write(buffer, 0, bytesRead);
}
fsInput.Position = 0;
cryptoStream.Close();
// 返回解密后的流
msOutput.Position = 0;
return msOutput;
}
catch (Exception e)
{
// 处理异常,例如记录日志或抛出自定义异常
Console.WriteLine($"解密文件时发生异常: {e.Message}");
throw;
}
}
} }
} }