Limyee 电商平台支持在集中文件存储系统中创建文件存储,使插件能够生成、存储、保护文件并提供文件服务。
文件存储是位于集中文件存储系统 (CFS) 中的一组有唯一路径的文件。每个文件存储都是一组独立的文件,可以独立保护这些文件,并位于所选的存储提供程序(操作系统文件系统、云储存等)上。
实现需要存储文件的插件时,最好将这些文件存储在您维护的文件存储 CFS 中,不建议重用现有文件存储。
在 CFS 中创建新的文件存储需要实现 ICentralizedFileStore 插件类型。ICentralizedFileStore 仅向 IPlugin 接口添加一个成员。名称必须是唯一的,并且必须符合 CFS 命名准则。
作为示例,以下是 Key 为“sample”的文件存储完整实现:
using System;
using Limyee.Extensibility.Version1;
using Limyee.Extensibility.Storage.Version1;
namespace Samples
{
public class SampleFileStore : IPlugin, ICentralizedFileStore
{
#region IPlugin Implementation
public string Name
{
get
{
return "Sample File Store";
}
}
public string Description
{
get
{
return "A sample store of files.";
}
}
public void Initialize()
{
}
#endregion
#region ICentralizedFileStore Implementation
public string FileStoreKey
{
get
{
return "samples";
}
}
#endregion
}
}
安装并启用插件后,此插件或其他插件可以使用“sample”文件存储来添加、删除或提供文件(有关 CFS 用法的示例,请参阅集中文件存储)。
默认情况下,文件存储的文件储存在 limyee.config 文件配置的默认文件存储中,但是,可以自定义 CFS 配置,以明确标识应为每个文件存储使用哪个文件存储提供程序(文件系统、云储存等)。但是,此配置超出了本主题的讨论范围。
文件存储始终可完全供代码访问,但是,Limyee 电商平台可以使用 ICentralizedFileStore 的扩展插件类型 IGloballySecuredCentralizedFileStore 和 ISecuredCentralizedFileStore,从而保护用户通过URL读取文件的可访问性。
全局安全文件存储是最简单的安全文件存储形式,要么每个人都可以访问文件,要么没有人有权访问文件。可访问性始终是全局的(适用于所有用户)。
若要实现全局安全的文件存储,请在现有 ICentralizedFileStore 上实现 IGloballySecuredCentralizedFileStore 接口,并在 IsAccessible 方法中定义可访问逻辑。例如,下面是一个完整的示例,显示了 IGloballySecuredCentralizedFileStore 的实现,该实现禁用了对“sample”文件存储中路径包含“secure”文件的所有访问:
using System;
using Limyee.Extensibility.Version1;
using Limyee.Extensibility.Storage.Version1;
namespace Samples
{
public class SampleGloballySecuredFileStore : IPlugin, ICentralizedFileStore, IGloballySecuredCentralizedFileStore
{
#region IPlugin Implementation
public string Name
{
get
{
return "Sample File Store";
}
}
public string Description
{
get
{
return "A sample store of files.";
}
}
public void Initialize()
{
}
#endregion
#region ICentralizedFileStore Implementation
public string FileStoreKey
{
get
{
return "samples";
}
}
#endregion
#region IGloballySecuredCentralizedFileStore
public bool IsAccessible(string path, string fileName)
{
return string.IsNullOrEmpty(path) || !path.StartsWith("secure", StringComparison.OrdinalIgnoreCase);
}
#endregion
}
}
与全局安全的文件存储不同,根据尝试通过 URL 访问文件的用户,可以对特定用户的安全文件存储进行不同的保护。若要实现特定用户的安全文件存储,请在现有 ICentralizedFileStore 上实现 ISecuredFileStore 接口,并定义 UserHasAccess 方法。
例如,我添加对原始的“sample”文件存储保护,以便只有注册用户(非匿名用户)才能访问文件存储中的任何文件:
using System;
using Limyee.Extensibility.Version1;
using Limyee.Extensibility.Storage.Version1;
using Limyee.Extensibility.Api.Version1;
using Limyee.Extensibility;
namespace Samples
{
public class SampleSecuredFileStore : IPlugin, ICentralizedFileStore, ISecuredCentralizedFileStore
{
#region IPlugin Implementation
public string Name
{
get
{
return "Sample File Store";
}
}
public string Description
{
get
{
return "A sample store of files.";
}
}
public void Initialize()
{
}
#endregion
#region ICentralizedFileStore Implementation
public string FileStoreKey
{
get
{
return "samples";
}
}
#endregion
#region ISecuredCentralizedFileStore
public bool UserHasAccess(int userId, string path, string fileName)
{
var userApi = Apis.Get<IUsers>();
if (userApi == null)
return false;
var user = userApi.Get(new UsersGetOptions
{
Id = userId
});
return user != null && !user.HasErrors() && user.Username != userApi.AnonymousUserName;
}
#endregion
}
}
此示例使用用户 API 检索基于 userId 的用户详细信息,然后提供给 UserHasAccess 方法 ,并确定提供的用户是否为匿名用户。
有时,可能需要重定向文件存储中的文件或在首次访问时生成文件。例如,如果必须处理文件或者处理是密集的(例如,LESS 文件或调整图像大小),则应存储结果,但可能需要等待请求文件创建新的文件处理版本。
为了启用这些方案,Limyee 电商平台将使用 IFindableCentralizedFileStore 扩展 ICentralizedFileStore 接口。此扩展为文件存储提供了当所请求的文件不存在时收到通知的机会,或使文件存储能够调整文件请求。
找不到文件时,将为 IFindableCentralizedFileStore 提供文件存储 Key、路径和文件名作为请求的引用参数。如果 IFindableCentralizedFileStore 可以找到(或生成文件),它可以更新这些标识符并返回 true(将文件标识为已找到)。如果找不到或生成文件,则返回 false,并提供常规的 404/未找到响应。查找过程通常对用户是透明的,但可能需要 HTTP 重定向,具体取决于为文件存储提供服务的文件存储提供程序配置。
在下面的示例中,我更新了原始示例文件存储,以实现 IFindableCentralizedFileStore,并定义了 FindFile 方法,将任何丢失的文件重定向到文件存储根目录的“notfound.png”文件:
using System;
using Limyee.Extensibility.Version1;
using Limyee.Extensibility.Storage.Version1;
namespace Samples
{
public class SampleFindableFileStore : IPlugin, ICentralizedFileStore, IFindableCentralizedFileStore
{
#region IPlugin Implementation
public string Name
{
get
{
return "Sample File Store";
}
}
public string Description
{
get
{
return "A sample store of files.";
}
}
public void Initialize()
{
}
#endregion
#region ICentralizedFileStore Implementation
public string FileStoreKey
{
get
{
return "samples";
}
}
#endregion
#region IFindableCentralizedFileStore
public bool FindFile(ref string fileStoreKey, ref string path, ref string fileName)
{
path = string.Empty;
fileName = "notfound.png";
return true;
}
#endregion
}
}