为每个CKFinder 3实例的S3存储桶设置公共密钥前缀 [英] Set common key prefix for S3 bucket per CKFinder 3 instance

查看:84
本文介绍了为每个CKFinder 3实例的S3存储桶设置公共密钥前缀的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使CKFinder ASP.net S3集成从动态键前缀而不是仅从根位置加载内容?

How can I make the CKFinder ASP.net S3 integration load content from a dynamic key prefix rather than just a root location?

我将CKEditor 5和CKFinder 3与ASP.net连接器配合使用,以允许将图像直接上传到S3存储桶.我们要连接的所有Web应用程序都不是ASP.net应用程序.

I'm using CKEditor 5 and CKFinder 3 with the ASP.net Connector to allow image upload directly to an S3 bucket. The web application we are connecting this all to is not an ASP.net application.

按照文档进行设置非常简单.

Setting is up was simple enough by following the documentation.

但是,我们的产品是SaaS,因此每次启动CKFinder时,我都需要它来定位存储桶中的其他键前缀.多个网站运行同一应用程序,并且每个网站都应该能够通过CKFinder加载自己的图像库,而看不到其他应用程序的图像.

However, our product is SaaS, so each time the CKFinder is launched, I need it to target a different key prefix in our bucket. Multiple websites run off the same app and each should be able to have their own gallery of images loaded via the CKFinder without being able to see the images belonging to other apps.

我们的CKFinder Web.config:

Our CKFinder Web.config:

<backend name="s3Bucket" adapter="s3">
   <option name="bucket" value="myBucket" />
   <option name="key" value="KEYHERE" />
   <option name="secret" value="SECRETHERE" />
   <option name="region" value="us-east-1" />
   <option name="root" value="images" />
 </backend>

此配置将内容很好地放入了/images/公用密钥前缀文件夹"中,但是对于每个使用CKFinder的应用程序,我希望它从不同的根"中读取:

This config gets content into the /images/ common key prefix "folder" just great, but for each app that uses the CKFinder, I want it to read from a different "root":

/images/app1Id/
/images/app2Id/
/images/app3Id/

理想情况下,我想在调用Editor/Finder实例时进行设置;像这样:

Ideally, I want to set this when invoking the Editor/Finder instance; something like:

ClassicEditor.create( document.querySelector( '#textareaId' ), {
    ckfinder: {
        uploadUrl: '/ckfinder/connector?command=QuickUpload&type=Images&responseType=json',
        connectorRoot: '/images/app1Id/'
    },
    toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'ckfinder' ],
    heading: {
        options: [
            { model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },
            { model: 'heading1', view: 'h1', title: 'Heading 1', class: 'ck-heading_heading1' },
            { model: 'heading2', view: 'h2', title: 'Heading 2', class: 'ck-heading_heading2' }
        ]
    }
});

在这里我添加了connectorRoot: '/images/app1Id/'作为我想通过的示例.

Here I added connectorRoot: '/images/app1Id/' as an example of what I would like to pass.

有什么办法可以做这样的事情吗?我通读了ASP.net连接器文档,发现可以建立自己的连接器并使用pass发送数据,但是必须编译和维护自定义连接器听起来并不好玩.这里的S3连接非常简单方便...只要让我更具体一点即可.

Is there some way to do something like this? I've read through the ASP.net Connector docs and see that you can build your own connector and use pass to send it data, but having to compile and maintain a custom connector does not sound very fun. The S3 connectivity here is so great and easy... if only it let me be a little more specific.

推荐答案

我们来到的解决方案是修改和自定义CKFinder ASP Connector.非常感谢CKSource团队帮助我们实现了这一目标.

The solution we came to was to modify and customize the CKFinder ASP Connector. Big thanks to the CKSource team for helping us to get this running.

ConnectorConfig.cs

namespace CKSource.CKFinder.Connector.WebApp
{
    using System.Configuration;
    using System.Linq;

    using CKSource.CKFinder.Connector.Config;
    using CKSource.CKFinder.Connector.Core.Acl;
    using CKSource.CKFinder.Connector.Core.Builders;
    using CKSource.CKFinder.Connector.Host.Owin;
    using CKSource.CKFinder.Connector.KeyValue.FileSystem;
    using CKSource.FileSystem.Amazon;
    //using CKSource.FileSystem.Azure;
    //using CKSource.FileSystem.Dropbox;
    //using CKSource.FileSystem.Ftp;
    using CKSource.FileSystem.Local;

