Jak zrobić w Flask funkcję dekoratora Pythona z argumentami (dla autoryzacji)
Użyłem fragmentu kolby dla mojej kolby-login, który sprawdza, czy użytkownik jest zalogowany:
from functools import wraps
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')
return redirect(url_for('login'))
return decorated_function
A ja tak dekoruję widoki:
@app.route('/secrets', methods=['GET', 'POST'])
@logged_in
def secrets():
error = None
Ja też chciałbym zrobić coś podobnego dla autoryzacji. W tej chwili mam wiele widoków, aby sprawdzić, czy użytkownik jest właścicielem zasobu, powiedzmy zasobu hotdogs
.
Jeśli użytkownik logged_in jest właścicielem danego hotdoga, może edytować i zarządzać swoimi hotdogami. Jeśli nie, wyrzucę go do nieautoryzowanego ekran.
@app.route('/<hotdog>/addmustard/',methods=["GET"])
@logged_in
def addmustard(hotdog):
if not (authorizeowner(hotdog)):
return redirect(url_for('unauthorized'))
do_stuff()
authorizeowner()
pobiera hotdoga jako dane wejściowe i sprawdza, czy zarejestrowany właściciel hotdoga odpowiada nazwie właściciela wymienionej w zmiennej sesji.
Próbowałem zrobić funkcję owns_hotdog wrapper / decorator podobną do mojej zalogowanej, ale narzekał, że nie akceptuje argumentów. Jak mogę osiągnąć coś podobnego? Coś w tym stylu...
def owns_hotdog(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not authorizeowner(hotdog):
return f(*args, **kwargs)
else:
flash('Please log in first.', 'error')
return redirect(url_for('login'))
return decorated_function
Z komunikatu o błędzie dekorator zdaje się nie odbierać argumentu hotdoga, do którego widoki Flask mają dostęp z zmienna na trasie. Mam nadzieję na coś takiego...
@app.route('/<hotdog>/addmustard/',methods=["GET"])
@logged_in
@owns_hotdog(hotdog)
def addmustard(hotdog):
do_stuff()
Wszystko działa z moją aktualną funkcją authorizeowner (hotdog), ale wydaje się czystsze, aby mieć to na swoim miejscu jako owijkę na górze mojej trasy, a nie jako pierwszą linię wewnątrz trasy.
Inne uwagi:
- wiem, że Flask-Security i Flask-Principal mogą zarządzać autoryzacja dla mnie. Niestety, używam nieobsługiwanego back-end bazy danych i nie mogę korzystać z tych rozszerzeń. Więc jestem zmuszeni do uwierzytelniania bez nich.
- jeśli widzisz jakieś rażące dziury w robieniu autoryzacji w ten sposób, proszę daj mi znać!
1 answers
Oto Jak to zrobić:
from functools import update_wrapper
def owns_hotdog(hotdog):
def decorator(fn):
def wrapped_function(*args, **kwargs):
# First check if user is authenticated.
if not logged_in():
return redirect(url_for('login'))
# For authorization error it is better to return status code 403
# and handle it in errorhandler separately, because the user could
# be already authenticated, but lack the privileges.
if not authorizeowner(hotdog):
abort(403)
return fn(*args, **kwargs)
return update_wrapper(wrapped_function, fn)
return decorator
@app.errorhandler(403)
def forbidden_403(exception):
return 'No hotdogs for you!', 403
Kiedy dekorator pobiera argumenty, nie jest to tak naprawdę dekorator, ale funkcja factory , która zwraca prawdziwy dekorator.
Ale gdybym był tobą, użyłbym Flask-Login do uwierzytelniania i rozszerzył go o niestandardowe dekoratory i funkcje jako twoje do obsługi autoryzacji.
Przyjrzałam się Dyrektorowi, ale uznałam, że to zbyt skomplikowane jak na mój gust. Nie sprawdzałem kolby-zabezpieczenia, ale uważam, że używa Kolba-główna do autoryzacji. Ogólnie rzecz biorąc, myślę, że Flask-Login z jakiegoś niestandardowego kodu wystarcza większość czasu.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-16 09:56:24