Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Flask中的自定义身份验证和参数检查_Python_Http_Flask_Decorator_Python 2.x - Fatal编程技术网

Python Flask中的自定义身份验证和参数检查

Python Flask中的自定义身份验证和参数检查,python,http,flask,decorator,python-2.x,Python,Http,Flask,Decorator,Python 2.x,我目前正在重构两年前写的一个Flask应用程序,我怀疑我做了一些事情没有使用该库可能做到的优雅和干净。因此,我想就如何改善现状征求一些建议: 该应用程序提供了许多API端点,每个端点都可以通过/形式的路由访问,其中是10个不同类别中的一个 对于每个,我创建了一个不同的Python模块.py,将其放置在api/子目录和一个不同的flask.Blueprint(实际上是它的一个子类,见下文)中,并将其注册到主app=flask(\uu name\uuu) 每个模块.py都包含许多函数,这些函数用作各

我目前正在重构两年前写的一个Flask应用程序,我怀疑我做了一些事情没有使用该库可能做到的优雅和干净。因此,我想就如何改善现状征求一些建议:

  • 该应用程序提供了许多API端点,每个端点都可以通过
    /
    形式的路由访问,其中
    是10个不同类别中的一个
  • 对于每个
    ,我创建了一个不同的Python模块
    .py
    ,将其放置在
    api/
    子目录和一个不同的
    flask.Blueprint
    (实际上是它的一个子类,见下文)中,并将其注册到主
    app=flask(\uu name\uuu)
  • 每个模块
    .py
    都包含许多函数,这些函数用作各自类别的端点,并且每个函数都用路由装饰器装饰
  • 到目前为止还不错

    每个端点函数都接受大量参数,这些参数可以作为GET请求的参数传递,也可以作为POST请求的JSON有效负载中的
    参数
    字段的一部分传递。因此,在调用相应的端点函数之前,将检查是否提供了具有正确名称的正确数量的参数

    此外,应用程序需要检查是否允许客户端调用某个函数。为此,将读取由Web服务器设置的环境变量
    SSL\u CLIENT\u CERT
    (在我的例子中,lighttpd over FCGI)并将其指纹与某些内部权限文件进行比较

    因为我不太知道把逻辑放在哪里去做上面的事情,所以我对flask.Blueprint进行了子类化,并编写了我自己的(修改的)
    route
    decorator(
    custom\u route
    )。此装饰器现在要么返回定制的错误响应(
    flask.response
    object),要么返回定制的成功响应(从而使用从客户端传递的参数调用端点函数)

    因此,一个模块
    category_xy.py
    如下所示:

    category_xy = CustomBlueprint('category_xy', __name__)    
    
    @category_xy.custom_route('/category_xy/some_endpoint',
                              auth_required=True,
                              methods=['GET', 'POST'])
    def some_endpoint(foo, bar):
        # do stuff 
        return '123'
    
    CustomBlueprint
    在单独的文件中定义为(部分伪代码):

    这是可行的,但感觉一点也不干净,我认为应该有更好、更干净的方法来做到这一点。将所有这些逻辑放在自定义装饰器中感觉非常错误


    有经验的人能提供一些想法和/或最佳实践吗?

    首先,您可以切换到-API,它允许您将视图函数作为类编写:

    from flask import Blueprint, Response, render_template
    from flask.views import View
    
    from models import db, CategoryXY # Let`s have here a database model
    
    category_blueprint = Blueprint('category_xy', __name__)
    
    class CategoryXYView(View):
        def get_list(self):
            items = db.session.query(CategoryXY).all()
            return render_template('category_xy_list.html', items=items)
    
        def get_one(self, item_id):
            item = db.session.query(CategoryXY).first()
            if item is None:
                return Response(status=404)
            return render_template('category_xy_edit.html', item=item)
    
        def dispatch_request(self, item_id):
            """Required method which handles incoming requests"""
            if item_id is None:
                return self.get_list()
            return self.get_one(item_id)
    
    category_xy_view = CategoryXYView.as_view('category_xy')
    category_blueprint.add_url_rule(
        'category_xy',
        view_func=category_xy_view,
        defaults={'item_id': None}
    )
    category_blueprint.add_url_rule(
        'category_xy/<item_id>',
        view_func=category_xy_view
    )
    
    为了自动生成路由,您可以为
    BaseView
    编写一个元类。每个新类的路由将在类定义后生成:

    class ViewMeta(type):
        def __new__(mcs, name, bases, attributes):
            cls = type(name, bases, attributes)
    
            if cls.route is not None:
                view_function = cls.as_view(cls.route)
                category_blueprint.add_url_rule(
                    cls.route,
                    view_func=view_function,
                    defaults={'item_id': None}
                )
                category_blueprint.add_url_rule(
                    '{}/<item_id>'.format(cls.route),
                    view_func=view_function
                )
            return cls
    
    class BaseView(View):
        __metaclass__ = ViewMeta
        route = None
        model = None
        # Other common attributes
    
    class CategoryXYView(BaseView):
        route = 'category_xy'
        model = CategoryXY
    
    class ViewMeta(类型):
    定义新(mcs、名称、基础、属性):
    cls=类型(名称、基础、属性)
    如果cls.route不是None:
    视图功能=cls.as\U视图(cls.route)
    类别\u蓝图。添加\u url\u规则(
    中环线,
    视图函数=视图函数,
    默认值={'item_id':None}
    )
    类别\u蓝图。添加\u url\u规则(
    “{}/”格式(cls.route),
    查看功能=查看功能
    )
    返回cls
    类BaseView(视图):
    __元类\视图元数据
    路线=无
    型号=无
    #其他共同属性
    类类别yxyView(基本视图):
    路线='category_xy'
    模型=类别
    
    我想您的类别有一些共同点:类似的端点名称、授权机制、验证函数。是吗?是的!每个端点函数都会触发服务器上的某些操作。一个类别中的所有操作都有一定的相关性,并且通常也有类似的端点名称。
    class BaseView(View):
        model = None
        edit_template = None
        list_template = None
    
        def get_one(self, item_id):
            item = db.session.query(self.model).filter_by(id=item_id).first()
            if item is None:
                return Response(status=404)
            return render_template(self.edit_template, item=item)
    
        def get_list(self):
            items = db.session.query(self.model).all()
            return render_template(self.list_template, items=items)
    
        def dispatch_request(self, item_id):
            if item_id is None:
                return self.get_list()
            return self.get_one(item_id)
    
    class CategoryXYView(BaseView):
        model = CategoryXY
        edit_template = 'category_xy_edit.html'
        list_template = 'category_xy_list.html'
    
    category_xy_view = CategoryXYView.as_view('category_xy')
    category_blueprint.add_url_rule(
        'category_xy',
        view_func=category_xy_view,
        defaults={'item_id': None}
    )
    category_blueprint.add_url_rule(
        'category_xy/<item_id>',
        view_func=category_xy_view
    )
    
    class CategoryXXView(BaseView):
        model = CategoryXX
        edit_template = 'category_xx_edit.html'
        list_template = 'category_xx_list.html'
    
        def get_one(self, item_id):
            item = db.session.query(self.model).first()
            if item is None:
                return Response(status=404)
            xy_items = db.session.query(CategoryXY).all()
            return render_template(self.edit_template, item=item, xy_items=xy_items)
    
    class ViewMeta(type):
        def __new__(mcs, name, bases, attributes):
            cls = type(name, bases, attributes)
    
            if cls.route is not None:
                view_function = cls.as_view(cls.route)
                category_blueprint.add_url_rule(
                    cls.route,
                    view_func=view_function,
                    defaults={'item_id': None}
                )
                category_blueprint.add_url_rule(
                    '{}/<item_id>'.format(cls.route),
                    view_func=view_function
                )
            return cls
    
    class BaseView(View):
        __metaclass__ = ViewMeta
        route = None
        model = None
        # Other common attributes
    
    class CategoryXYView(BaseView):
        route = 'category_xy'
        model = CategoryXY