    using Owin;

    public class ConnectorConfig
    {
        public static void RegisterFileSystems()
        {
            FileSystemFactory.RegisterFileSystem<LocalStorage>();
            //FileSystemFactory.RegisterFileSystem<DropboxStorage>();
            FileSystemFactory.RegisterFileSystem<AmazonStorage>();
            //FileSystemFactory.RegisterFileSystem<AzureStorage>();
            //FileSystemFactory.RegisterFileSystem<FtpStorage>();
        }

        public static void SetupConnector(IAppBuilder builder)
        {
            var allowedRoleMatcherTemplate = ConfigurationManager.AppSettings["ckfinderAllowedRole"];
            var authenticator = new RoleBasedAuthenticator(allowedRoleMatcherTemplate);

            var connectorFactory = new OwinConnectorFactory();
            var connectorBuilder = new ConnectorBuilder();
            var connector = connectorBuilder
                .LoadConfig()
                .SetAuthenticator(authenticator)
                .SetRequestConfiguration(
                    (request, config) =>
                    {

                        config.LoadConfig();

                        var defaultBackend = config.GetBackend("default");
                        var keyValueStoreProvider = new FileSystemKeyValueStoreProvider(defaultBackend);
                        config.SetKeyValueStoreProvider(keyValueStoreProvider);

                        // Remove dummy resource type
                        config.RemoveResourceType("dummy");

                        var queryParameters = request.QueryParameters;

                        // This code lacks some input validation - make sure the user is allowed to access passed appId
                        string appId = queryParameters.ContainsKey("appId") ? Enumerable.FirstOrDefault(queryParameters["appId"]) : string.Empty;

                        // set up an array of StringMatchers for folder to hide!
                        StringMatcher[] hideFoldersMatcher = new StringMatcher[] { new StringMatcher(".*"), new StringMatcher("CVS"), new StringMatcher("thumbs"), new StringMatcher("__thumbs") };

                        // image type resource setup
                        var fileSystem_Images = new AmazonStorage(secret: "SECRET-HERE",
                                                            key: "KEY-HERE",
                                                            bucket: "BUCKET-HERE",
                                                            region: "us-east-1",
                                                            root: string.Format("images/{0}/userimages/", appId),
                                                            signatureVersion: "4");

                        string[] allowedExtentions_Images = new string[] {"gif","jpeg","jpg","png"};

                        config.AddBackend("s3Images", fileSystem_Images, string.Format("CDNURL-HERE/images/{0}/userimages/", appId), false);

                        config.AddResourceType("Images", resourceBuilder => {
                            resourceBuilder.SetBackend("s3Images", "/")
                            .SetAllowedExtensions(allowedExtentions_Images)
                            .SetHideFoldersMatchers(hideFoldersMatcher)
                            .SetMaxFileSize( 5242880 );
                        });

                         // file type resource setup
                        var fileSystem_Files = new AmazonStorage(secret: "SECRET-HERE",
                                                        key: "KEY-HERE",
                                                        bucket: "BUCKET-HERE",
                                                        region: "us-east-1",
                                                        root: string.Format("docs/{0}/userfiles/", appId),
                                                        signatureVersion: "4");

                        string[] allowedExtentions_Files = new string[] {"csv","doc","docx","gif","jpeg","jpg","ods","odt","pdf","png","ppt","pptx","rtf","txt","xls","xlsx"};

                        config.AddBackend("s3Files", fileSystem_Files, string.Format("CDNURL-HERE/docs/{0}/userfiles/", appId), false);

                        config.AddResourceType("Files", resourceBuilder => {
                            resourceBuilder.SetBackend("s3Files", "/")
                            .SetAllowedExtensions(allowedExtentions_Files)
                            .SetHideFoldersMatchers(hideFoldersMatcher)
                            .SetMaxFileSize( 10485760 );
                        });

                    })
                .Build(connectorFactory);

            builder.UseConnector(connector);
        }
    }
}

