Looking at the Flask-Login docs and several relatively old threads on Stackoverflow, I am concerned about the security of my solution for passing the restricted page URL through the login process.
First, I was getting Attribution Error when trying to use @login_manager.unauthorized_handler
. ("login_manager
does not have an attribute unauthorized_handler
.") This a separate issue altogether, because it really should have worked. (See app factory below.)
When I applied a redirect_destination
function without the modified @login_manager.unauthorized_handler
, the login failed to redirect to the target destination.
def redirect_destination(dest_url, fallback):
try:
dest_url = url_for(dest_url)
except:
return redirect(fallback)
return redirect(dest_url)
Then I applied a session instance to be passed from the destination URL through login along with the fresh_login_required
decorator and .is_authenticated
property instead of the standard login_required
.
target blueprint:
@target.route('/target', methods=['GET', 'POST'])
@fresh_login_required
def target():
if current_user.is_authenticated:
...
return render_template('target.html')
else:
session['dest_url']=request.endpoint
return redirect(url_for('account.login'))
auth blueprint:
@account.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('main.index'))
dest_url = session.get('dest_url')
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if not user:
return redirect(url_for('account.login'))
if user.check_password(form.password.data):
login_user(user, remember=form.remember_me.data)
...
return redirect_destination(dest_url, fallback=url_for('main.index'))
else:
return redirect(url_for('account.login'))
return render_template('account/login.html')
app factory:
...
login_manager = LoginManager()
login_manager.login_view = 'account.login' #hard-coded view
login_manager.refresh_view = 'account.refresh' #hard-coded view
def create_app():
app = Flask(__name__,
static_url_path='/',
static_folder='../app/static',
template_folder='../app/templates')
db.init_app(app)
login_manager.init_app(app)
from app import models
from .templates.account import account
from .templates.main import main
from .templates.target import target
app.register_blueprint(main)
app.register_blueprint(account)
app.register_blueprint(target)
return app
So, this solution works, and it can be applied to multiple blueprints. My concern is that I am missing some important details that necessitated other, more complex solutions. Is there a security weak point? Other issues?
References:
https://flask-login.readthedocs.io/en/latest/
How do I pass through the "next" URL with Flask and Flask-login?
Flask/Werkzeug, how to return previous page after login
Flask how to redirect to previous page after successful login