Flask/Werkzeug, how to return previous page after login

Jon Cox picture Jon Cox · Sep 10, 2010 · Viewed 12.3k times · Source

I am using the Flask micro-framework which is based on Werkzeug, which uses Python.

Before each restricted page there is a decorator to ensure the user is logged in, currently returning them to the login page if they are not logged in, like so:

# Decorator
def logged_in(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        try:
            if not session['logged_in']:
                flash('Please log in first...', 'error')
                return redirect(url_for('login'))
            else:
                return f(*args, **kwargs)
        except KeyError:
            flash('Please log in first...', 'error')
            return redirect(url_for('login'))
    return decorated_function


# Login function
@app.route('/', methods=['GET', 'POST'])
def login():
    """Login page."""
    if request.method=='POST':
    ### Checks database, etc. ###
    return render_template('login.jinja2')


# Example 'restricted' page
@app.route('/download_file')
@logged_in
def download_file():
    """Function used to send files for download to user."""
    fileid = request.args.get('id', 0)
    ### ... ###

After logging in, it needs to return users to the page that took them to the login page. It also needs to retain things such as the passed variables (i.e. the entire link basically www.example.com/download_file?id=3 )

Does anyone know how to do this?

Thank you for your help :-)

Answer

Will McCutchen picture Will McCutchen · Sep 10, 2010

I think standard practice is to append the URL to which the user needs to be redirected after a successful login to the end of the login URL's querystring.

You'd change your decorator to something like this (with redundancies in your decorator function also removed):

def logged_in(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if session.get('logged_in') is not None:
            return f(*args, **kwargs)
        else:
            flash('Please log in first...', 'error')
            next_url = get_current_url() # However you do this in Flask
            login_url = '%s?next=%s' % (url_for('login'), next_url)
            return redirect(login_url)
    return decorated_function

You'll have to substitute something for get_current_url(), because I don't know how that's done in Flask.

Then, in your login handler, when the user successfully logs in, you check to see if there's a next parameter in the request and, if so, you redirect them to that URL. Otherwise, you redirect them to some default URL (usually /, I guess).