Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask middleware for specific route

I made API Server with Python Flask-RESTful.

My system use token authentication for verify permission.

So, I added middleware for verify token.

For example, code like this,

[middleware.py]

class Test(object):
    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        print("gogo")
        return self.app(environ, start_response)

[app.py]

from flask import Flask
from flask_restful import Api
from api.board import Article
from api.auth import Login, Register, RefreshToken
from middleware import Test


app = Flask(__name__)
api = Api(app)

api.add_resource(Login, '/login')
api.add_resource(Register, '/register')
api.add_resource(RefreshToken, '/refresh')

# middleware here
app.wsgi_app = Test(app.wsgi_app)
api.add_resource(Article, '/article')

if __name__ == '__main__':
    app.run(debug=True)

I insert app.wsgi_app = Test(app.wsgi_app) before /article.

So I expect that only access to /article will print "gogo", however every route print "gogo".

Maybe every route pass through with middleware.

How can I apply middleware for specific route? (In this code, only /article)

like image 700
Hide Avatar asked Aug 05 '18 05:08

Hide


People also ask

How do you use middleware in Flask?

Middlewares are created in Flask by creating a decorator; a function can have multiple middlewares, and the order matters a lot. You need to add a secret key to your application; this is what you should pass to JWT. Add the following to your app.py file below the app declaration.

How do I protect my route in Flask?

One simple way this can be restricted is to check type of the user in createUser function and allow only if user is admin. But in general what is the best way to protect flask end points and give only few users the access to end points?

How do I post a route in Flask?

In order to demonstrate the use of POST method in URL routing, first let us create an HTML form and use the POST method to send form data to a URL. Now enter the following script in Python shell. After the development server starts running, open login. html in the browser, enter name in the text field and click Submit.

Can you use multiple decorators to route urls to a function in Flask?

The decorator syntax is just a little syntactic sugar. This code block shows an example using our custom decorator and the @login_required decorator from the Flask-Login extension. We can use multiple decorators by stacking them.


1 Answers

There are a few ways how to add custom processing before specific endpoint.

1) Using python decorator:

from functools import wraps

def home_decorator():
    def _home_decorator(f):
        @wraps(f)
        def __home_decorator(*args, **kwargs):
            # just do here everything what you need
            print('before home')
            result = f(*args, **kwargs)
            print('home result: %s' % result)
            print('after home')
            return result
        return __home_decorator
    return _home_decorator


@app.route('/home')
@home_decorator()
def home():
    return 'Hello'

2) Using before_request

@app.before_request
def hook():
    # request - flask.request
    print('endpoint: %s, url: %s, path: %s' % (
        request.endpoint,
        request.url,
        request.path))
    # just do here everything what you need...

3) Using middleware. Just add condition on request path.

class Middleware:

    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        # not Flask request - from werkzeug.wrappers import Request
        request = Request(environ)
        print('path: %s, url: %s' % (request.path, request.url))
        # just do here everything what you need
        return self.app(environ, start_response)


@app.route('/home')
def home():
    return 'Hello'


app.wsgi_app = Middleware(app.wsgi_app)

4) Also you can use before_request_funcs to set list of functions before specific blueprint.

api = Blueprint('my_blueprint', __name__)


def before_my_blueprint():
    print(111)


@api.route('/test')
def test():
    return 'hi'


app.before_request_funcs = {
    # blueprint name: [list_of_functions]
    'my_blueprint': [before_my_blueprint]
}

app.register_blueprint(api)

Hope this helps.

like image 176
Danila Ganchar Avatar answered Oct 29 '22 14:10

Danila Ganchar