Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to override a Flask blueprint URL?

I am using flask-mwoauth to create a simple application in Flask using OAuth authentication on Mediawiki (and Wikipedia in particular).

flask-mwoauth is a blueprint that provides some convenience methods to interact with Mediawiki Extensions:OAuth and adds the following URIs:

  • /login - runs the OAuth handshake and returns the user to /
    • /login?next=/someurl will return the user to /someurl
  • /logout - clears the users' access tokens
    • /logout?next=/someurl will return the user to /someurl
  • /oauth-callback - callback from MW to finish the handshake

The users' OAuth key and secret are stored in the session.

I would like to be able to create custom responses for some of this custom URIs. Take for example /logout, the definition of the response in very simple (__init__.py#L56):

@self.bp.route('/logout')
def logout():
    session['mwo_token'] = None
    session['username'] = None
    if 'next' in request.args:
        return redirect(request.args['next'])
    return "Logged out!"

I would like to define in my application the route /logout with a custom response (for example, rendering a template), however if I use the blueprint then the route @app.route("/logout") is ignored.

What I would like to know if it is possible to "extend" the blueprint in the sense that I can define a route /logout in my app, call the original method from the blueprint and then serve a customized response.

like image 499
CristianCantoro Avatar asked Jul 09 '16 17:07

CristianCantoro


People also ask

How do I import blueprints into flask?

To use any Flask Blueprint, you have to import it and then register it in the application using register_blueprint() . When a Flask Blueprint is registered, the application is extended with its contents. While the application is running, go to http://localhost:5000 using your web browser.

What does .route do in flask?

App Routing means mapping the URLs to a specific function that will handle the logic for that URL. Modern web frameworks use more meaningful URLs to help users remember the URLs and make navigation simpler. Example: In our application, the URL (“/”) is associated with the root URL.

How does blueprint work in flask?

Now, this is where Flask Blueprints come into picture. Blueprints help you structure your application by organizing the logic into subdirectories. In addition to that, you can store your templates and static files along with the logic in the same subdirectory. Now you can see that you have clear separation of concerns.


1 Answers

If you want to completely redefine behavior of route the best way is override MWOAuth class. Here an example which works:

import os

from flask import Flask, Blueprint
from flask_mwoauth import MWOAuth

app = Flask(__name__)
app.secret_key = os.urandom(24)


class MyMWOAuth(MWOAuth):
    def __init__(self,
                 base_url='https://www.mediawiki.org/w',
                 clean_url="Deprecated",
                 default_return_to='index',
                 consumer_key=None,
                 consumer_secret=None,
                 name="Deprecated"):
        # I skipped other rows. It's just an example
        self.bp = Blueprint('mwoauth', __name__)
        # By the way you can customize here login and oauth-callback
        @self.bp.route('/logout')
        def logout():
            # your custom logic here...
            return "My custom logout"


mwoauth = MyMWOAuth(consumer_key='test', consumer_secret='test')
app.register_blueprint(mwoauth.bp)


if __name__ == "__main__":
    app.run(debug=True, threaded=True)

Let's open /logout. You will see My custom logout. As you can see registration of BluePrint routes takes place in init method of MWOAuth.

The second way is to use request callbacks. Here an example which demonstrates the change in the body of the response after logout.

from flask import g, request


def after_this_request(f):
    if not hasattr(g, 'after_request_callbacks'):
        g.after_request_callbacks = []
    g.after_request_callbacks.append(f)
    return f


@app.after_request
def call_after_request_callbacks(r):
    for callback in getattr(g, 'after_request_callbacks', ()):
        callback(r)
    return r


@app.before_request
def before_logout():
    @after_this_request
    def after_logout(response):
        # check if called route == '/logout'
        # in our case response.data == 'Logged out!'
        # see: https://github.com/valhallasw/flask-mwoauth/blob/master/flask_mwoauth/__init__.py#L48
        if request.url_rule.endpoint == 'mwoauth.logout':
            # custom logic here...
            # for example I change data in request
            response.data = 'Data from after_logout'

Let's open /logout. You will see Data from after_logout.

Hope this helps.

like image 147
Danila Ganchar Avatar answered Sep 27 '22 16:09

Danila Ganchar