首页 文章

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

提问于
浏览
4

我正在编写一个支持插件架构的Flask应用程序 . 每个插件都位于一个单独的文件夹中,并且是一个至少有一个类的类,该类是 Plugin 类的子类 . 出于安全原因,我没有加载任何自定义代码 .

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

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')

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

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

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

对于该插件的模块,以便它变为活动状态并注册已在子类插件中定义的所有路由 . 这将引发 AssertionError 因为我无法在运行时更改蓝图 . 什么是好的解决方案呢?我可以从应用程序中重新加载应用程序吗?我可以在运行时修改现有的蓝图吗?

谢谢你的帮助!

3 回答

  • 0

    我不确定你是否需要让这个变得复杂 .

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

    您还可以动态设置要从某些文件夹/文件继承的配置选项,以使其更具动态性 .

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

    出于安全考虑,我不想在最初运行烧瓶应用程序时加载所有插件 .

    我不确定这一点 . 不允许用户手动启动插件,更具安全风险(因此,如果用户秘密地能够上传代码,那么现在他可以启用它们) .

    你可以创建一个像WordPress一样的插件启用CMS,只需不要路由插件的网址,直到用户点击“激活插件”

  • 1

    我不确定如何在运行时修改app对象,但有一种替代方法可以尝试满足您的需求 .

    • 创建一个名为“Plugins”的表,其中包含2列:
    Field 1: Blueprint name
    
    Field 2: isActive
    
    • 为用户提供可以“激活”所需插件的界面 . 您可以根据需要控制对它的访问 . 所以你可以写一个如下的视图:
    @login_required
    def activate_plugin(name):
    
    #whatever code is needed to activate the flag in Plugins table.
    
    • 蓝图可以有一个before_request()方法,可用于检查是否启用了插件/蓝图 . 如果没有启用,则返回404或任何代码 .
    @blueprintname.before_request
    def check_if_active(blueprintname):
    
        is_active = some_function_that_checks_plugin_active_flag()
        if is_active:
          #Normal processing
        else:
            abort(404)
    
    • 这样,对蓝图视图的每个请求都将在返回响应之前首先检查它是否处于活动状态 .
  • 1

    您可以使用Application Dispatching模式在运行时重新创建Flask应用程序对象 .

    以下是关于如何在调用特殊 endpoints 时重新加载Flask应用程序的要点,您当然可以将其调整为从数据库中读取:

    https://gist.github.com/nguyenkims/ff0c0c52b6a15ddd16832c562f2cae1d

相关问题