在运行时更改蓝图或重新加载 Flask 应用程序

Man*_*ert 5 python flask

我正在编写一个支持插件架构的 Flask 应用程序。每个插件都位于一个单独的文件夹中,并且是一个模块,该模块至少具有一个类,该类是一个类的子类Plugin。出于安全原因,我不想在 Flask 应用程序最初运行时加载所有插件。相反,用户可以从 Flask 应用程序内启用插件。一旦他这样做了,我们就会在数据库中存储一份备忘录,将要加载的应用程序列入白名单。然而,我们仍然必须记住哪些插件被禁用以及这些插件的经过验证的视图。我通过为未启用且不加载任何自定义代码的插件创建一个虚拟类来实现此目的。

每个插件都有自己的蓝图。我们在加载插件时注册它。蓝图还定义了启用插件的路线。整个事情看起来是这样的:

for plugin_name in os.listdir(plugin_dir):
    plugin_path = os.path.join(plugin_paths, plugin_name)
    module_name = "plugins.{}.__init__".format(plugin_name)
    plugin_enabled = ask_db_whether_plugin_is_enabled(plugin_name)

    if os.path.isdir(plugin_path) and plugin_enabled:
        module = __import__(module_name)
        for plugin in load_plugins_from_module(module):
            app.register_blueprint(plugin.blueprint, url_prefix='/plugins')
    else:
        PluginCls = type(identifier, (Plugin, ), {})
        disabled_plugin = PluginCls()
        app.register_blueprint(disabled_plugin.blueprint, url_prefix='/plugins')
Run Code Online (Sandbox Code Playgroud)

load_plugins_from_module看起来像这样:

def load_plugins_from_module(module):
    def is_plugin(c):
        return inspect.isclass(c) and \
               issubclass(c, Plugin) and \
               c != Plugin

    for name, objects in inspect.getmembers(module, lambda c: inspect.ismodule(c)):
        for name, PluginCls in inspect.getmembers(objects, is_plugin):
            plugin = PluginCls()
            yield plugin
Run Code Online (Sandbox Code Playgroud)

现在的问题是:当我将插件更改为启用时,我基本上想重新运行

module = __import__(module_name)
for plugin in load_plugins_from_module(module):
    app.register_blueprint(plugin.blueprint, url_prefix='/plugins')
Run Code Online (Sandbox Code Playgroud)

对于该插件的模块,使其变为活动状态并注册子类插件中定义的所有路由。这会引发一个问题AssertionError,因为我无法在运行时更改蓝图。对此有什么好的解决方法吗?我可以从应用程序内重新加载应用程序吗?我可以在运行时修改现有的蓝图吗?

感谢您的帮助!

Dex*_*ter 1

我不确定你是否需要把这个复杂化。

您只需为要启用的插件设置配置选项即可。您可以根据“Start_app()”方法中的配置注册您的蓝图。

您还可以动态设置从某些文件夹/文件继承的配置选项,例如使其更加动态。

插件通常由开发人员开发,因此配置选项并不麻烦,除非您尝试构建每个随机用户都可以修改您的网站的东西,这可能会带来巨大的安全问题。

出于安全原因,我不想在 Flask 应用程序最初运行时加载所有插件。

我对此不太确定。不允许用户手动启动插件,会带来更大的安全风险(因此,如果用户秘密地能够上传代码,然后现在他可以启用它们)。

您可以像 WordPress 一样创建一个支持插件的 CMS,只需在用户单击“激活插件”之前不路由插件的 URL