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 } }