The documentation for Flask-login talks about handling a "next" URL. The idea seems to be:
- User goes to
/secret
- User is redirect to a login page (e.g.
/login
) - After a successful login, the user is redirected back to
/secret
The only semi-full example using Flask-login that I've found is https://gist.github.com/bkdinoop/6698956 . It's helpful, but since it doesn't include the HTML template files, I'm seeing if I can recreate them as an self-training exercise.
Here's a simplified version of the /secret
and /login
section:
@app.route("/secret")
@fresh_login_required
def secret():
return render_template("secret.html")
@app.route("/login", methods=["GET", "POST"])
def login():
<...login-checking code omitted...>
if user_is_logged_in:
flash("Logged in!")
return redirect(request.args.get("next") or url_for("index"))
else:
flash("Sorry, but you could not log in.")
return render_template("login.html")
And here's login.html
:
<form name="loginform" action="{{ url_for('login') }}" method="POST">
Username: <input type="text" name="username" size="30" /><br />
Password: <input type="password" name="password" size="30" /><br />
<input type="submit" value="Login" /><br />
Now, when the user visits /secret
, he gets redirected to /login?next=%2Fsecret
. So far, so good - the "next" parameter is in the query string.
However when the user submits the login form, he is redirected back to the index page, not back to the /secret
URL.
I'm guessing the reason is because the "next' parameter, which was available on the incoming URL, is not incorporated into the login form and is therefore not being passed as a variable when the form is processed. But what's the right way to solve this?
One solution seems to work - change the <form>
tag from
<form name="loginform" action="{{ url_for('login') }}" method="POST">
to:
<form name="loginform" method="POST">
With the "action" attribute removed, the browser (at least Firefox 45 on Windows) automatically uses the current URL, causing it to inherit the ?next=%2Fsecret
query string, which successfully sends it on to the form processing handler.
But is omitting the "action" form attribute and letting the browser fill it in the right solution? Does it work across all browsers and platforms?
Or does Flask or Flask-login intend for this to be handled in a different way?