注意事项:

  • 添加了using System.Linq;,以便FirstOrDefault在获取appId时有效
  • 我们删除了一些文件系统(Azure,Dropbox,Ftp),因为我们没有在集成中使用这些文件系统
  • 在CKFinder web.config文件中,我们创建了一个虚拟"资源类型,因为Finder要求至少存在一个虚拟资源,但是随后我们在连接器配置期间将其删除,并用所需的资源类型<resourceTypes><resourceType name="dummy" backend="default"></resourceType>resourceTypes>
  • 请注意并注意您在此文件中放置了一些敏感信息.请考虑如何(或不可以)对版本进行控制,并且您可能需要采取其他措施以使其更加安全
  • Added using System.Linq; so that FirstOrDefault works when getting the appId
  • We removed some of the fileSystems (Azure,Dropbox,Ftp) because we do not use those in our integration
  • In the CKFinder web.config file, we create a 'dummy' resource type because the Finder requires at least one to be present, but we then remove it during connector config and replace it with our desired resource types <resourceTypes><resourceType name="dummy" backend="default"></resourceType>resourceTypes>
  • Please note and take care that you're placing some sensitive information in this file. Please consider how you version control this (or not) and you may want to take additional actions to make this more secure

初始化CKEditor4/CKFinder3实例

<script src="/js/ckeditor/ckeditor.js"></script>
<script src="/js/ckfinder3/ckfinder.js"></script>

<script type="text/javascript">

    var myEditor = CKEDITOR.replace( 'bodyContent', {

        toolbar:                    'Default',
        width:                      '100%',
        startupMode:                'wysiwyg',

        filebrowserBrowseUrl:       '/js/ckfinder3/ckfinder.html?type=Files&appId=12345',
        filebrowserUploadUrl:       '/js/ckfinder3/connector?command=QuickUpload&type=Files&appId=12345',

        filebrowserImageBrowseUrl:  '/js/ckfinder3/ckfinder.html?type=Images&appId=12345',
        filebrowserImageUploadUrl:  '/js/ckfinder3/connector?command=QuickUpload&type=Images&appId=12345',

        uploadUrl:                  '/js/ckfinder3/connector?command=QuickUpload&type=Images&responseType=json&appId=12345'

    });
</script>

注意事项:

  • 由于其他集成要求,此处使用的是手动集成"方法,这要求我们手动定义filebrowserUrls
  • 当前,在文件browserUrls中添加&pass=appId或在config.js文件中添加config.pass = 'appId';并不能正确地将pass所需值传递给编辑器
  • 我相信这只会在使用手动积分"方法时失败(如果您使用的是CKFinder.setupCKEditor(),它将正确运行)
  • Due to other integration requirements, are using the Manual Integration method here, which requires us to manually define our filebrowserUrls
  • Currently, adding &pass=appId to your filebrowserUrls or adding config.pass = 'appId'; to your config.js file does not properly pass the desired value through to the editor
  • I believe this only fails when using the Manual Integration method (it should work correctly if you're using CKFinder.setupCKEditor())

ckfinder.html

<!DOCTYPE html>
<!--
Copyright (c) 2007-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or https://ckeditor.com/sales/license/ckfinder
-->
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
    <title>CKFinder 3 - File Browser</title>
</head>
<body>

<script src="ckfinder.js"></script>
<script>

    var urlParams = new URLSearchParams( window.location.search );
    var myAppId = ( urlParams.has( 'appId' ) ) ? urlParams.get( 'appId' ) : '';

    if ( myAppId !== '' ) {
        CKFinder.start( { pass: 'appId', appId: myAppId } );
    } else {
        document.write( 'Error loading configuration.' );
    }

</script>

</body>
</html>

注意事项:

  • 当集成到CKEditor5中时,这一切看起来似乎更加流畅,但是当集成到CKEditor4中时,在使用CKFinder的手动集成"方法时,将appId值正确地输入到编辑器中会遇到很多问题
  • 我们在此处修改ckfinder.html文件以查找所需的URL参数,并在启动时将它们pass放入CKFinder实例中.这样可以确保它们在整个Finder实例中传递
  • 查看此问题,以获取有关此过程的更多详细信息以及将 n 参数传递到Finder实例的更通用方法:
  • This all seems to work much more smoothly when integrating into CKEditor5, but when integrating into CKEditor4, we experience a lot of issues getting the appId value to pass properly into the editor when utilizing the Manual Integration method for CKFinder
  • We modify the ckfinder.html file here to look for the desired url params and pass them into the CKFinder instance as it's started. This ensures they are passed through the entirety of the Finder instance
  • Check out this question for some great further details about this process as well as a more generic method of passing n params into your Finder instances: How do I pass custom values to CKFinder3 when instantiating a CKEditor4 instance?

这篇关于为每个CKFinder 3实例的S3存储桶设置公共密钥前缀的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