Flask
Autoryzacja i uwierzytelnianie
Szukaj…
Używanie rozszerzenia login flask
Jednym z prostszych sposobów implementacji systemu autoryzacji jest użycie rozszerzenia login-flask . Strona internetowa projektu zawiera szczegółowy i dobrze napisany szybki start, którego krótsza wersja jest dostępna w tym przykładzie.
Główny pomysł
Rozszerzenie udostępnia zestaw funkcji używanych do:
- logowanie użytkowników
- wylogowywanie użytkowników
- sprawdzanie, czy użytkownik jest zalogowany czy nie, i sprawdzanie, który to użytkownik
Czego nie robi i co musisz zrobić sam:
- nie zapewnia sposobu przechowywania użytkowników, na przykład w bazie danych
- nie zapewnia sposobu sprawdzania poświadczeń użytkownika, na przykład nazwy użytkownika i hasła
Poniżej znajduje się minimalny zestaw kroków niezbędnych do działania.
Zalecam umieszczenie całego kodu związanego z uwierzytelnianiem w oddzielnym module lub pakiecie, na przykład auth.py
W ten sposób możesz osobno utworzyć niezbędne klasy, obiekty lub funkcje niestandardowe.
Utwórz LoginManager
Rozszerzenie używa klasy LoginManager
którą należy zarejestrować w obiekcie aplikacji Flask
.
from flask_login import LoginManager
login_manager = LoginManager()
login_manager.init_app(app) # app is a Flask object
Jak wspomniano wcześniej, LoginManager
może na przykład być zmienną globalną w osobnym pliku lub pakiecie. Następnie można go zaimportować do pliku, w którym obiekt Flask
jest tworzony, lub do funkcji fabryki aplikacji i zainicjować ją.
Określ wywołanie zwrotne używane do ładowania użytkowników
Użytkownicy zwykle będą ładowani z bazy danych. Oddzwonienie musi zwrócić obiekt reprezentujący użytkownika odpowiadającego podanemu identyfikatorowi. Powinien zwrócić None
jeśli identyfikator jest niepoprawny.
@login_manager.user_loader
def load_user(user_id):
return User.get(user_id) # Fetch the user from the database
Można to zrobić bezpośrednio poniżej podczas tworzenia LoginManager
.
Klasa reprezentująca twojego użytkownika
Jak wspomniano, wywołanie zwrotne user_loader
musi zwrócić obiekt reprezentujący użytkownika. Co to dokładnie znaczy? Obiekt ten może na przykład być opakowaniem wokół obiektów użytkownika przechowywanych w bazie danych lub po prostu bezpośrednio modelem z bazy danych. Ten obiekt musi implementować następujące metody i właściwości. Oznacza to, że jeśli wywołanie zwrotne zwróci model bazy danych, musisz upewnić się, że wspomniane właściwości i metody zostały dodane do modelu.
is_authenticated
Ta właściwość powinna zwracać wartość
True
jeśli użytkownik jest uwierzytelniony, tzn. Podał prawidłowe poświadczenia. Należy upewnić się, że obiekty reprezentujące użytkowników zwrócone przez wywołanie zwrotneuser_loader
zwracają wartośćTrue
dla tej metody.is_active
Ta właściwość powinna zwracać wartość Prawda, jeśli jest to aktywny użytkownik - oprócz uwierzytelnienia aktywowali oni także swoje konto, nie zostali zawieszeni ani nie spełnili żadnych warunków dotyczących odrzucenia konta przez aplikację. Nieaktywne konta mogą się nie logować. Jeśli nie masz takiego mechanizmu, zwróć wartość
True
z tej metody.is_anonymous
Ta właściwość powinna zwrócić wartość True, jeśli jest to anonimowy użytkownik. Oznacza to, że obiekt użytkownika zwrócony przez wywołanie zwrotne
user_loader
powinien zwrócić wartośćTrue
.get_id()
Ta metoda musi zwrócić kod Unicode, który jednoznacznie identyfikuje tego użytkownika, i można go użyć do załadowania użytkownika z wywołania zwrotnego
user_loader
. Pamiętaj, że musi to być Unicode - jeśli ID jest natywnie int lub innego typu, musisz przekonwertować go na Unicode. Jeśli wywołanie zwrotneuser_loader
zwraca obiekty z bazy danych, ta metoda najprawdopodobniej zwróci identyfikator bazy danych tego konkretnego użytkownika. Ten sam identyfikator powinien oczywiście powodować, że wywołanie zwrotneuser_loader
zwróci później tego samego użytkownika.
Jeśli chcesz ułatwić sobie pracę (** jest to faktycznie zalecane), możesz dziedziczyć po UserMixin
w obiekcie zwróconym przez wywołanie zwrotne user_loader
(prawdopodobnie model bazy danych). Można zobaczyć, jak te metody i właściwości są wdrażane domyślnie w tym wstawek tutaj .
Logowanie użytkowników
Rozszerzenie pozostawia sprawdzenie poprawności nazwy użytkownika i hasła wprowadzonych przez użytkownika. W rzeczywistości rozszerzenie nie ma znaczenia, jeśli używasz kombinacji nazwy użytkownika i hasła lub innego mechanizmu. To jest przykład logowania użytkowników przy użyciu nazwy użytkownika i hasła.
@app.route('/login', methods=['GET', 'POST'])
def login():
# Here we use a class of some kind to represent and validate our
# client-side form data. For example, WTForms is a library that will
# handle this for us, and we use a custom LoginForm to validate.
form = LoginForm()
if form.validate_on_submit():
# Login and validate the user.
# user should be an instance of your `User` class
login_user(user)
flask.flash('Logged in successfully.')
next = flask.request.args.get('next')
# is_safe_url should check if the url is safe for redirects.
# See http://flask.pocoo.org/snippets/62/ for an example.
if not is_safe_url(next):
return flask.abort(400)
return flask.redirect(next or flask.url_for('index'))
return flask.render_template('login.html', form=form)
Zasadniczo logowanie użytkowników odbywa się poprzez wywołanie login_user i przekazanie instancji obiektu reprezentującego wspomnianego wcześniej użytkownika. Jak pokazano, zwykle dzieje się to po pobraniu użytkownika z bazy danych i sprawdzeniu jego poświadczeń, jednak obiekt użytkownika po prostu magicznie pojawia się w tym przykładzie.
Zalogowałem użytkownika, co teraz?
Do obiektu zwróconego przez wywołanie zwrotne user_loader
można uzyskać dostęp na wiele sposobów.
W szablonach:
Rozszerzenie automatycznie wstrzykuje je pod nazwą
current_user
przy użyciu procesora kontekstowego szablonu. Aby wyłączyć to zachowanie i użyć niestandardowego procesora, ustawadd_context_processor=False
w konstruktorzeLoginManager
.{% if current_user.is_authenticated %} Hi {{ current_user.name }}! {% endif %}
W kodzie Python:
Rozszerzenie udostępnia obiekt związany z żądaniem o nazwie
current_user
.from flask_login import current_user @app.route("/hello") def hello(): # Assuming that there is a name property on your user object # returned by the callback if current_user.is_authenticated: return 'Hello %s!' % current_user.name else: return 'You are not logged in!'
login_required
ograniczanie dostępu za pomocą dekoratora Zalogin_required
dekoratoralogin_required
można szybko ograniczyć dostęp.from flask_login import login_required @app.route("/settings") @login_required def settings(): pass
Wylogowywanie użytkowników
Użytkownicy mogą zostać wylogowani poprzez wywołanie logout_user()
. Wygląda na to, że jest to bezpieczne, nawet jeśli użytkownik nie jest zalogowany, więc dekorator @login_required
może najprawdopodobniej zostać pominięty.
@app.route("/logout")
@login_required
def logout():
logout_user()
return redirect(somewhere)
Co się stanie, jeśli użytkownik nie będzie zalogowany i current_user
dostęp do obiektu current_user
?
Defult zwraca AnonymousUserMixin :
-
is_active
iis_authenticated
sąFalse
-
is_anonymous
toTrue
-
get_id()
zwracaNone
Aby użyć innego obiektu dla anonimowych użytkowników, należy udostępnić wywołanie (funkcję klasową lub fabryczną), które tworzy anonimowych użytkowników do LoginManager
pomocą:
login_manager.anonymous_user = MyAnonymousUser
Co następne?
To kończy podstawowe wprowadzenie do rozszerzenia. Aby dowiedzieć się więcej na temat konfiguracji i dodatkowych opcji, zaleca się przeczytanie oficjalnego przewodnika .
Przekroczono limit czasu sesji logowania
Dobrą praktyką jest limit czasu zalogowanej sesji po określonym czasie, możesz to osiągnąć dzięki Flask-Login.
from flask import Flask, session
from datetime import timedelta
from flask_login import LoginManager, login_require, login_user, logout_user
# Create Flask application
app = Flask(__name__)
# Define Flask-login configuration
login_mgr = LoginManager(app)
login_mgr.login_view = 'login'
login_mgr.refresh_view = 'relogin'
login_mgr.needs_refresh_message = (u"Session timedout, please re-login")
login_mgr.needs_refresh_message_category = "info"
@app.before_request
def before_request():
session.permanent = True
app.permanent_session_lifetime = timedelta(minutes=5)
Domyślny czas życia sesji wynosi 31 dni, w przypadku przekroczenia limitu czasu użytkownik musi określić widok odświeżania logowania.
app.permanent_session_lifetime = timedelta(minutes=5)
Powyższa linia zmusi użytkownika do ponownego logowania co 5 minut.