Flask / Werkzeug, как вернуть предыдущую страницу после входа в систему
Вопрос
Я использую микро-фреймворк Flask, основанный на Werkzeug, который использует Python.
Перед каждой страницей с ограниченным доступом есть декоратор, обеспечивающий вход пользователя в систему, который в данный момент возвращает их на страницу входа, если они не вошли в систему, вот так:
# 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)
### ... ###
После входа в систему ему необходимо вернуть пользователей на страницу, которая привела их на страницу входа в систему.Он также должен сохранять такие вещи, как переданные переменные (т. е.вся ссылка в принципе www.example.com/download_file?id=3 )
Кто-нибудь знает, как это сделать?
Спасибо вам за вашу помощь :-)
Решение
Я думаю, что стандартная практика заключается в добавлении URL-адреса, на который пользователь должен быть перенаправлен после успешного входа в систему, в конец строки запроса URL-адреса входа.
Вы бы изменили свой декоратор на что-то вроде этого (при этом избыточность в вашей функции декоратора также была удалена).:
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
Вам придется чем-то заменить get_current_url()
, потому что я не знаю, как это делается во Flask.
Затем в вашем обработчике входа в систему, когда пользователь успешно входит в систему, вы проверяете, есть ли next
параметр в запросе, и, если это так, вы перенаправляете их на этот URL.В противном случае вы перенаправляете их на какой-либо URL по умолчанию (обычно /
, я думаю).
Другие советы
Вы могли бы использовать строку запроса, чтобы сохранить информацию о файле нетронутой одним-двумя щелчками мыши.Одна из приятных особенностей url_for
вот как это происходит передает неизвестные параметры в виде строк запроса.Итак, не слишком меняя свою страницу регистрации, вы могли бы сделать что-то вроде этого:
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if g.user is None:
return redirect(url_for('register', wantsurl = request.path))
return f(*args, **kwargs)
return decorated_function
Здесь wantsurl
будет отслеживать URL-адрес, на который попал пользователь.Если незарегистрированный пользователь переходит на /download/some/file.txt
, login_required
отправлю вас в /register?wantsurl=%2Fdownload%2Fsome%2Ffile.txt
Затем вы добавляете пару строк в свою регистрационную функцию:
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'GET':
if 'wantsurl' in request.args:
qs = request.args['wantsurl']
return render_template('register.html', wantsurl=qs)
if request.method == 'POST':
if 'wantsurl' in request.form and everything_else_ok:
return redirect(request.form['wantsurl'])
Это автоматически перенаправит на загрузку при успешной регистрации, при условии, что у вас есть что-то в форме под названием 'wantsurl' со значением qs
, или вы могли бы отправить свою форму со строкой запроса;это может быть просто небольшое значение if-else в шаблоне.